【问题标题】:How do you use sprite groups?你如何使用精灵组?
【发布时间】:2021-05-14 01:22:15
【问题描述】:

我收到错误消息'Enemy' object has no attribute '_Sprite__g',但我不知道如何使用精灵组。我试图让它们仅在 x 轴上随机生成。

import pygame, os, random
pygame.init()
 
FPS=60

SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')

x=50
y=450
vel = 3
width = 20
height = 20

class Player(object):
    def __init__(self,x,y,width,height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 3
        self.image = pygame.Surface((width, height))
        self.image.fill((0,0,0))
    def draw(self,SCREEN):
        SCREEN.blit(self.image, (self.x,self.y))
class B():
    def __init__(self,x,y,radius, color):
        self.x = x
        self.y = y
        self.color = color
        self.radius = radius
        self.vel = vel
    def draw(self,SCREEN):
        pygame.draw.circle(SCREEN, self.color, (self.x,self.y),self.radius)
    
class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        self.image = pygame.Surface((20,20))
        self.x = random.randrange (0,400)
        self.y = 500
        self.speed = random.randrange(1,3)
    def draw (self,SCREEN):
        SCREEN.blit(self.image,(self.x,self.y))
 
player = Player(x, y, width, height)
bullets = []
enemies = pygame.sprite.Group()
# Main loop
running = True
clock = pygame.time.Clock()
while running:
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    for bullet in bullets:
        if bullet.x < 450 and bullet.x >0:
            bullet.x += bullet.vel
        else:
            bullets.pop(bullets.index(bullet))
     
    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE]:
        if len(bullets)< 5:
            bullets.append(B(round(player.x + player.width //2), round(player.y + player.height//2),3, (0,0,0)))
            
    if keys[pygame.K_w] and player.y > 30 - player.width - player.vel:
        player.y -= player.vel
    if keys[pygame.K_s] and player.y < 500 - player.width - player.vel:
        player.y += player.vel
 

    SCREEN.fill((190, 232, 220))
    player.draw(SCREEN)
    for bullet in bullets:
            bullet.draw(SCREEN)
    for i in range (8):
        e = Enemy()
        enemies.add(e)
    pygame.display.update()

pygame.quit()

【问题讨论】:

    标签: python random pygame


    【解决方案1】:

    对象需要来自pygame.sprite.Sprite。基类也需要初始化。使用super() 委托给基类构造函数。例如:

    class Player(object):
        def __init__(self,x,y,width,height):
            super().__init__() 
            # [...]
    

    pygame.sprite.Group.draw()pygame.sprite.Group.update()pygame.sprite.Group提供的方法。

    前者将update 方法委托给包含的pygame.sprite.Sprites - 你必须实现该方法。见pygame.sprite.Group.update()

    在组中的所有 Sprite 上调用 update() 方法 [...]

    后者使用包含的pygame.sprite.Sprites 的imagerect 属性来绘制对象-您必须确保pygame.sprite.Sprites 具有所需的属性。见pygame.sprite.Group.draw()

    将包含的 Sprite 绘制到 Surface 参数。这将Sprite.image 属性用于源表面,并使用Sprite.rect。 [...]

    因此,Sprite 类必须具有属性.rect.image。但是你不需要draw 方法:

    class Player(pygame.sprite.Sprite):
        def __init__(self,x,y,width,height):
            super().__init__() 
            self.vel = 3
            self.image = pygame.Surface((width, height))
            self.image.fill((0,0,0))
            self.rect = self.image.get_rect(topleft = (x, y))
    

    使用SRCALPHA 标志创建一个透明的pygame.Surface 并在其上画一个圆圈:

    class B(pygame.sprite.Sprite):
        def __init__(self,x,y,radius, color):
            super().__init__() 
            self.x = x
            self.y = y
            self.color = color
            self.radius = radius
            self.vel = vel
            self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
            pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
            self.rect = self.image.get_rect(center = (self.x, self.y))
    

    为所有精灵添加pygame.sprite.Groups。 add()玩家、敌人和子弹到

    enemies = pygame.sprite.Group()
    bullets = pygame.sprite.Group()
    all_sprites = pygame.sprite.Group()
    all_sprites.add(player)
    
    for i in range (8):
        e = Enemy()
        enemies.add(e)
        all_sprites.add(e)
    

    all_sprites Group 中用pygame.sprite.Group.draw 绘制Sprites。删除带有killSprite(形成所有):

    while running:
        # [...]
    
        for bullet in bullets:
            if 0 < bullet.rect.y < 500:
                bullet.rect.y -= bullet.vel
            else:
                bullet.kill()
    
        # [...]
    
        all_sprites.draw(SCREEN)
    

    使用键盘事件而不是pygame.key.get_pressed() 来发射子弹。见How do I stop more than 1 bullet firing at once?:

    可以使用pygame.sprite.groupcollide() 检测到敌人和子弹的碰撞。当 doKill 参数设置为True 时,精灵将被自动移除:

    pygame.sprite.groupcollide(bullets, enemies, True, True)
    

    完整示例:

    import pygame, os, random
    pygame.init()
     
    FPS=60
    
    SCREEN = pygame.display.set_mode((400,500))
    pygame.display.set_caption('caption')
    
    x=50
    y=450
    vel = 3
    width = 20
    height = 20
    
    class Player(pygame.sprite.Sprite):
        def __init__(self,x,y,width,height):
            super().__init__() 
            self.vel = 3
            self.image = pygame.Surface((width, height))
            self.image.fill((0,0,0))
            self.rect = self.image.get_rect(topleft = (x, y))
       
    class B(pygame.sprite.Sprite):
        def __init__(self,x,y,radius, color):
            super().__init__() 
            self.x = x
            self.y = y
            self.color = color
            self.radius = radius
            self.vel = vel
            self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
            pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
            self.rect = self.image.get_rect(center = (self.x, self.y))
           
    class Enemy(pygame.sprite.Sprite):
        def __init__(self):
            super().__init__() 
            self.image = pygame.Surface((20,20))
            self.image.fill((255, 0, 0))
            y = random.randrange (0, 480)
            x = 400
            self.rect = self.image.get_rect(topleft = (x, y))
            self.speed = random.randrange(1,3)
     
    player = Player(x, y, width, height)
    
    enemies = pygame.sprite.Group()
    bullets = pygame.sprite.Group()
    all_sprites = pygame.sprite.Group()
    all_sprites.add(player)
    
    # Main loop
    running = True
    clock = pygame.time.Clock()
    while running:
        clock.tick(FPS)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and len(bullets) < 5:
                    bullet = B(player.rect.centerx, player.rect.centery, 3, (0,0,0))
                    bullets.add(bullet)
                    all_sprites.add(bullet)
    
        if len(enemies) < 8:
            e = Enemy()
            enemies.add(e)
            all_sprites.add(e)
    
        for bullet in bullets:
            if bullet.rect.right < 500:
                bullet.rect.x += bullet.vel
            else:
                bullet.kill()
        for enemy in enemies:
            if enemy.rect.right > 0:
                enemy.rect.x -= enemy.speed
            else:
                enemy.kill()
    
        pygame.sprite.groupcollide(bullets, enemies, True, True)
                
        keys = pygame.key.get_pressed()            
        if keys[pygame.K_w] and player.rect.top > player.vel:
            player.rect.y -= player.vel
        if keys[pygame.K_s] and player.rect.bottom < 500 - player.vel:
            player.rect.y += player.vel
        
        SCREEN.fill((190, 232, 220))
        all_sprites.draw(SCREEN)
        pygame.display.update()
    
    pygame.quit()
    

    【讨论】:

      【解决方案2】:

      根据文档:

      “子类化 Sprite 时,请务必在将 Sprite 添加到组之前调用基本初始化程序。”

      所以 Enemy __init__() 的前两行应该是:

      def __init__(self):
          pygame.sprite.Sprite.__init__(self)
      

      你还需要为敌人设置一个矩形:

      self.rect = self.image.get_rect()
      self.rect.x = x
      self.rect.y = y
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        • 2017-01-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多