如何在Pygame太空侵略者类游戏中实现多敌人生成?
解决太空侵略者游戏多敌人生成问题
嘿,我看你在开发太空侵略者游戏时,卡在了生成多个敌人实例的问题上——别担心,咱们一步步把这个问题搞定!
当前代码的核心问题
你已经定义了enemy_list列表,但实际代码里只创建了单个aliens敌人实例,而且绘制、碰撞检测逻辑都是针对这单个敌人写的,完全没用到列表来管理多个敌人。这就是为什么你没法生成多个敌人的原因。
方案1:生成固定数量的敌人
我们可以直接在初始化阶段往enemy_list里添加多个敌人实例,然后修改绘制和碰撞逻辑来遍历这个列表。
修改步骤:
替换单个敌人为敌人列表
把原来的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))更新绘制函数
修改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()更新碰撞检测逻辑
不管是玩家和敌人的碰撞,还是子弹和敌人的碰撞,都要遍历敌人列表:- 玩家与敌人的碰撞:
# 玩家和敌人的碰撞检测 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的自定义事件来实现:
定义自定义事件并设置定时器
在初始化部分添加:# 定义自定义生成敌人事件 SPAWN_ENEMY = pygame.USEREVENT + 1 # 每隔2000毫秒(2秒)触发一次 pygame.time.set_timer(SPAWN_ENEMY, 2000)在主循环中处理生成事件
在事件处理部分添加: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




