我应该如何为精灵表中的精灵分配名称?

Posted

技术标签:

【中文标题】我应该如何为精灵表中的精灵分配名称?【英文标题】:How should I be assigning names to sprites from a sprite sheet? 【发布时间】:2019-10-17 17:30:47 【问题描述】:

我知道如何加载精灵表、剪辑图像并返回这些图像的列表,但我喜欢按名称而不是索引来引用我的精灵,以保持代码的可读性和可管理性,但有时它很长而且繁琐的写出精灵名称列表。

我通常创建一个字典,并通过名称引用我需要的精灵,但我想知道我是否应该对名称进行硬编码?

这是我通常做的:

sprites = load_spritesheet('spr_buttons.png', (64, 64))
BUTTON_NAMES = ['start', 'start_hover', 'start_click', 'back', 'back_hover',
                'back_click', 'skip', 'skip_hover', 'skip_click', 'exit',
                'exit_hover', 'exit_click', 'check', 'check_hover',
                'check_click', 'blank']
spr_buttons = 
for index, sprite in enumerate(sprites):
    spr_buttons[BUTTON_NAMES[index]] = sprite

以这些按钮精灵为例,我还有一个按钮类,并为每个按钮创建一个新实例,传入精灵的名称。

这很好,但我想找到更好的方法。我是否创建一个 .txt 文件来伴随我的精灵表并从中获取名称?或者我是否使用分配给每个精灵的关键字 + 索引号(例如button_1button_2 等)?

这是我的NewButton 课程:

import pygame


class NewButton:
    """Create and maintain a new button."""`

    def __init__(self, name, sprites, x_pos, y_pos, size):
        """Initialise a new button instance.

        :param name:    The name of the button from the dictionary.
        :param sprites: A dictionary of button sprite images.
        :param x_pos:   The x position of the button image.
        :param y_pos:   The y position of the button image.
        :param size:    The squared size of the button image.
        """
        self.img_normal = sprites[name]
        self.img_hover = sprites[name + '_hover']
        self.img_click = sprites[name + '_click']
        self.rect = pygame.Rect(x_pos, y_pos, size, size)
        self.image = self.img_normal
        self.hover = False
        self.clicked = False
        self.execute = False
        self.max_timer = 20
        self.click_timer = 0

    def update(self, delta):
        """Update the button instance.

        :param delta: A multiplier based on real time between updates.
        """
        if self.clicked:
            self.click_timer += delta
            if self.click_timer < self.max_timer / 2:
                self.image = self.img_click
            elif self.click_timer >= self.max_timer:
                self.clicked = False
                self.click_timer = 0
                self.image = self.img_normal
                self.execute = True
            else:
                self.image = self.img_normal
        else:
            mx, my = pygame.mouse.get_pos()
            if self.rect.collidepoint(mx, my):
                self.image = self.img_hover
                self.hover = True
            else:
                self.image = self.img_normal
                self.hover = False

    def click(self):
        """Set the button as being clicked."""
        self.clicked = True

    def reset(self):
        """Reset the execute status of the button."""
        self.execute = False

【问题讨论】:

【参考方案1】:

您可以使用zip() 函数以更简单的方式创建字典:

sprites = load_spritesheet('spr_buttons.png', (64, 64))

BUTTON_NAMES = ['start', 'start_hover', 'start_click',
                'back', 'back_hover', 'back_click',
                'skip', 'skip_hover', 'skip_click',
                'exit', 'exit_hover', 'exit_click',
                'check', 'check_hover', 'check_click',
                'blank']

spr_buttons = dict(zip(BUTTON_NAMES, sprites))

【讨论】:

谢谢@martineau,zip() 函数确实缩短了将图像分配给名称的过程,但至于创建名称列表然后分配它们的整个过程 - 你会说这是要走的路,还是你知道一种更蟒蛇式的方式来完成我想做的事情? Jayce:我很难根据你的问题推荐任何东西。你提到了一些关于还有一个按钮类和使用精灵名称的事情,但没有这样的例子。我也不能确定是否应该硬编码名称,因为我不知道应用程序是什么以及在其上下文中什么是有意义的。应用程序通常有固定数量的 GUI 按钮,所以我不确定您要完成什么。 这是我正在制作的游戏。我的 GUI 中确实有固定数量的按钮——那些在我的BUTTON_NAMES 列表中列出。它们是我的标题画面、游戏设置和游戏画面的按钮。感谢您迄今为止提供的帮助,这不是我制作的第一款游戏,但我只是在寻找一些关于我迄今为止的方法的建议/肯定。如果可以的话,我会用我的NewButton() 课程更新帖子。 根据您的 NewButton 类中的代码,我会说您这样做的方式很好,因为您创建 spr_buttons 字典的方式不太可能影响其余部分您的代码(只是在启动时一次性创建NewButton 实例)。由于后者是您的 GUI 的一部分,因此硬编码它们的变量名可能也可以。即start_button = NewButton('start', spr_buttons, x, y, size)back_button = NewButton('back', spr_buttons, x, y, size) 等。为这些按钮对象使用这样的硬编码名称应该有助于实现 GUI。【参考方案2】:

首先您要考虑的是,pygame.sprite.Group 中的 pygame.sprite.Sprite 没有排序。不能保证在迭代分组时,精灵会以相同的顺序枚举,因为它们是附加到组中的。 见pygame.sprite.Group的文档:

Group 中的 Sprite 没有顺序,因此绘制和迭代 Sprite 没有特定的顺序。


我建议定义 enums 来命名按钮:

from enum import Enum
class Button(Enum):
    start = 0
    start_hover = 1
    # [...]

创建一个字典,其中每个按钮都与一个枚举器相关联:

spr_buttons = dict(zip(Button, sprites))

所以一个按钮可以通过例如:

sprite = spr_buttons[Button.start] 

甚至使用getattr 和一个名字:

sprite = spr_buttons[getattr(Button, "start")]

或者,您可以创建一个按钮列表并通过枚举器的.value 属性进行访问,该属性是列表的索引:

spr_buttons = list(sprites)
sprite = spr_buttons[Button.start_hover.value]

【讨论】:

@Jayce 标识需要是名称(字符串)还是可以是任何其他类型的 id?在 python 中,将一种标识映射到对象的一般方法是字典。但我建议在创建对象时将对象和 id 的关联附加到字典中。 谢谢@Rabbid76。只是为了记录,我没有在这个游戏中使用 pygame.sprite,我为精灵使用完全自定义的类。另一件事,字典对象实际上是按照它们添加的顺序保存的——你可以通过创建一个字典然后打印它来测试它,但无论如何,因为我的精灵是通过它们的名称(字符串)而不是索引来引用的,所以无论如何都不是问题。 @Jayce 我明白了。如果您可以确保精灵列表的顺序明确,那么对于zip,精灵列表和名称列表是正确的解决方案。当然,该解决方案意味着关于图像顺序的隐含知识。 请允许我插话。 @Jayce:您可能不应该对自己的变量(或自定义类型)使用“精灵”一词,因为 pygame 带有一个内置的 one,它通常用于其他目的,而不是听起来像你正在做(并且是 Rabbid76 可以理解的假设你在说什么)。其次,您打算如何使用这些对象的实例可能是游戏设计中的一个重要因素,具体取决于引用它们所需的内容以及可能的频率发生以及它影响的代码量。 谢谢你们俩 - 如果可以的话,我会将两者都标记为答案。是的,我确实有点过于随意地使用“精灵”这个词,但我实际上并没有过时使用它,因为精灵 is 是 2D 位图图像,而不仅仅是 Python类,但在这个论坛的背景下,我可能应该更加小心以防止被误解。无论如何,你们都给了我很好的答案,我感谢你们的帮助,非常感谢。【参考方案3】:

您可以使用精灵的序列解包来将它们分配给您希望使用的名称:

sprites = load_spritesheet('spr_buttons.png', (64, 64))

start, start_hover, start_click, back, back_hover, back_click, \
skip, skip_hover, skip_click, exit, exit_hover, exit_click, \
check, check_hover, check_click, blank = sprites

【讨论】:

我认为将所有这些精灵名称硬编码到自己的代码中并不是一个好主意。 IMO,将按钮名称与精灵相关联的字典会更好。 我同意@martineau,这可能不是一个好主意;但是,可能会有一些用例,它很容易实现,这就是操作所要求的。 我认为无需硬编码就可以很简单——请参阅我的answer。

以上是关于我应该如何为精灵表中的精灵分配名称?的主要内容,如果未能解决你的问题,请参考以下文章

在 Unity 5 中,为啥精灵表中的某些精灵在精灵中不可见,但在 UI 图像中可以正常工作?

从精灵表中以 sfml 动画精灵

将 spritesheet 中的精灵存储在数组 Libgdx 中

多个精灵表中的 Unity 9-slice

在画布中同时渲染精灵表中的多个部分?

使用按键精灵,如何将excel表格中的内容复制到报名软件的框中