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

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()
问题根因
  1. 逻辑嵌套错误:update_entities本身就在遍历单个实体,当某个实体满足射击条件(a==205)时调用的entity_shoot又额外写了一层遍历所有实体的循环,等于只要一个实体触发射击,就会给所有实体走一遍生成子弹的流程。
  2. 全局变量覆盖:entity_bullet、ebullet_coordinates都是实例级共享变量,遍历过程中每次赋值都会覆盖上一次的计算结果,整个循环跑完之后变量里只会保留最后一个实体的对应值,表现出来就是只有最后一个实体的射击逻辑生效。
  3. 后续子弹逻辑存在连锁错误:子弹移动、碰撞检测部分的循环逻辑完全错误,单个Image类型的子弹对象不是可迭代对象,内层遍历子弹的循环本身就无法正常执行;同时子弹移动的偏移量是全局计算一次,没有针对每颗子弹单独计算,碰撞检测时遍历列表直接删除元素还会导致索引错位,出现漏删、错删问题。
修复方向
  • 调整entity_shoot逻辑:去掉函数内部遍历所有实体的循环,触发射击时直接把当前遍历到的实体作为参数传入,只给当前满足条件的实体生成子弹。
  • 清理不必要的全局共享中间变量:子弹生成、坐标计算、移动偏移、碰撞检测都针对单个子弹/实体对象单独处理,不要用全局变量反复覆盖结果。
  • 修正循环写法:遍历子弹列表时不要把循环变量赋值给实例属性,遍历过程中如果需要删除元素,就遍历列表的副本或者倒序遍历,避免索引错位。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 00:12:40