Python Pygame:试图理解Sprite类

Python Pygame:试图理解Sprite类,python,pygame,Python,Pygame,我在上找到了一个名为Sprite的类。我读了解释,但我不明白这门课是用来做什么的 我知道我们用它来继承构造函数中的其他类,但仅此而已 如果有人清楚地解释了该课程的有用性,以及如何使用它,我很感兴趣。对,所以移动鼠标光标。那是雪碧 这是一个方形位图,具有一定的透明度。但是只有可见的部分才有意义——例如,你不在乎透明部分是否移动到了某个屏幕元素上 在PyGame中,它们是相似的 在过去;)大多数街机游戏使用精灵类型的动画。想想(大约1980年);那是一张黄色的大嘴巴。它被实现为一个精灵。让我们做一个

我在上找到了一个名为
Sprite
的类。我读了解释,但我不明白这门课是用来做什么的

我知道我们用它来继承构造函数中的其他类,但仅此而已


如果有人清楚地解释了该课程的有用性,以及如何使用它,我很感兴趣。

对,所以移动鼠标光标。那是雪碧

这是一个方形位图,具有一定的透明度。但是只有可见的部分才有意义——例如,你不在乎透明部分是否移动到了某个屏幕元素上

在PyGame中,它们是相似的

在过去;)大多数街机游戏使用精灵类型的动画。想想(大约1980年);那是一张黄色的大嘴巴。它被实现为一个精灵。让我们做一个:

现在这个东西必须在屏幕上移动,透明的像素(浅灰色和深灰色)需要显示背景。重要的是,对于PacMan来说并不是如此,但对于更多的锯齿图像,任何透明的东西都不应该成为碰撞检测的一部分。这是精灵的另一个重要方面

假设《吃豆人》中的敌人鬼魂发射了子弹(哇,这是一个可怕的想法!),如果子弹穿过吃豆人精灵的透明角落,你会非常不安,但这仍然被认为是“击中”。为了正确地实现这一点,使用了一种新的方法。这基本上是另一个逻辑位图,说明哪些像素将被视为冲突精灵的一部分,哪些不被视为冲突精灵的一部分

还有将位图绘制到屏幕上所需的代码。现在,这方面的CPU使用率只是一个小问题。一台装有PyGame的普通PC可以以60帧/秒的速度在屏幕上轻松绘制1000个精灵。但在以前,这需要大量的处理时间,并且有希望在某种硬件协助下完成。甚至在20世纪90年代,一些视频卡的广告中也有“硬件鼠标光标”支持[需要引用]。PyGame的代码非常高效,可以将位图绘制到屏幕上

总之,为什么要使用精灵:

  • 易于实现
  • 透明度和遮罩
  • 快速碰撞检测
  • 20世纪80年代的硬件甚至不能梦想硬件3D
为什么要使用PyGame的精灵:

  • 他们已经写好了
  • 它们速度快、效率高、无bug
  • 他们可以使用面具
  • 他们已经有了高效的碰撞检测代码
  • 支持是非常有用的
所以。。。我怎么做雪碧

这是一个参考类。我将对代码进行注释

class Pacman( pygame.sprite.Sprite ):               # parent class is Sprite

    def __init__( self, x, y, pacman_bitmap ):      # New PacMan at (x,y)
        pygame.sprite.Sprite.__init__( self )       # Init the parent obj too
        self.image = pacman_bitmap                  # it MUST be self.image for sprites
        self.rect  = self.image.get_rect()          # it MUST be self.rect for sprites
        self.rect.center = ( x, y )                 # move the sprite
        self.move_dir_x  = 0                        
        self.move_dir_y  = 0                        # This pacman never stops

    # Semi-optional Part 
    def update( self ):                             # called to somehow effect the sprite.  
        # Move pacman                               # MUST be named "update"
        x, y = self.rect.center
        x += self.move_dir_x
        y += self.move_dir_y
        self.rect.center = ( x, y )                 # move the sprite

    # Optional Part
    def setDirection( self, dir ):                  # Called when user sends
        if ( dir == 'up' ):                         # input to change direction
            self.move_dir_x = 0
            self.move_dir_y = -1
        elif ( dir == 'right' ):
            self.move_dir_x = 1
            self.move_dir_y = 0
        #elif ... TODO - rest of direction changes
就这样。基本Sprite对象期望子类“覆盖”
image
rect
成员变量。精灵组使用
update()
函数以某种方式修改精灵。这一个只是朝着设置好的任何方向移动(根据用户输入的不同而变化)

所以我们可以这样使用:

pacman_image   = pygame.image.load( 'pacman.png' ).convert()
pacman_sprite  = Pacman( 100, 100, pacman_image )
player1_sprite = pygame.sprite.GroupSingle()           # Just 1 player for now
player_sprites.add( pacman_sprite )

# Imagine a similar sprite class for ghosts
ghost_image   = pygame.image.load( 'blue_ghost.png' ).convert()
...
ghost_sprites = pygame.sprite.Group()
for i in range( 4 ):
    ghost_sprites.add( Ghost( 10, 50, ghost_image ) )
然后在主循环中:

game_over = False
while not game_over:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            game_over = True

    # Movement keys too (not event driven)
    keys = pygame.key.get_pressed()
    if ( keys[pygame.K_UP] ):
        player_sprite.setDirection( 'up' )
    elif ( keys[pygame.K_RIGHT] ):
        player_sprite.setDirection( 'right' )
    #elif  TODO - rest of keys

    # re-position all the players and ghosts
    player_sprites.update()
    ghost_sprites.update()

    # Paint the background
    paintPacmanEnvironment( window )

    # Paint all the sprites
    player_sprites.draw( window )
    ghost_sprites.draw( window )

    # Did the player hit a ghost? 
    # spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
    if ( pygame.sprite.spritecollide( player_sprite, ghost_sprites, False ) ):
        # TODO: handle hitting a ghost
是的,最初设置精灵有点复杂。但看看那个主回路!只需几次函数调用,您就可以获得几乎免费的绘制和碰撞,再加上一点设置(大约1行),您还可以获得位图掩码。这就是为什么你应该使用PyGame精灵

编辑:Sprite.update()上的快速注释


update()
函数不仅是处理运动的好地方,也是处理动画的好地方。显然,我们需要多帧动画来让吃豆人的嘴动起来。为了实现这一点,
Pacman.update()
将查看当前时钟时间,并使用它前进到动画的下一帧。因此,我们可以使用图像列表来创建Pacman,而不是仅使用单个位图创建Pacman。然后,
Pacman.image
将被设置为
.udpate()中的正确图像。它工作得非常好。

非常感谢您提供了这个有用的答案!还有一个问题:为什么要使用
self.rect=self.image.get_rect()
self.rect.center=(x,y)
?@Tangax将pygame精灵视为一个容器,它将一个曲面与在屏幕上绘制该曲面的位置相结合。因此,精灵必须具有的最小属性是
图像
属性(包含曲面)和
rect
属性(包含图像的大小和位置)。在这里使用Rect而不是例如
x,y
元组可以轻松更改精灵的位置。如您所见,我们可以通过使用rect的
center
属性轻松地将图像的中心设置为特定位置,并且rect类为我们处理所有数学运算。再次感谢,它对我非常有用!