libGDX Box2D:碰撞后如何销毁物体?

问题描述 投票:0回答:2

感谢您的宝贵时间。

我正在通过 libGDX 使用 Box2D 创建 Pong 克隆。当由于球体与两个目标传感器体之一接触而尝试删除球体时(下图),我遇到了一个导致空指针异常的症结点。

我想将接触的球体添加到列表中,以便稍后可以遍历列表来删除球体(以及将来的多个球体)。

enter image description here

堆栈跟踪:

Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.physics.box2d.World.destroyBody(World.java:311)
at com.ckq3r.Ponger.screens.GameScreen.update(GameScreen.java:484)
at com.ckq3r.Ponger.screens.GameScreen.render(GameScreen.java:114)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.ckq3r.Ponger.PongerGame.render(PongerGame.java:236)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:204)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:112)

我的 GameScreen 类中的第 484 行是位于

world.destroyBody(circleBody);
方法的
if(scoredGoal1 == true){stuff}
条件语句中的行
public void render(float delta){stuff}
,如下所示。

public class GameScreen implements Screen, InputProcessor{

/*----methods and variables omitted for readability------*/

private boolean scoredGoal1 = false, scoredGoal2 = false;
ArrayList<Body> ballDeletionList = new ArrayList<Body>();

/*==============Screen implementation methods============*/
    @Override
    public void show(){
        /*ball*/
        BodyDef circleDef = new BodyDef();      
        Body circleBody = world.createBody(circleDef);
        circleBody.setUserData(1);              
        CircleShape circleShape = new CircleShape();                
        FixtureDef circleFixture = new FixtureDef();
        circleFixture.shape = circleShape;              
        circleBody.createFixture(circleFixture);        
        circleShape.dispose();
    }

    @Override
    public void render(float delta) {           
        world.step(Gdx.app.getGraphics().getDeltaTime(), 8, 3);
        Gdx.gl.glClearColor(0, 0, 0, 1); 
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        camera.update();
        debugRenderer.render(world, camera.combined);

        /*-------ball deletion experiment-------*/          
        if(scoredGoal1 == true){

            //iterate through ballDeletionList somehow?

            world.destroyBody(circleBody);                            
            circleBody.setUserData(null);
            circleBody = null;                              
            scoredGoal1 = false;
            //clear ballDeletionList

        }else if(scoredGoal2 == true){

            //iterate through ballDeletionList somehow?

            world.destroyBody(circleBody);
            circleBody.setUserData(null);
            circleBody = null;              
            scoredGoal2 = false;
            //clear ballDeletionList
        }
        /*-----end ball deletion experiment------*/
}   

/*===========Box2D contact listener=============*/
    private void createContactListener() {
        world.setContactListener(new ContactListener() {

        @Override
        public void beginContact(Contact contact) {
            Fixture fixtureA = contact.getFixtureA();
            Fixture fixtureB = contact.getFixtureB();
            Gdx.app.log("beginContact", "between " + fixtureA.toString() + " and " + fixtureB.toString());

            if(fixtureA.getBody().getUserData().equals(1) && fixtureB.getBody().getUserData().equals(2) || fixtureA.getBody().getUserData().equals(2) && fixtureB.getBody().getUserData().equals(1)){
                Gdx.app.log("HIT", "goal1 contact");

                /*ball deletion experiment*/
                ballDeletionList.add(circleBody);
                Gdx.app.log("Ball", "circleBody added to deletion list");
                scoredGoal1 = true;
                /*ball deletion experiment*/
            }         

            if(fixtureA.getBody().getUserData().equals(1) && fixtureB.getBody().getUserData().equals(3) || fixtureA.getBody().getUserData().equals(3) && fixtureB.getBody().getUserData().equals(1)){
                Gdx.app.log("HIT", "goal2 contact");

                /*ball deletion experiment*/
                ballDeletionList.add(circleBody);
                Gdx.app.log("Ball", "circleBody added to deletion list");
                scoredGoal2 = true;
                /*ball deletion experiment*/
            }
        }                

        });

关于球体和目标传感器体之间的接触,我的逻辑如下:

  1. 在 ContactListener 的 beginContact() 方法中,与 EdgeShape 传感器主体接触的球体将被添加到
    ArrayList<Body> ballDeletionList = new ArrayList<Body>();
    并且
    scoredGoal1 = true;
    布尔标志将设置为 true。
  2. render();
    中检查
    scoredGoal1 = true
    scoredGoal2 = true
    ,然后在
    world.step()
    方法之后删除适用的一个或多个正文。

我在整个网络上搜索了其他代码示例和教程,但发现的答案不明确,因为代码要么是专门针对大小写的,要么我目前只了解 Java。

如果可以发布 Java/libGDX 代码示例解决方案,那就太好了。

android box2d libgdx physics game-physics
2个回答
2
投票

您无法删除联系人侦听器中的主体,因为它位于您的世界步骤内,并且世界已锁定。 我在渲染方法中所做的与您尝试做的完全相同:

if(ballDeletionList.size>0) ballDeletionList.clear();

另外,使用 libgdx 建议使用 Array http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Array.html 而不是 ArrayList,它会产生更少的垃圾并使得更多优化。


0
投票

我认为你应该让 FixtureDef 能够为此定义 maskBits,然后更改 maskBits

看这个链接https://github.com/yichen0831/SuperMarioPratice_libGDX/blob/master/core/src/com/ychstudio/actors/enemies/Goomba.java

© www.soinside.com 2019 - 2024. All rights reserved.