You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame射击游戏敌人触底失败条件误触发问题求助

Pygame射击游戏失败条件异常问题修复

问题背景

开发了一款基于Pygame的射击游戏,核心玩法为射击敌方飞船。需要添加失败条件:当敌人到达屏幕底部时,游戏暂停,清除屏幕上的子弹和敌人,几秒后重新开始游戏。

尝试用以下代码实现,但出现异常:即使第一行敌人已被完全消灭,或无任何敌人触底,失败逻辑仍会触发:

for enemy in enemys.sprites():
    if enemy.rect.bottom >= screen.get_rect().bottom:
        #game_over

错误原因分析

  1. 空列表索引错误:生成新敌人的逻辑中,last_enemy = enemys.sprites()[-1]在敌人被全部消灭后,enemys.sprites()为空列表,取[-1]会抛出索引错误,导致后续逻辑混乱,误触发失败条件。
  2. 失败条件未做空判断:检查敌人触底时,未先判断敌人组是否为空,直接遍历会导致无意义执行,甚至因之前的错误引发异常。
  3. 缺少失败后重置逻辑:原代码未实现失败后的暂停、清除元素和重启游戏的完整流程。

修正方案

关键修复点

  • 生成新敌人前先判断敌人组是否为空,避免空列表索引错误
  • 检查敌人触底时,先确认敌人组非空,再遍历判断
  • 添加完整的失败处理流程:暂停游戏、清除子弹和敌人、等待几秒后重新生成初始敌人

完整修正代码

import pygame
import sys
import time
from pygame.sprite import Group

pygame.init()

# 屏幕参数
height, width = 800, 650 
screen = pygame.display.set_mode((width, height))
screen_rect = screen.get_rect()

# 玩家飞船
class Ship:
    def __init__(self, screen):
        self.screen = screen
        self.rect = pygame.Rect(300, 710, 80, 80)
        self.color = (255, 255, 255)

        self.move_left = False
        self.move_right = False

    def move(self):
        if self.move_left:
            self.rect.centerx -= 1
        elif self.move_right:
            self.rect.centerx += 1
        # 边界限制
        if self.rect.right >= width:
            self.rect.right = width
        elif self.rect.left <= 0:
            self.rect.left = 0

    def output_s(self):
        pygame.draw.rect(self.screen, self.color, self.rect)


# 子弹类
class Bullet(pygame.sprite.Sprite):
    def __init__(self, screen, my_ship):
        super(Bullet, self).__init__()
        self.screen = screen
        self.rect = pygame.Rect(0, 0, 100, 10)
        self.speed = 5
        self.rect.centerx = my_ship.rect.centerx
        self.rect.top = my_ship.rect.top
        self.y = self.rect.y

    def update(self):
        self.y -= self.speed
        self.rect.y = self.y

    def draw_bullet(self):
        pygame.draw.rect(self.screen, (255, 255, 255), self.rect)


# 敌人飞船类
class Enemy(pygame.sprite.Sprite):
    def __init__(self, screen):
        super(Enemy, self).__init__()
        self.screen = screen
        self.rect = pygame.Rect(0, 0, 70, 70)
        self.rect.top = screen_rect.top
        self.rect.centerx = screen_rect.centerx
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

    def output_e(self):
        pygame.draw.rect(self.screen, (255, 255, 255), self.rect)

    def update(self):
        self.y += 0.1
        self.rect.y = self.y


# 初始化对象和组
my_ship = Ship(screen)
bullets = Group()
enemys = Group()

# 创建一行敌人
def create_enemy(screen, enemys, width):
    if not enemys:  # 避免重复创建
        enemy_width = Enemy(screen).rect.width
        e_numbers = (width - 50) // enemy_width
        for i in range(e_numbers):
            enemy = Enemy(screen)
            enemy.x = 25 + (enemy_width + 25) * i
            enemy.rect.x = enemy.x
            enemys.add(enemy)


# 更新子弹和碰撞检测
def update_bullets(bullets, enemys):
    bullets.update()
    pygame.sprite.groupcollide(bullets, enemys, True, True)
    # 移除超出屏幕的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)


# 屏幕刷新
def screen_update(screen, enemys, bullets):
    screen.fill((0, 0, 0))
    for enemy in enemys:
        enemy.output_e()
    for bullet in bullets:
        bullet.draw_bullet()
    my_ship.output_s()
    my_ship.move()
    pygame.display.flip()

# 失败处理函数
def handle_game_over(bullets, enemys):
    # 清除所有子弹和敌人
    bullets.empty()
    enemys.empty()
    # 显示游戏结束提示(可选)
    font = pygame.font.SysFont(None, 72)
    game_over_text = font.render("GAME OVER", True, (255, 0, 0))
    screen.blit(game_over_text, (width//2 - game_over_text.get_width()//2, height//2))
    pygame.display.flip()
    # 暂停3秒
    time.sleep(3)
    # 重新生成初始敌人
    create_enemy(screen, enemys, width)

# 主游戏循环
def main():
    create_enemy(screen, enemys, width)
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_a:
                    my_ship.move_left = True
                elif event.key == pygame.K_d:
                    my_ship.move_right = True
                elif event.key == pygame.K_SPACE:
                    new_bullet = Bullet(screen, my_ship)
                    bullets.add(new_bullet)
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_a:
                    my_ship.move_left = False
                elif event.key == pygame.K_d:
                    my_ship.move_right = False

        # 生成新敌人:仅当敌人组非空,且最后一个敌人下移到指定位置时
        if enemys:
            last_enemy = enemys.sprites()[-1]
            if last_enemy.rect.y >= 100:
                create_enemy(screen, enemys, width)

        enemys.update()
        update_bullets(bullets, enemys)

        # 检查失败条件:敌人触底
        game_over = False
        if enemys:
            for enemy in enemys.sprites():
                if enemy.rect.bottom >= screen_rect.bottom:
                    game_over = True
                    break
        if game_over:
            handle_game_over(bullets, enemys)

        screen_update(screen, enemys, bullets)

if __name__ == "__main__":
    main()

修复说明

  1. 空列表判断:在生成新敌人和检查失败条件前,都先判断enemys是否为空,避免索引错误和无效遍历。
  2. 完整失败流程:新增handle_game_over函数,实现清除元素、显示提示、暂停等待和重启游戏的逻辑。
  3. 代码优化:简化了部分冗余判断(如== True直接用变量本身),统一了屏幕边界的引用。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:49:51