PyGame精灵组

0 投票
3 回答
1481 浏览
提问于 2025-04-18 14:12

我刚开始使用PyGame和Python。说到这,我创建了一些精灵(也就是游戏中的角色或物体),并把它们放在一个组里。例如:

gems = pygame.sprite.Group()

for i in range (0,4):
    gem = Gem()
    all_sprite_list.add(gem)
    gems.add(gem)

现在在我的主程序中,我想通过按一个特定的键来操作这个组里的一个宝石。我现在的做法是给每个宝石设置一个ID,然后在组里一个一个地查找,直到找到我想操作的那个ID。也就是说:

if event.type == pygame.KEYDOWN and event.key == pygame.K_F1:
    for gem in gems:
        if gem.id == 1:
           gem.state = normal
elif event.type == pygame.KEYDOWN and event.key == pygame.K_F2:
    for gem in gems:
        if gem.id == 2:
           gem.state = normal

我知道这样做有点笨,肯定有更好的方法,不用一个一个查找。我查了一些资料,试着做了类似的事情:

gems.sprites().index(0) 

但是没有成功。有没有什么建议呢?

3 个回答

0

我写了一个其他答案,看起来是更新PyGame精灵的标准答案(特别是当你每次更新很多精灵时)。不过,这里有一个替代方案,适合在众多精灵中只更新少数几个的情况。


我们的目标是从一个大集合中找到一小部分对象。我的建议是为你的精灵组创建一个并行字典。这个字典的键是触发它的那个键。

这里我们会用到defaultdict(可以看看这个问题,特别是第二个答案,了解如何使用它们)。简单来说,它是一个带有默认值的字典(在这里,因为它是list,所以默认是空列表)。

key_dict = defaultdict(list)
# add the sprite triggered by F1
key_dict[pygame.K_F1].append(gem1)
# you can add multiple sprites as well (these are lists)
key_dict[pygame.K_F2].append(gem2)
key_dict[pygame.K_F2].append(gem3)

#...  in your update loop
if event.type == pygame.KEYDOWN:
    for gem in key_dict[event.key] : #this gets all the gems for this key event 
                                     # (empty if not defined because defaultdict)
        gem.state = normal

这个方案适合你有很多宝石,但只需要更新几个小宝石的情况。

但是也有一些问题:

  • 你需要维护两个集合(你的精灵组和这个字典)

  • 如果你有很多宝石要处理,那么速度优势就会减少

  • 这会让你的代码变得更复杂

我觉得只有在你要更新的宝石数量远小于总宝石数量的情况下,这样做才有意义。如果你还要更新很多其他属性,我建议你参考我之前的答案,因为那样更简洁。

0

在PyGame的Sprite类中,有一个叫update(*args)的函数(文档链接)。

顺便提一下,*args的意思是你可以传入任意数量的参数:

>>> def f(*args):
...     print args
...
>>> f(1,2)
(1, 2)
>>> f(3)
(3,)
>>> f(3,5,6)
(3, 5, 6)
>>> def g(*args):
...     print args[0]
...
>>> g(1,2)
1

默认情况下,update什么都不做,但你可以根据自己的需要重写这个函数,比如创建一个新的类来覆盖基础的Sprite类:

class MySprite(Sprite):
    def update(self,*args):
        key = args[0]
        if key == pygame.K_F1 and self.id == 1 :
            self.state = normal
        elif key == pygame.K_F2 and self.id == 2 :
            self.state = normal

现在,Sprite组也有一个update函数(它的参数形式和update(*args)是一样的)。

官方文档.

这个函数的作用是对每个精灵调用update,并传入你提供的参数。

# group has sprite1 and sprite2
group.update(1,2,3) # same as calling sprite1.update(1,2,3) 
                    #  and sprite2.update(1,2,3)

所以如果gems是你的精灵组,你可以这样做(假设你在使用上面提到的MySprite类):

if event.type == pygame.KEYDOWN:
    gems.update(event.key) 
    # this will call the MySprite.update function for all the gems
0

看起来你知道哪些键对应哪些ID,所以你可以把这些信息放到一个字典里,然后只需要遍历一次宝石:

gem_keys = {
    1: pygame.K_F1,
    2: pygame.K_F2,
}

if event.type == pygame.KEYDOWN:
    for gem in gems:
        # Check if key pressed corresponds to current gem
        if event.key == gem_keys[gem.id]:
           gem.state = normal

除了代码感觉有点笨重之外,你还有遇到什么具体的问题吗?

撰写回答