java - Box2D 和引擎 : app hangs out when creating Joints during ContactListener?

标签 java android box2d andengine game-engine

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

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

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

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

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

这是我的代码:

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()-Call 中修改世界,因为世界已被锁定!你应该得到一个异常(exception)。您必须记住哪些对象正在发生碰撞并在 beginContact 之后执行操作......例如在更新函数中。

关于java - Box2D 和引擎 : app hangs out when creating Joints during ContactListener?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13912254/

相关文章:

android - 如何监控每个 Activity 的 Android 应用程序的电池使用情况?

java - 为什么 createKeyFromXml() 不创建语言切换键?

javascript - Box2dWeb 动态与静态物体恢复

java - Box2D静态体碰撞性能问题

java - 在 NetSuite Suitescript 中加密并在 java 应用程序中解密

java - 检测 Kafka 集群已关闭的最佳方法是什么?

android - 如何通过抽屉导航导航到不同的 Activity

java - 如何将动画应用到 box2d 主体?

java - 应用程序在执行 AsyncTask 后不显示任何内容

java - 如何有效地管理一堆 jar 文件及其管道?