Box2D AndEngine:应用程序在ContactListener期间创建关节时挂起



我在AndEngine中使用Box2D(适用于Android)。

我的目的是在 2 个物体相互碰撞时创建一个力关节。

当我尝试在此过程中在 2 个对象(实体)之间创建鼠标关节 ContactListner时。应用程序将挂起一段时间,然后退出,没有任何错误,只是线程结束的通知。

当我在 ContactListener 之外调用mEnvironment.CreateForceJoint(..)时,联合创建是可以的 - 当应用程序在某些物理环境中运行时的某个地方。UpdateHandler()。

请帮我解决问题,或者找出原因。感谢您的任何帮助!

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);            
        }
    }
}

你不能在Box2D的Step()-调用中修改世界,因为世界是锁定的! 你应该得到一个例外。你必须记住哪些物体正在碰撞,并在开始接触后做一些事情。例如,在更新函数中。

最新更新