Python游戏开发:遍历实体列表时射击函数仅最后一个实体生效
问题描述
- 编写
update_entities函数用于持续更新游戏内实体状态,upward和downward两个函数实现实体的基础上下移动逻辑 - 函数放在for循环中执行:游戏每回合生成3个实体/敌人,循环遍历所有实体,统一管控实体的位置坐标、武器射击触发等状态
- 异常表现:所有实体的振荡移动逻辑运行正常,但射击逻辑始终只对3个实体中的最后一个生效,不符合预期;单独测试射击函数本身运行逻辑无问题
相关代码
entity_bullet = None ebullet_coordinates = [(0, 0), (0, 0)] entity_bullets = [] def get_ebullet_coordinates(self): for child in self.entity_bullets: x1, y1 = child.pos self.ebullet_coordinates[0] = (x1, y1) x2, y2 = child.pos[0] + child.width, child.pos[1] + child.height self.ebullet_coordinates[1] = (x2, y2) def entity_shoot(self): for child in self.entities: self.get_entity_coordinates() x = self.entity_coordinates[0][0] y = self.entity_coordinates[0][1] - 20 if child.source == "images/evil_drone.png": self.entity_bullet = Image(source="images/evil_drone_bullet2.png", pos=(x, y)) elif child.source == "images/angry_cloud.png": self.entity_bullet = Image(source="images/lightning_bullet2.png", pos=(x, y)) elif child.source == "images/skullairballoon.png": self.entity_bullet = Image(source="images/bomb.png", pos=(x, y)) self.add_widget(self.entity_bullet) self.entity_bullets.append(self.entity_bullet) # Add to list for them to move def update_entity_bullets(self): self.get_drone_coordinates() self.get_entity_coordinates() drone_xmin, drone_ymin = self.drone_coordinates[0][0], self.drone_coordinates[0][1] drone_xmax, drone_ymax = self.drone_coordinates[1][0], self.drone_coordinates[1][1] bullet_xmin, bullet_ymin = self.entity_coordinates[0][0], self.entity_coordinates[0][1] - 20 bullet_xmax, bullet_ymax = self.entity_coordinates[1][0], self.entity_coordinates[1][1] xdistance = bullet_xmax - drone_xmin ydistance = bullet_ymin - drone_ymax final_xdistance = (xdistance / 60) + 1 final_ydistance = (ydistance / 60) + 1 for self.entity_bullet in self.entity_bullets: for child in self.entity_bullet: if child.pos[1] <= 0: self.remove_widget(child) elif child.pos[1] >= self.height - 10: self.remove_widget(child) if child.pos[0] <= -10: self.remove_widget(child) elif child.pos[0] >= self.width - 10: self.remove_widget(child) self.entity_bullet.pos[0] -= final_xdistance self.entity_bullet.pos[1] -= final_ydistance pass def check_ebullet_collision(self, dt): if self.game_ongoing: self.get_drone_coordinates() self.get_ebullet_coordinates() drone_xmin, drone_ymin = self.drone_coordinates[0][0], self.drone_coordinates[0][1] drone_xmax, drone_ymax = self.drone_coordinates[1][0], self.drone_coordinates[1][1] bullet_xmin, bullet_ymin = self.ebullet_coordinates[0][0], self.ebullet_coordinates[0][1] bullet_xmax, bullet_ymax = self.ebullet_coordinates[1][0], self.ebullet_coordinates[1][1] if ((drone_xmax - 40) >= bullet_xmin >= (drone_xmin - 50)) and ((drone_ymax - 65) >= bullet_ymin >= (drone_ymin - 50)): print("hit") for self.entity_bullet in self.entity_bullets: self.remove_widget(self.entity_bullet) for ebullet in self.entity_bullet: self.entity_bullets.remove(ebullet) self.remove_widget(ebullet) def update_entities(self): for child in self.entities: z = random.randint(1, 3000) a = random.randint(1, 215) def upward(): child.pos[1] += .1 def downward(): child.pos[1] -= .1 if z >= 2800 or z % 2 == 0: for i in range(random.randint(1, 20)): upward() else: for i in range(random.randint(1, 22)): downward() if a == 205: self.entity_shoot()
问题根因
- 逻辑嵌套错误:
update_entities本身就在遍历单个实体,当某个实体满足射击条件(a==205)时调用的entity_shoot又额外写了一层遍历所有实体的循环,等于只要一个实体触发射击,就会给所有实体走一遍生成子弹的流程。 - 全局变量覆盖:
entity_bullet、ebullet_coordinates都是实例级共享变量,遍历过程中每次赋值都会覆盖上一次的计算结果,整个循环跑完之后变量里只会保留最后一个实体的对应值,表现出来就是只有最后一个实体的射击逻辑生效。 - 后续子弹逻辑存在连锁错误:子弹移动、碰撞检测部分的循环逻辑完全错误,单个
Image类型的子弹对象不是可迭代对象,内层遍历子弹的循环本身就无法正常执行;同时子弹移动的偏移量是全局计算一次,没有针对每颗子弹单独计算,碰撞检测时遍历列表直接删除元素还会导致索引错位,出现漏删、错删问题。
修复方向
- 调整
entity_shoot逻辑:去掉函数内部遍历所有实体的循环,触发射击时直接把当前遍历到的实体作为参数传入,只给当前满足条件的实体生成子弹。 - 清理不必要的全局共享中间变量:子弹生成、坐标计算、移动偏移、碰撞检测都针对单个子弹/实体对象单独处理,不要用全局变量反复覆盖结果。
- 修正循环写法:遍历子弹列表时不要把循环变量赋值给实例属性,遍历过程中如果需要删除元素,就遍历列表的副本或者倒序遍历,避免索引错位。
内容的提问来源于stack exchange,提问作者Pyr0
相关产品推荐
相关产品推荐

