You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Pygame太空侵略者类游戏中实现多敌人生成?

解决太空侵略者游戏多敌人生成问题

嘿,我看你在开发太空侵略者游戏时,卡在了生成多个敌人实例的问题上——别担心,咱们一步步把这个问题搞定!

当前代码的核心问题

你已经定义了enemy_list列表,但实际代码里只创建了单个aliens敌人实例,而且绘制、碰撞检测逻辑都是针对这单个敌人写的,完全没用到列表来管理多个敌人。这就是为什么你没法生成多个敌人的原因。

方案1:生成固定数量的敌人

我们可以直接在初始化阶段往enemy_list里添加多个敌人实例,然后修改绘制和碰撞逻辑来遍历这个列表。

修改步骤:

  1. 替换单个敌人为敌人列表
    把原来的aliens = enemy(...)删掉,换成生成多个敌人的代码:

    # 生成5个随机位置的敌人
    enemy_list = []
    for _ in range(5):
        # 随机x坐标,避免超出窗口,留出敌人宽度的余量
        random_x = random.randint(10, 550 - 15)  # 15是敌人width
        enemy_list.append(enemy(random_x, 20, 15, 25, 550))
    
  2. 更新绘制函数
    修改drawing_window里的敌人绘制逻辑,遍历列表绘制每个敌人:

    def drawing_window():
        window.fill((0,0,0))
        text = font.render('Score: ' + str(score), 1, (255,0,0))
        window.blit(text, (390, 10))
        space_ship.draw(window)
        for bullet in bullets :
            bullet.draw(window)
        # 遍历敌人列表绘制每个敌人
        for alien in enemy_list:
            if alien.visible:  # 只绘制可见的敌人
                alien.draw(window)
        pygame.display.update()
    
  3. 更新碰撞检测逻辑
    不管是玩家和敌人的碰撞,还是子弹和敌人的碰撞,都要遍历敌人列表:

    • 玩家与敌人的碰撞:
      # 玩家和敌人的碰撞检测
      for alien in enemy_list:
          if alien.visible and space_ship.visible:
              if space_ship.hitbox[1] < alien.hitbox[1] + alien.hitbox[3] and space_ship.hitbox[1] + space_ship.hitbox[3] > alien.hitbox[1]:
                  if space_ship.hitbox[0] + space_ship.hitbox[2] > alien.hitbox[0] and space_ship.hitbox[0] < alien.hitbox[0] + alien.hitbox[2]:
                      space_ship.hit()
      
    • 子弹与敌人的碰撞:
      for bullet in bullets[:]:  # 用切片避免遍历中修改列表出错
          for alien in enemy_list[:]:
              if alien.visible:
                  if bullet.y - bullet.radius < alien.hitbox[1] + alien.hitbox[3] and bullet.y + bullet.radius > alien.hitbox[1]:
                      if bullet.x + bullet.radius > alien.hitbox[0] and bullet.x - bullet.radius < alien.hitbox[0] + alien.hitbox[2]:
                          alien.hit()
                          score += 1
                          if not alien.visible:
                              enemy_list.remove(alien)  # 移除死亡的敌人
                          bullets.remove(bullet)
                          break  # 一颗子弹只打一个敌人
          if bullet in bullets:  # 如果子弹没命中敌人,继续处理移动
              if bullet.y > 0:
                  bullet.y -= 10
              else:
                  bullets.remove(bullet)
      

方案2:定时生成敌人

如果你想每隔几秒自动生成一个敌人,可以用Pygame的自定义事件来实现:

  1. 定义自定义事件并设置定时器
    在初始化部分添加:

    # 定义自定义生成敌人事件
    SPAWN_ENEMY = pygame.USEREVENT + 1
    # 每隔2000毫秒(2秒)触发一次
    pygame.time.set_timer(SPAWN_ENEMY, 2000)
    
  2. 在主循环中处理生成事件
    在事件处理部分添加:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            begin = False
        # 处理生成敌人事件
        if event.type == SPAWN_ENEMY:
            random_x = random.randint(10, 550 - 15)
            enemy_list.append(enemy(random_x, 20, 15, 25, 550))
    

完整修改后的代码

这里整合了固定生成+定时生成的逻辑(你可以根据需求选择其中一种,或者结合):

import pygame
import sys
import random
pygame.init()
#window of game
window = pygame.display.set_mode((550,550))
#character image
character = pygame.image.load('gg/New Piskel-1.png.png')
clock = pygame.time.Clock()
score = 0

# character class
class player(object):
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.speed = 5
        self.hitbox = (self.x + 10, self.y + 15, 33, 43)
        self.health = 10
        self.visible = True

    def draw(self , window):
        if self.visible == True:
            window.blit(character, (self.x ,self.y))
            self.hitbox = (self.x + 10, self.y + 15, 33, 43)
        if self.visible == False:
            font_display = pygame.font.SysFont('comicsans', 100)
            text = font_display.render('YOU ARE DEAD' , 1 , (255, 0, 0))
            window.blit(text , (275 - (text.get_width()/2), 275))
        pygame.display.update()

    def hit(self):
        if self.health > 0:
            self.health -= 1
        else:
            self.visible = False
            font_display = pygame.font.SysFont('comicsans', 100)
            text = font_display.render('YOU ARE DEAD' , 1 , (255, 0, 0))
            window.blit(text , (275 - (text.get_width()/2), 275))
            pygame.display.update()

class shot(object):
    def __init__(self , x , y , radius, color):
        self.x = x
        self.y = y
        self.radius = radius
        self.color = color
        self.speed = 10

    def draw(self , window):
        pygame.draw.circle(window, self.color ,(self.x , self.y), self.radius)

class enemy(object):
    enemy_img = pygame.image.load('gg/alien.png')
    def __init__(self , x , y , width , height , end):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.end = end
        self.speed = 1
        self.path = [self.y , self.end]
        self.hitbox = (self.x + 7, self.y, 13, 20)
        self.health = 14
        self.visible = True

    def draw(self, window):
        self.move()
        if self.y > 548:
            self.visible = False
        if self.visible:
            window.blit(self.enemy_img, (self.x , self.y))
            pygame.draw.rect(window, (255, 0, 0), (self.hitbox[0], self.hitbox[1] - 20, 14 , 10))
            pygame.draw.rect(window, (0, 255, 0), (self.hitbox[0], self.hitbox[1] - 20, 14 - ((14/7) * (14 - self.health)) , 10))
            self.hitbox = (self.x + 7, self.y, 13, 20)
            # pygame.draw.rect(window , (255, 0 , 0), self.hitbox , 2)# hitbox

    def move(self):
        if self.y + self.speed < self.path[1]:
            self.y += self.speed

    def hit(self):
        if self.health > 0:
            self.health -= 2
        else:
            self.visible = False

begin = True
bullets = []
enemy_list = []

# 初始化生成5个敌人
for _ in range(5):
    random_x = random.randint(10, 550 - 15)
    enemy_list.append(enemy(random_x, 20, 15, 25, 550))

# 定义定时生成敌人事件
SPAWN_ENEMY = pygame.USEREVENT + 1
pygame.time.set_timer(SPAWN_ENEMY, 2000)  # 每2秒生成一个

#animation/character display
def drawing_window():
    window.fill((0,0,0))
    text = font.render('Score: ' + str(score), 1, (255,0,0))
    window.blit(text, (390, 10))
    space_ship.draw(window)
    for bullet in bullets :
        bullet.draw(window)
    # 绘制所有可见敌人
    for alien in enemy_list:
        if alien.visible:
            alien.draw(window)
    pygame.display.update()

#movement and other repeating data (i.e bullets)
font = pygame.font.SysFont('comicsans', 30 , True)
space_ship = player(250 , 460 , 45 , 50)

while begin:
    clock.tick(50)

    # 玩家与敌人碰撞检测
    for alien in enemy_list:
        if alien.visible and space_ship.visible:
            if space_ship.hitbox[1] < alien.hitbox[1] + alien.hitbox[3] and space_ship.hitbox[1] + space_ship.hitbox[3] > alien.hitbox[1]:
                if space_ship.hitbox[0] + space_ship.hitbox[2] > alien.hitbox[0] and space_ship.hitbox[0] < alien.hitbox[0] + alien.hitbox[2]:
                    space_ship.hit()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            begin = False
        # 处理定时生成敌人
        if event.type == SPAWN_ENEMY:
            random_x = random.randint(10, 550 - 15)
            enemy_list.append(enemy(random_x, 20, 15, 25, 550))

    # 子弹逻辑
    for bullet in bullets[:]:
        hit_enemy = False
        for alien in enemy_list[:]:
            if alien.visible:
                if bullet.y - bullet.radius < alien.hitbox[1] + alien.hitbox[3] and bullet.y + bullet.radius > alien.hitbox[1]:
                    if bullet.x + bullet.radius > alien.hitbox[0] and bullet.x - bullet.radius < alien.hitbox[0] + alien.hitbox[2]:
                        alien.hit()
                        score += 1
                        if not alien.visible:
                            enemy_list.remove(alien)
                        bullets.remove(bullet)
                        hit_enemy = True
                        break
        if not hit_enemy:
            if bullet.y > 0:
                bullet.y -= 10
            else:
                bullets.remove(bullet)

    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE]:
        if len(bullets) < 11 and space_ship.visible:
            bullets.append(shot(round(space_ship.x + space_ship.width //2), round(space_ship.y + space_ship.height//2), 3 , (255,0,0)))

    if keys[pygame.K_LEFT] and space_ship.x > space_ship.speed and space_ship.visible:
        space_ship.x -= space_ship.speed
    elif keys[pygame.K_RIGHT] and space_ship.x < 550 - space_ship.width -space_ship.speed and space_ship.visible:
        space_ship.x += space_ship.speed

    if keys[pygame.K_UP] and space_ship.y > space_ship.speed and space_ship.visible:
        space_ship.y -= space_ship.speed

    if keys[pygame.K_DOWN] and space_ship.y <550 - space_ship.height - space_ship.speed and space_ship.visible:
        space_ship.y += space_ship.speed

    drawing_window()

pygame.quit()

额外小提示

  • 我简化了你的player.draw里的方向判断,因为你不管哪个方向都是绘制同一张图,没必要分那么多分支
  • 处理列表遍历时用了[:]切片,这样可以避免在遍历过程中修改列表导致的索引错误
  • 可以限制enemy_list的最大长度,防止敌人太多导致游戏卡顿

内容的提问来源于stack exchange,提问作者Laboratory gaming

火山引擎 最新活动