Python Arcade游戏菜单场景敌人生成计时器触发崩溃修复
问题根源
崩溃由两个逻辑缺陷共同导致:
- 敌人生成计时器、刷怪逻辑写在场景判断分支外部,菜单场景下计时器仍在后台累计时间
- 菜单阶段
setup()方法未执行,enemy_list为None,一旦计时器达到刷怪阈值,代码尝试向不存在的列表追加精灵实例,直接触发属性错误崩溃。
修复方案
按照以下三点修改即可彻底解决问题:
- 将所有计时累加、时间计算、敌人生成的逻辑,整体移动到
SCENE_GAME的判断分支内部,菜单场景下完全不执行刷怪相关逻辑,从执行路径上切断菜单阶段触发刷怪的可能 - 点击开始按钮进入游戏时,重置刷怪计时器、每波敌人数、刷怪间隔三个参数的初始值,避免程序启动后菜单停留的累计时间带入游戏局内,导致刚进游戏就瞬间刷怪
- 在游戏场景逻辑最前端加一层防御校验,判断核心精灵列表是否已初始化,避免后续其他场景切换逻辑出问题时再次触发同类崩溃
具体代码修改
首先修改开始按钮的点击回调,加入参数重置逻辑:
def on_click_start(self, event): self.setup() # 重置刷怪相关参数,避免菜单阶段的残留值影响新局 self.total_time = 0.0 self.enemy_count = 1 self.enemy_diff = 3 self.scene = SCENE_GAME self.manager.disable() print("Start:", event)
然后修改on_update方法,把原本在场景判断外的计时、刷怪逻辑全部移入游戏场景分支,同时加入防御校验:
def on_update(self, delta_time): """ updates values n stuff """ if self.scene == SCENE_GAME: # 防御校验:核心精灵列表未初始化时直接返回,避免崩溃 if not self.player_list or not self.enemy_list or not self.bullet_list: return # call update to move the sprite self.player_list.update() # Call update on all sprites self.bullet_list.update() # go through each bullet for bullet in self.bullet_list: # check each bullet to see if it hit a zombie hit_list = arcade.check_for_collision_with_list(bullet, self.enemy_list) # if it did, remove the bullet if len(hit_list) > 0: bullet.remove_from_sprite_lists() # for each enemy we hit with a bullet, remove enemy and add to the score for enemy in hit_list: enemy.remove_from_sprite_lists() self.score += 1 # if bullet goes off screen, then remove it if bullet.bottom > self.width or bullet.top < 0 or bullet.right < 0 or bullet.left > self.width: bullet.remove_from_sprite_lists() for enemy in self.enemy_list: Enemy.follow_sprite(enemy, self.player_sprite) # create a list of all sprites that had a collision with the player. hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.enemy_list) # go through each sprite, if it got hit, then remove the sprite and lower score and health for enemy in hit_list: enemy.remove_from_sprite_lists() self.score -= 1 self.health -= 1 # 仅在游戏场景下累计刷怪时间 self.total_time += delta_time # Calculate minutes minutes = int(self.total_time) // 60 # Calculate seconds by using a modulus (remainder) seconds = int(self.total_time) % 60 # Calculate 100s of a second seconds_100s = int((self.total_time - seconds) * 100) if self.total_time > self.enemy_diff: for i in range(self.enemy_count): # enemy texture enemy = arcade.Sprite(":resources:images/animated_characters/zombie/zombie_idle.png", SPRITE_SCALING) enemy.center_x = random.randrange(SCREEN_WIDTH) enemy.center_y = random.randrange(SCREEN_HEIGHT) self.enemy_list.append(enemy) self.total_time = 0.0 self.enemy_diff -= 0.005 self.enemy_count += 1
可选优化
- 当前敌人会完全随机生成在屏幕任意位置,可能直接刷在玩家出生点导致瞬间掉血,可以在生成敌人时计算和玩家坐标的距离,距离小于200像素时重新随机生成位置
- 现有鼠标点击退出的逻辑没有场景判断,菜单下点击鼠标也会直接触发退出,可以给死亡退出逻辑加上
self.scene == SCENE_GAME and self.health <=0的前置判断 - 刷怪间隔不要无限制缩短,可以加个最小值判断,比如
self.enemy_diff降到0.5秒就不再减少,避免后期刷怪速度太快导致游戏完全无法进行
内容的提问来源于stack exchange,提问作者riley
相关产品推荐
相关产品推荐

