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

LibGDX Box2D碰撞触发时删除物体导致游戏崩溃问题求助

LibGDX Box2D抛射物碰撞敌人后崩溃问题修复

问题描述

在LibGDX的Box2D模块中处理抛射物与敌人的碰撞逻辑,期望抛射物击中敌人后消失,但碰撞发生时游戏直接崩溃。尝试过在update方法调用world.destroyBody()、body.destroyFixture(),也试过在beginContact中添加物体到删除列表,均未解决问题。

原代码

CollisionProcessing类

public class CollisionProcessing implements ContactListener {
    World world;

    public static ArrayList<Body> deleteList = new ArrayList<>();

    public CollisionProcessing(World world) {
        super();
        this.world = world;
    }
    @Override
    public void beginContact(Contact contact) {}

    @Override
    public void endContact(Contact contact) {}

    @Override
    public void preSolve(Contact contact, Manifold manifold) {}

    @Override
    public void postSolve(Contact contact, ContactImpulse contactImpulse) {
        Fixture A = contact.getFixtureA();
        Fixture B = contact.getFixtureB();
        if (A == null || B == null) return;
        if (A.getUserData() == null || B.getUserData() == null) return;

        if (A.getUserData().equals(3)) {
            System.out.println("Bullet Body collision");
            deleteList.add(A.getBody());
        }
        if (B.getUserData().equals(3)) {
            System.out.println("Body Bullet collision");
            deleteList.add(B.getBody());
        }
    }
    public static ArrayList<Body> getDeleteList() {
        return deleteList;
    }
}

update方法

public void update() {
        deleteList = CollisionProcessing.getDeleteList();
        deleteList.forEach(obj -> {
            obj.setActive(false);
            world.destroyBody(obj);
        });
        world.step(1/60f, 6, 2);

        inputUpdate();
        cameraUpdate();
        enemies.forEach(enemy -> enemyUpdate(enemy));
        bullets.forEach(bullet -> bulletUpdate(bullet.getPoint().x, bullet.getPoint().y));

}

问题原因与修复方案

核心问题

  1. 销毁时机错误:在world.step()前销毁Body,此时Box2D仍在处理当前帧物理计算,直接修改世界结构会触发崩溃。
  2. 删除列表未清空:重复使用同一静态列表,导致已销毁的Body被重复操作。
  3. 静态列表风险:静态deleteList若存在多实例会引发数据混乱,且无法保证线程安全。

具体修复步骤

1. 修改CollisionProcessing类

  • 移除deleteList的静态修饰符,改为实例变量
  • 移动物体检测逻辑到beginContact(比postSolve更适合触发碰撞销毁逻辑)
  • 添加重复添加检查,避免同一Body被多次加入删除列表
public class CollisionProcessing implements ContactListener {
    World world;
    public ArrayList<Body> deleteList = new ArrayList<>();

    public CollisionProcessing(World world) {
        this.world = world;
    }

    @Override
    public void beginContact(Contact contact) {
        Fixture A = contact.getFixtureA();
        Fixture B = contact.getFixtureB();
        if (A == null || B == null) return;
        if (A.getUserData() == null || B.getUserData() == null) return;

        checkAndAddToDeleteList(A);
        checkAndAddToDeleteList(B);
    }

    private void checkAndAddToDeleteList(Fixture fixture) {
        if (fixture.getUserData().equals(3)) {
            System.out.println("Bullet collision detected");
            Body body = fixture.getBody();
            if (!deleteList.contains(body)) {
                deleteList.add(body);
            }
        }
    }

    @Override
    public void endContact(Contact contact) {}
    @Override
    public void preSolve(Contact contact, Manifold manifold) {}
    @Override
    public void postSolve(Contact contact, ContactImpulse contactImpulse) {}

    public ArrayList<Body> getDeleteList() {
        return deleteList;
    }
}

2. 调整update方法逻辑

  • 先执行world.step()完成物理计算,再处理Body销毁
  • 销毁完成后清空删除列表,避免重复操作
  • 增加Body活跃状态检查,防止重复销毁
public void update() {
    // 先完成当前帧物理模拟
    world.step(1/60f, 6, 2);

    // 处理Body销毁(需持有CollisionProcessing实例引用)
    ArrayList<Body> deleteList = collisionProcessing.getDeleteList();
    for (Body body : deleteList) {
        if (body.isActive()) {
            body.setActive(false);
            world.destroyBody(body);
        }
    }
    deleteList.clear(); // 清空列表,避免重复操作

    inputUpdate();
    cameraUpdate();
    enemies.forEach(this::enemyUpdate);
    bullets.forEach(bullet -> bulletUpdate(bullet.getPoint().x, bullet.getPoint().y));
}

额外注意事项

  • 禁止在ContactListener回调中直接销毁Body/Fixture,必须延迟到world.step()之后
  • 确保抛射物Fixture的UserData是Integer类型的3,避免类型不匹配导致逻辑失效
  • 若使用多个CollisionProcessing实例,需保证每个实例持有独立的删除列表

内容的提问来源于stack exchange,提问作者Happy Trash Bin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:37:39