2012-12-17 2 views
2

AndEngine (Android 용)에 Box2D을 사용하고 있습니다.Box2D AndEngine : ContactListener 중에 접합을 만들 때 앱이 멈 춥니 다?

내 목적은 2 개의 개체가 서로 충돌 할 때마다 강제 연결을 만드는 것입니다.

내가 ContactListner 과정에서 마우스 공동 2 사이의 객체 (몸을) 만들려고. 응용 프로그램은 잠시 멈추고 아무런 오류없이 끝나는 스레드의 알림 만 종료합니다. 응용 프로그램은 일부 physics.UpdateHandler에서 실행되는 곳 동안() -

공동 작성 내가 ContactListener 외부 mEnvironment.CreateForceJoint(..)를 호출 할 때 OK입니다.

문제를 해결하거나 이유를 찾도록 도와주십시오. 어떤 도움을 주셔서 감사합니다!

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

답변

2

당신은 단계에서 세계를 수정할 수 없습니다() - Box2D의 콜을 세계가 잠겨 있기 때문에! 당신은 예외를 받아야합니다. 어떤 객체가 충돌 하는지를 기억하고 beginContact 후에 물건을해야합니다. 예를 들어 업데이트 기능에서.

+0

설명이 너무 일반적이어서 '수정'요청이 표시되지 않습니다. 나는 아직도 너의 생각을 잡을 수 없다. Step2) Call of Box2D를 어디서 수정 했습니까? 세상은 무엇을 잠근거야? –

+2

아아아, 나는 당신의 아이디어를 잡을 수있다. 즉, 'ContactListener'에서 충돌 객체 *에 대한 포인터를 저장하고, 다른'Update'에서 그 객체에 의해 발생한 월드로의 변경을 처리한다. 더 명확한 것은 여기에 있습니다 : http://www.neilson.co.za/?p=168 –

+2

그리고 여기에서 ContactListener에 대한 자세한 내용을 볼 수 있습니다 : http://blog.sethladd.com/2011/09/box2d- collision-damage-for-javascript.html –

관련 문제