PyGame精灵组
我刚开始使用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 个回答
我写了一个其他答案,看起来是更新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
这个方案适合你有很多宝石,但只需要更新几个小宝石的情况。
但是也有一些问题:
你需要维护两个集合(你的精灵组和这个字典)
如果你有很多宝石要处理,那么速度优势就会减少
这会让你的代码变得更复杂
我觉得只有在你要更新的宝石数量远小于总宝石数量的情况下,这样做才有意义。如果你还要更新很多其他属性,我建议你参考我之前的答案,因为那样更简洁。
在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
看起来你知道哪些键对应哪些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
除了代码感觉有点笨重之外,你还有遇到什么具体的问题吗?