牛顿在andengine上的摇篮,box2d

时间:2013-06-23 18:05:18

标签: android box2d andengine

我正在努力创造像牛顿摇篮一样的东西。但当一个球击中另一个球时,所有球同时向同一方向移动。我该如何判断这个问题?我应该在createFixtureDef中创建另一个球的物理选项吗?或者我需要使用一些特定的算法来在球之间传递脉冲?

public class MainActivity extends SimpleBaseGameActivity implements IAccelerationListener, IOnAreaTouchListener
{

private static final int CAMERA_WIDTH = 720;
private static final int CAMERA_HEIGHT = 480;
private BitmapTextureAtlas mBitmapTextureAtlas;

final String TAG = "States";
private Scene mScene;

protected ITiledTextureRegion mBoxFaceTextureRegion;
protected ITiledTextureRegion mCircleFaceTextureRegion;

protected PhysicsWorld mPhysicsWorld;
@Override
public EngineOptions onCreateEngineOptions() {
    final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);

    return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, 
            new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
}

@Override
protected void onCreateResources() {
    BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");

    this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 64, 64, TextureOptions.BILINEAR);
    this.mBoxFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_box_tiled.png", 0, 0, 2, 1); // 64x32
    this.mCircleFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_circle_tiled.png", 0, 32, 2, 1); // 64x32
    this.mBitmapTextureAtlas.load();

}

@Override
protected Scene onCreateScene() {
    this.mEngine.registerUpdateHandler(new FPSLogger());

    this.mScene = new Scene();
    this.mScene.setBackground(new Background(0, 0, 0));
    //this.mScene.setOnSceneTouchListener(this);

    this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);



    this.initJoints(mScene);


    this.mScene.registerUpdateHandler(this.mPhysicsWorld);
    this.mScene.setOnAreaTouchListener(this);

    return this.mScene;
}

private void initJoints(final Scene pScene) {
    final float centerY = CAMERA_HEIGHT / 2;

    final float spriteWidth = this.mBoxFaceTextureRegion.getWidth();
    final float spriteHeight = this.mBoxFaceTextureRegion.getHeight();

    final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(30, 0.2f, 0.2f);

    for(int i = 0; i < 10; i++) {
        final float anchorFaceX =  100 + i * spriteWidth ;
        final float anchorFaceY = centerY;

        final AnimatedSprite anchorFace = new AnimatedSprite(anchorFaceX, anchorFaceY, 
                this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager());
        final Body anchorBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld, 
                anchorFace, BodyType.StaticBody, 
                objectFixtureDef);

        final AnimatedSprite movingFace = new AnimatedSprite(anchorFaceX, anchorFaceY + 150, 
                this.mCircleFaceTextureRegion, this.getVertexBufferObjectManager()) ;
//      movingFace.setScale(1.2f);
        final Body movingBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, 
                        movingFace, BodyType.DynamicBody, objectFixtureDef);
        movingFace.setUserData(movingBody);

//      anchorFace.setScale(1.2f);
        anchorFace.animate(200);
        anchorFace.animate(200);
        final Line connectionLine = new Line(anchorFaceX + spriteWidth / 2,
                                    anchorFaceY + spriteHeight / 2,
                                    anchorFaceX + spriteWidth / 2, 
                                    anchorFaceY + spriteHeight / 2, 
                                    this.getVertexBufferObjectManager());

        pScene.registerTouchArea(movingFace);
        pScene.attachChild(connectionLine);
        pScene.attachChild(anchorFace);
        pScene.attachChild(movingFace);

        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(anchorFace, 
                anchorBody, true, true){
            @Override
            public void onUpdate(final float pSecondsElapsed) {
                super.onUpdate(pSecondsElapsed);
                final Vector2 movingBodyWorldCenter = movingBody.getWorldCenter();
                connectionLine.setPosition(connectionLine.getX1(), connectionLine.getY1(), 
                        movingBodyWorldCenter.x * PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, 
                        movingBodyWorldCenter.y * PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT);
            }
        });

        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(movingFace, movingBody, true, true));
        final RevoluteJointDef revoluteJointDef = new RevoluteJointDef();
        revoluteJointDef.initialize(anchorBody, movingBody, anchorBody.getWorldCenter());
        this.mPhysicsWorld.createJoint(revoluteJointDef);
    }
}
@Override
public void onAccelerationAccuracyChanged(final AccelerationData pAccelerationData) {
}
@Override
public void onAccelerationChanged(final AccelerationData pAccelerationData) {
    final Vector2 gravity = Vector2Pool.obtain(pAccelerationData.getX(), pAccelerationData.getY());
    this.mPhysicsWorld.setGravity(gravity);
    Vector2Pool.recycle(gravity);
}


public boolean onAreaTouched( final TouchEvent pSceneTouchEvent, 
        final ITouchArea pTouchArea,final float pTouchAreaLocalX,
        final float pTouchAreaLocalY) {

    if(pSceneTouchEvent.isActionMove())
    {
        float touchX = pSceneTouchEvent.getX();
        float touchY = pSceneTouchEvent.getY();
        Log.d(TAG, "move to in X" +touchX + "n Y " +touchY);
        final AnimatedSprite anchorFace = (AnimatedSprite) pTouchArea;
        final Body tochedBody = (Body)anchorFace.getUserData();
         //move sprite to xy
        final float x = pSceneTouchEvent.getX();
        final float y = pSceneTouchEvent.getY();
        final float widthD2 = anchorFace.getWidth() / 2;
        final float heightD2 = anchorFace.getHeight() / 2;
        final float angle = tochedBody.getAngle(); // keeps the body angle
        final Vector2 v2 = Vector2Pool.obtain((x + widthD2) / 32, (y + heightD2) / 32);         
       tochedBody.setTransform(v2, angle);
        Vector2Pool.recycle(v2);
        return true;        
    }
    return false;
}

private static final int CAMERA_WIDTH = 720; private static final int CAMERA_HEIGHT = 480; private BitmapTextureAtlas mBitmapTextureAtlas; final String TAG = "States"; private Scene mScene; protected ITiledTextureRegion mBoxFaceTextureRegion; protected ITiledTextureRegion mCircleFaceTextureRegion; protected PhysicsWorld mPhysicsWorld; @Override public EngineOptions onCreateEngineOptions() { final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT); return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera); } @Override protected void onCreateResources() { BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/"); this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 64, 64, TextureOptions.BILINEAR); this.mBoxFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_box_tiled.png", 0, 0, 2, 1); // 64x32 this.mCircleFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_circle_tiled.png", 0, 32, 2, 1); // 64x32 this.mBitmapTextureAtlas.load(); } @Override protected Scene onCreateScene() { this.mEngine.registerUpdateHandler(new FPSLogger()); this.mScene = new Scene(); this.mScene.setBackground(new Background(0, 0, 0)); //this.mScene.setOnSceneTouchListener(this); this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false); this.initJoints(mScene); this.mScene.registerUpdateHandler(this.mPhysicsWorld); this.mScene.setOnAreaTouchListener(this); return this.mScene; } private void initJoints(final Scene pScene) { final float centerY = CAMERA_HEIGHT / 2; final float spriteWidth = this.mBoxFaceTextureRegion.getWidth(); final float spriteHeight = this.mBoxFaceTextureRegion.getHeight(); final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(30, 0.2f, 0.2f); for(int i = 0; i < 10; i++) { final float anchorFaceX = 100 + i * spriteWidth ; final float anchorFaceY = centerY; final AnimatedSprite anchorFace = new AnimatedSprite(anchorFaceX, anchorFaceY, this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager()); final Body anchorBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld, anchorFace, BodyType.StaticBody, objectFixtureDef); final AnimatedSprite movingFace = new AnimatedSprite(anchorFaceX, anchorFaceY + 150, this.mCircleFaceTextureRegion, this.getVertexBufferObjectManager()) ; // movingFace.setScale(1.2f); final Body movingBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, movingFace, BodyType.DynamicBody, objectFixtureDef); movingFace.setUserData(movingBody); // anchorFace.setScale(1.2f); anchorFace.animate(200); anchorFace.animate(200); final Line connectionLine = new Line(anchorFaceX + spriteWidth / 2, anchorFaceY + spriteHeight / 2, anchorFaceX + spriteWidth / 2, anchorFaceY + spriteHeight / 2, this.getVertexBufferObjectManager()); pScene.registerTouchArea(movingFace); pScene.attachChild(connectionLine); pScene.attachChild(anchorFace); pScene.attachChild(movingFace); this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(anchorFace, anchorBody, true, true){ @Override public void onUpdate(final float pSecondsElapsed) { super.onUpdate(pSecondsElapsed); final Vector2 movingBodyWorldCenter = movingBody.getWorldCenter(); connectionLine.setPosition(connectionLine.getX1(), connectionLine.getY1(), movingBodyWorldCenter.x * PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, movingBodyWorldCenter.y * PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT); } }); this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(movingFace, movingBody, true, true)); final RevoluteJointDef revoluteJointDef = new RevoluteJointDef(); revoluteJointDef.initialize(anchorBody, movingBody, anchorBody.getWorldCenter()); this.mPhysicsWorld.createJoint(revoluteJointDef); } } @Override public void onAccelerationAccuracyChanged(final AccelerationData pAccelerationData) { } @Override public void onAccelerationChanged(final AccelerationData pAccelerationData) { final Vector2 gravity = Vector2Pool.obtain(pAccelerationData.getX(), pAccelerationData.getY()); this.mPhysicsWorld.setGravity(gravity); Vector2Pool.recycle(gravity); } public boolean onAreaTouched( final TouchEvent pSceneTouchEvent, final ITouchArea pTouchArea,final float pTouchAreaLocalX, final float pTouchAreaLocalY) { if(pSceneTouchEvent.isActionMove()) { float touchX = pSceneTouchEvent.getX(); float touchY = pSceneTouchEvent.getY(); Log.d(TAG, "move to in X" +touchX + "n Y " +touchY); final AnimatedSprite anchorFace = (AnimatedSprite) pTouchArea; final Body tochedBody = (Body)anchorFace.getUserData(); //move sprite to xy final float x = pSceneTouchEvent.getX(); final float y = pSceneTouchEvent.getY(); final float widthD2 = anchorFace.getWidth() / 2; final float heightD2 = anchorFace.getHeight() / 2; final float angle = tochedBody.getAngle(); // keeps the body angle final Vector2 v2 = Vector2Pool.obtain((x + widthD2) / 32, (y + heightD2) / 32); tochedBody.setTransform(v2, angle); Vector2Pool.recycle(v2); return true; } return false; }

1 个答案:

答案 0 :(得分:1)

不幸的是Box2D并不适合这个。

根据我的经验,只要球没有相互接触就可以开始工作一到两次。也就是说,每个球开始时它与每侧的邻居之间的间隙非常小。这意味着当它们发生碰撞时,每次只用两个球就可以解决碰撞问题,总共有4次单独的碰撞让冲击力传递到另一侧(对于5个球),而不是将所有5个球作为单个球解决岛”。

麻烦的是,定位需要非常精确,并且经过几次摆动之后球会偏离它,这样你最终会同时发生涉及两个以上球的碰撞。我只看到最多2-3次摆动按需要工作......