【问题标题】:Difficiating objects in a group区分组中的对象
【发布时间】:2021-01-04 02:20:06
【问题描述】:

在名为powerUpGroup 的组中,有两个对象:speedUpjumpUP。以下代码检查 player 对象是否与组中的任何对象发生碰撞:

for eachPowerUp in powerUpGroup:        
    if pygame.sprite.spritecollide(eachPowerUp, playerGroup, False) :
        eachPowerUp.kill()

假设我希望程序在玩家与speedUp 对象碰撞时打印“速度增加”。根据上面的代码,如果它是speedUpjumpUP,它将打印消息,因为它们在同一个组中。在不创建新组的情况下,python 有没有办法识别它们是不同的对象运行某些代码?

【问题讨论】:

    标签: python object pygame sprite


    【解决方案1】:

    如果speedUpjumpUp 是不同的类,您应该在它们的类中实现它们的行为(某种多态性):

    speepUp 类应该包含加速(或其他任何功能)和触发次要效果的代码(例如向玩家显示内容并将自己从游戏中移除),jumpUp 类也应该这样做.当然,您可以深入抽象兔子洞,但让我们保持简单。

    这是一个小例子:

    import pygame
    from random import choice
    
    class Actor(pygame.sprite.Sprite):
        def __init__(self, color, pos, *grps):
            super().__init__(*grps)
            self.image = pygame.Surface((64, 64))
            self.image.fill(color)
            self.rect = self.image.get_rect(topleft=pos)
            
        def update(self, events, dt):
            pass
    
    class Player(Actor):
        def __init__(self, *grps):
            super().__init__('dodgerblue', (400, 300), *grps)
            self.pos = pygame.Vector2(self.rect.topleft)
            self.dir = pygame.Vector2((0, 0))
            self.speed = 300
            
        def update(self, events, dt):
            pressed = pygame.key.get_pressed()
            self.dir.x, self.dir.y = (0, 0)
            if pressed[pygame.K_d]: self.dir += ( 1,  0)
            if pressed[pygame.K_a]: self.dir += (-1,  0)
            if pressed[pygame.K_s]: self.dir += ( 0,  1)
            if pressed[pygame.K_w]: self.dir += ( 0, -1)
            
            if self.dir.length() > 0:
                self.dir.normalize()
            
            self.pos += self.dir * self.speed * dt
            self.rect.topleft = self.pos
            
    
    class PowerUp(Actor):
        def __init__(self, color, pos, player, *grps):
            super().__init__(color, pos, *grps)
            self.player = player
    
        def apply(self):
            pass
    
        def update(self, events, dt):
            if pygame.sprite.collide_rect(self, self.player):
                self.apply()
                self.kill()
    
    class SpeedUp(PowerUp):
        def __init__(self, player, *grps):
            super().__init__('yellow', (100, 100), player, *grps)
         
        def apply(self):
            print('Speed Up')
            self.player.speed += 200
    
    class ColorChange(PowerUp):
        def __init__(self, player, *grps):
            super().__init__('purple', (600, 300), player, *grps)
         
        def apply(self):
            print('ColorChange!')
            self.player.image.fill(choice(['green', 'blue', 'yellow', 'grey']))
    
    def main():
        pygame.init()
        screen = pygame.display.set_mode((800, 600))
        clock, dt = pygame.time.Clock(), 0
        sprites = pygame.sprite.Group()
        player = Player(sprites)
        SpeedUp(player, sprites)
        ColorChange(player, sprites)
        while True:
            events = pygame.event.get()
            for e in events: 
                if e.type == pygame.QUIT:
                    return
            screen.fill('black')
            sprites.draw(screen)
            sprites.update(events, dt)
            pygame.display.flip()
            dt = clock.tick(120)/1000
            
    if __name__ == '__main__':
        main()
    

    【讨论】:

    • 我想我理解大意。通过将对象提供给玩家的参数,您可以触发某些动作?如果不正确,请添加一些 cmets 以便我更好地理解代码
    • 是的,为某些对象提供对播放器对象的引用允许我们轻松更改该播放器对象的属性或调用方法。这当然不是唯一的方法。另一个不错且简单的方法是创建一个代表游戏上下文的类并传递它而不仅仅是玩家。然后,该游戏上下文为所有精灵提供访问玩家的方法、全局属性(例如分数或级别编号等)和创建另一个精灵的方法(例如函数display_text,以便在屏幕上显示一些文本)。
    • 我没有将此添加为正确答案,因为我不知道如何将其应用于我的程序。在@AlarmClockMan 的回答中,我能够根据碰撞的精灵打印不同的消息。但是,如果产生多个speedUp,则存在一个错误,即仅注册第一个碰撞。
    【解决方案2】:

    使用 if 语句检查上电是否为speedUp

    for eachPowerUp in powerUpGroup:        
        if pygame.sprite.spritecollide(eachPowerUp, playerGroup, False):
            if eachPowerUp == speedUp:
                print("Speed increased")
            eachPowerUp.kill()
    

    编辑问题的第二部分: 您可以检查它是否是某个类,而不是检查上电是否是某个对象。 假设您有一个名为SpeedUp 的类。您可以检查eachPowerUp 是否为SpeedUp 对象,然后打印您想要的消息。

    for eachPowerUp in powerUpGroup:        
        if pygame.sprite.spritecollide(eachPowerUp, playerGroup, False):
            if type(eachPowerUp) == SpeedUp:
                print("Speed increased")
            eachPowerUp.kill()
    

    【讨论】:

    • 这行得通,但产生了另一个错误。如果产生了多个speedUps(sprite obj),则触摸一些未注册的碰撞。这是因为 if 语句只有在玩家与之碰撞的特定 speedUp 是该变量中的特定 speedUp 时才会为真。
    • @DaeshaunMorrison 查看我对答案所做的编辑。
    【解决方案3】:

    前面的代码是两个精灵之间的相等测试,而不是一种精灵。变量speedUp 是您的powerUpGroup 精灵之一。仅当玩家正在与之碰撞的特定 speedUp 是该变量中的特定 speedUp 时,if 语句才会为真。

    所以我添加了一个属性。
    在构造函数中(OP 中没有添加),我有self.type = "multiShot"self.type = "speed",具体取决于它是哪种类型。然后,一个 if 语句现在应该是这样的:

    for eachPowerUp in powerUpGroup:
        if pygame.sprite.spritecollide(eachPowerUp, playerGroup, False) :
            if eachPowerUp.type == "multiShot" :
                ...
            elif eachPowerUp.type == "speed" :
                ...
    
            
    

    【讨论】:

      猜你喜欢
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 2017-09-02
      • 1970-01-01
      • 2019-08-25
      相关资源
      最近更新 更多