简体   繁体   中英

Removing Box2D bodies crashes AndEngine

Thanks in advance for your help!

I am building an Arkanoid/Breakout style game, and am running into some issues on account of body removal (at least that's where I suspect that the issue is). When I run the game, most of the time everything works just fine, but every now and then, the game crashes. during this crash, all of the sprites attached to bodies disappear, and any sprite without a body is left on the screen. There are no LogCat errors, but there is a drastic slowdown in FPS. Also, I noticed that sometime the contacts are registered twice before the code in the contact listener is fired (you can see where I implement the log file output in the ContactListener below).

In the game, instead of bricks, I am using bolts, and the code that I used to generate the bolts is listed below. After that, I show how I am using a ContactListener, and after that I give the code for removing the body/sprite combination. Any help or suggestions are greatly appreciated!

Thanks,

Adam

Creating the body/sprite items that will be removed when they are contacted.

//BOLTS
    final FixtureDef boltFixtureDef = PhysicsFactory.createFixtureDef(1, 1.0f, 0.1f);
    final Body[] boltBody=new Body[BOLT_NUMBER];
    final Sprite[] boltSprite=new Sprite[BOLT_NUMBER];
    final PhysicsConnector[] facePhysicsConnector= new PhysicsConnector[BOLT_NUMBER];
    String[] bodyNames=new String[BOLT_NUMBER];

        for(int i=0; i<BOLT_NUMBER; i++){
            boltSprite[i] = new Sprite(-100,-100, sceneManager.mBolt, sceneManager.activity.getVertexBufferObjectManager());
            boltSprite[i].setCullingEnabled(true);
            boltBody[i] = PhysicsFactory.createBoxBody(mPhysicsWorld, boltSprite[i], BodyType.KinematicBody, boltFixtureDef);
            mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(boltSprite[i], boltBody[i], true, true));
            bodyNames[i]="bolt"+Integer.toString(i);
            boltBody[i].setUserData(bodyNames[i]);
            facePhysicsConnector[i] = mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(boltSprite[i]);
            boltBody[i].setTransform(xLocations[i]/PMR, yLocations[i]/PMR, 0);}

            for(int i=0; i<BOLT_NUMBER; i++){       
                scene.attachChild(boltSprite[i]);}

The ContactListener:

final ContactListener contact = new ContactListener(){

    @Override
    public void postSolve(Contact contact, ContactImpulse impulse) {

        String a = (String) contact.getFixtureA().getBody().getUserData();
        String b = (String) contact.getFixtureB().getBody().getUserData();
        if(a != null && b != null) {
            for(int i=0; i<BOLT_NUMBER; i++){
                if(a.equals("wrench") && b.equals(facePhysicsConnector[i].getBody().getUserData()) ||
                             a.equals(facePhysicsConnector[i].getBody().getUserData()) && b.equals("wrench")) {
                               //boltCollision[i]=true;
                    Log.i("contact","bolt contact" + i);
                               myDestroyer(facePhysicsConnector[i], true);
                               Log.i("contact","bolt POSTcontact" + i);}

                else if((a.equals("wrench") && b.equals("paddle")) ||
                        (a.equals("paddle") && b.equals("wrench"))) {
                    Log.i("contact","paddle contact");
                       SpringNoise=true;}

                else if((a.equals("wrench") && b.equals("door")) ||
                         (a.equals("door") && b.equals("wrench"))) {
                    Log.i("contact","door contact");
                           WoodNoise=true;}
            }}

    }
    @Override
    public void endContact(final Contact contact) {}

    @Override
    public void beginContact(Contact contact) {}

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

And here is the code to remove the body/sprite combo:

private void myDestroyer(final PhysicsConnector facePhysicsConnector2, final Boolean bodyToo){
            if(killingInProcess == false){
                    killingInProcess = true;
                    //final PhysicsConnector facePhysicsConnector2 = mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(myShape);
                    sceneValue.engine.registerUpdateHandler(new IUpdateHandler(){
                            @Override
                            public void onUpdate(float pSecondsElapsed) {
                                sceneValue.engine.unregisterUpdateHandler(this);
                                sceneValue.engine.runOnUpdateThread(new Runnable(){
                                                    @Override
                                                    public void run() {
                                                        Log.i("contact","removing bolt");
                                                            mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector2);
                                                            Vibrator v = (Vibrator) sceneValue.activity.getSystemService(Context.VIBRATOR_SERVICE);
                                                            //myFixture.getBody().destroyFixture(myFixture);
                                                    if(bodyToo == true){
                                                                    mPhysicsWorld.destroyBody(facePhysicsConnector2.getBody());
                                                    }
                                                    facePhysicsConnector2.getShape().registerEntityModifier(new ParallelEntityModifier(new RotationModifier(3,180,0),
                                                    new ScaleModifier(3, 1, 0)));
                                                    sceneValue.mBlockSound.play();
                                                    v.vibrate(75);

                                                    //mScene.detachChild(mySprite);
                                                    System.gc();
                                                    killingInProcess = false;
                                                    }
                                            });
                            }
                            @Override
                            public void reset() {
                            }
                    });    
            }}

I'm not sure about the crashing problem, but I do know why the removal of bodies happens too late.

The method postSolve is called from the UpdaeThread. But instead of removing the body there, you register another update handler (So it's code runs in the next game update). And in this code, you run another code in runOnUpdateThread so it runs again in the next game update . You skipped 2 updates for no reason :) This might create problems (It probably does)

I suggest you to fix this, this look up for another problems (This may serious and it's easily solved)

I'm not sure, but I think that the problem might be in your removing of sprites. I met the problem and now I'm trying to kill bodies in update handler like this(method onUpdate in IUpdateHandler):

                final PhysicsConnector physicsConnector = physicsWorld
                        .getPhysicsConnectorManager().findPhysicsConnectorByShape(
                                body);
                body.clearEntityModifiers();
                physicsWorld.unregisterPhysicsConnector(physicsConnector );
                physicsWorld.destroyBody(physicsConnector.getBody());
                scene.detachChild(body);
                activity.getEngine().unregisterUpdateHandler(this);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM