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