Box2D AndEngine: app hangs out when creating Joints during ContactListener?

…衆ロ難τιáo~ 提交于 2019-12-10 11:33:00

问题


I am using Box2D in AndEngine (for Android).

My purpose is to create a Force joint whenever 2 objects collide with each other.

When I try to create a Mouse Joint between 2 objects (bodies) during ContactListner process. The application will hang for some time then exit, without any error, just a notification of threads ending.

The Joint creating is OK when I call mEnvironment.CreateForceJoint(..) outside the ContactListener - somewhere while app is running in some physics.UpdateHandler().

Please help me to solve the problems, or find out the reason. Thanks for any help!

This is my code:

public class MyActivity extends SimpleBaseGameActivity {
    private final String DEBUG_TAG = "MyActivity";
    private GEnvironment mEnvironment;
    private PhysicsWorld mPhysicsWorld;

    private MyFixture FIXTURE_PLANET = GlobalSettings.FIXTURE_PLANET;
    private MyFixture FIXTURE_VACUUM = GlobalSettings.FIXTURE_VACUUM;

    // CODE TO CREATE RESOURCES and ENGINE OPTIONS....

    @Override
    protected Scene onCreateScene() {
        Scene scene = new Scene();
        scene.setBackground(new Background(0.8627f, 0.9020f, 1.0f));

        //CODE: creating physic world
        //.....

        //creating game environment
        mEnvironment = new GEnvironment(mPhysicsWorld, scene, mEngine);

        //CODE: creating objects, register and attach them into scene
        GMediaPlanet sunZone = mEnvironment.CreatePlanet(x1, y1, sunTextureRegion, FIXTURE_PLANET);
        GMediaPlanet earthZone = mEnvironment.CreatePlanet(x2, y2, earthTextureRegion, FIXTURE_PLANET);

        // enable contact listener, detect collision between bodies
        mPhysicsWorld.setContactListener(new PlanetContactHandler());

        return scene;
    }

    // ----------------------------------------------------
    // Handling collision between letter cubes
    // ----------------------------------------------------
    /**
     * Handling the collision of GMediaPlanets
     */
    public class PlanetContactHandler implements ContactListener {
        private final String DEBUG_TAG = "CONTACT";

        // if there's one collision, do not handle others or re-handle it
        private boolean mIsColliding = false;

        @Override
        public void beginContact(Contact contact) {
            if (mIsColliding)
                return;

            //-----------------------------------------------
            //suppose colliding objects to be sunZone and earthZone
            //-----------------------------------------------
            Object aTag = contact.getFixtureA().getBody().getUserData();
            Object bTag = contact.getFixtureB().getBody().getUserData();

            if (aTag != null && bTag != null) {
                GMediaPlanet box = null;
                GMediaPlanet cube = null;

                if (aTag instanceof GMediaPlanet
                        && bTag instanceof GMediaPlanet) {
                    box = (GMediaPlanet) aTag;
                    cube = (GMediaPlanet) bTag;
                }

                if (box != null && cube != null) 
                {
                    //!!!!!!!-----------------------------------------------------
                    //This code will HANG the app when called inside contact listner:
                    MouseJoint mTestJoint = mEnvironment.CreateForceJoint(box, cube);
                    //!!!!!!!-----------------------------------------------------

                    Vector2 target = Vector2Pool.obtain(box.GetLocation());
                    mTestJoint.setTarget(target);
                    Vector2Pool.recycle(target);
                }
            }
            mIsColliding = true;
        }

        @Override
        public void endContact(Contact contact) {
            Log.d(DEBUG_TAG, "end colliding!");
            mIsColliding = false;
        }

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

        }

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

        }
    }
}

public class GMediaPlanet 
{
    protected IAreaShape mSprite = null;
    protected Body mBody = null;

    public GMediaPlanet()
    {   }

    public Vector2 GetLocation()
    {
        mBody.getPosition();
    }

}//end

public class GEnvironment 
{
    private PhysicsWorld mWorld;
    private Scene mScene;
    private org.andengine.engine.Engine mEngine;

    public GEnvironment(PhysicsWorld pWorld, Scene pScene, org.andengine.engine.Engine pEngine)
    {
        mWorld = pWorld;
        mScene = pScene;
        mEngine = pEngine;
    }

    /** the constructor is hidden, available within Appearances packet only */
    public GMediaPlanet CreatePlanet(float pX, float pY, ITextureRegion pTextureRegion, MyFixture pFixture) 
    {
        GMediaPlanet entity = new GMediaPlanet();
        entity.mSprite = new Sprite(pX, pY, pTextureRegion, mEngine.getVertexBufferObjectManager());
        entity.mBody = PhysicsFactory.createCircleBody(mWorld, entity.mSprite, BodyType.DynamicBody,
                pFixture.GetDef(), GlobalSettings.PIXEL_2_METER);

        mScene.attachChild(entity.mSprite);

        entity.mSprite.setUserData(entity.mBody);
        entity.mBody.setUserData(entity);

        mWorld.registerPhysicsConnector(new PhysicsConnector(entity.mSprite, entity.mBody, true, true));

        return entity;
    }

    // -----------------------------
    // Creating JOINTS
    // -----------------------------
    /**
     * Creating a force joit based on type of MouseJointDef
     * 
     * @param anchorObj
     *            the static object in the mTestJoint (anchor base)
     * @param movingObj
     *            object to move forward the target
     */
    public MouseJoint CreateForceJoint(GMediaPlanet anchorObj, GMediaPlanet movingObj)
    {
        ChangeFixture(movingObj, GlobalSettings.FIXTURE_VACUUM);

        MouseJointDef jointDef = new MouseJointDef();

        jointDef.dampingRatio = GlobalSettings.MOUSE_JOINT_DAMP;
        jointDef.frequencyHz = GlobalSettings.MOUSE_JOINT_FREQ;
        jointDef.collideConnected = true;

        Vector2 initPoint = Vector2Pool.obtain(movingObj.mBody.getPosition());
        jointDef.bodyA = anchorObj.mBody;
        jointDef.bodyB = movingObj.mBody;
        jointDef.maxForce = (GlobalSettings.MOUSE_JOINT_ACCELERATOR * movingObj.mBody.getMass());

        // very important!!!, the initial target must be position of the sattelite
        jointDef.target.set(initPoint);
        MouseJoint joint = (MouseJoint) mWorld.createJoint(jointDef);
        Vector2Pool.recycle(initPoint);

        // very important!!!, the target of the joint then changed to target anchor object
        Vector2 targetPoint = Vector2Pool.obtain(anchorObj.mBody.getWorldCenter());
        joint.setTarget(targetPoint);
        Vector2Pool.recycle(targetPoint);

        return joint;
    }

    public void ChangeFixture(GMediaPlanet entity, MyFixture pFixture)
    {
        Filter fil = new Filter();
        fil.categoryBits = pFixture.categoryBit;
        fil.maskBits = pFixture.maskBits;
        if(entity.mBody != null)
        {
            entity.mBody.getFixtureList().get(0).setFilterData(fil);            
        }
    }
}

回答1:


You can not modify the world in Step()-Call of Box2D because the World is locked! you should get an exception. You have to Remember which objects are colliding and do stuff after beginContact.. for example in an update function.



来源:https://stackoverflow.com/questions/13912254/box2d-andengine-app-hangs-out-when-creating-joints-during-contactlistener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!