Python Arcade游戏定时生成敌人 无total_time属性报错修复
问题描述
使用Python Arcade开发基础僵尸射击游戏(核心玩法为操控角色移动、射击僵尸)时,实现敌人随时间自动生成功能触发如下报错:AttributeError: 'MyGame' object has no attribute 'total_time'
已在MyGame类中定义self.total_time属性,仍无法定位报错原因。
报错根因
self.total_time的初始化逻辑写在setup()方法内,而setup()仅在玩家点击「Start Game」按钮触发on_click_start时才会执行。
Arcade框架的on_update生命周期函数从窗口创建完成、处于主菜单阶段时就会每帧自动调用,此时还未执行setup(),self.total_time属性尚未创建,执行到self.total_time += delta_time时就会触发属性不存在的错误。
除此之外原代码还存在两个逻辑隐患:
- 计时、敌人生成逻辑写在
if self.scene == SCENE_GAME判断外,主菜单阶段也会累加时间,不符合功能预期 - 重置计时器的
self.total_time = 0.0写在生成敌人的for循环内部,每生成1个敌人就会重置一次计时,导致5个敌人生成完计时器直接归0,永远无法触发下一波敌人生成
修复方案
- 把所有游戏内计时、敌人生成相关的逻辑,全部移动到
on_update方法的if self.scene == SCENE_GAME:代码块内部,保证仅进入游戏场景后才执行这部分逻辑 - 把重置计时器的代码移到敌人生成的for循环外部,确保每波敌人全部生成完后再重置计时
修正后的on_update方法核心代码如下:
def on_update(self, delta_time): """ updates values n stuff """ if self.scene == SCENE_GAME: # 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 if self.total_time > 5: for i in range(5): # 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
如果想进一步规避初始化顺序导致的属性问题,也可以在__init__方法中提前给self.total_time赋初始值0.0,做双重保险。
内容的提问来源于stack exchange,提问作者riley
相关产品推荐
相关产品推荐

