2

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

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

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

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

请帮我解决问题,或找出原因。谢谢你的帮助!

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

1 回答 1

2

你不能在 Box2D 的 Step()-Call 中修改世界,因为世界被锁定了!你应该得到一个例外。您必须记住在 beginContact.. 之后哪些对象正在发生碰撞并执行某些操作,例如在更新函数中。

于 2012-12-17T10:50:33.783 回答