AndEngine physics - 我的角色在移动时摇晃

时间:2012-08-26 19:20:23

标签: box2d sprite andengine physics

AndEngine的物理问题。我的精灵在移动时摇晃,有时会跳跃。我制作了32x32盒子的“地板”,每个人都是另一个身体,所以我认为这是问题(与角落或某些东西发生碰撞)。我试图使用一个形状而不是那些盒子,但问题仍然存在。

看起来我的地板的表面不直,但不规律......

我的问题是,如何让我的角色在这个表面上顺利移动?

顺便说一下,如何让我的角色更重?

我的整个代码在这里:

private final int CAMERA_WIDTH = 800;
private final int CAMERA_HEIGHT = 480;

enum PlayerAction {
    RUN,
    NONE,
    JUMP
}

enum Direction {
    RIGHT,
    LEFT,
    NONE
}

enum BodyId {
    PLAYER,
    BOX
}

Direction mPlayerDirection = Direction.NONE;
Direction mLastPlayerDirection = Direction.NONE;

private Camera mCamera;
private Scene mGameScene;

private PhysicsWorld mPhysicsWorld;

private BitmapTextureAtlas mBoxBitmapTextureAtlas;
private BitmapTextureAtlas mPlayerBitmapTextureAtlas;
private ITextureRegion mBoxTextureRegion;
private TiledTextureRegion mPlayerTextureRegion;

private AnimatedSprite mPlayer;
private Body mPlayerBody;

private BitmapTextureAtlas mOnScreenControlTexture;
private ITextureRegion mOnScreenControlBaseTextureRegion;
private ITextureRegion mOnScreenControlKnobTextureRegion;

private AnalogOnScreenControl mAnalogOnScreenControl;

@Override
public EngineOptions onCreateEngineOptions() {

    this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
    EngineOptions mEngineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), this.mCamera);
    mEngineOptions.getTouchOptions().setNeedsMultiTouch(true);

    return mEngineOptions;
}
@Override
public void onCreateResources(
        OnCreateResourcesCallback pOnCreateResourcesCallback)
        throws Exception {

    BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
    this.mBoxBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 32, 32, TextureOptions.BILINEAR);
    this.mBoxTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBoxBitmapTextureAtlas, this, "box.png", 0, 0);
    this.mBoxBitmapTextureAtlas.load();

    this.mPlayerBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 256, 128, TextureOptions.BILINEAR);
    this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mPlayerBitmapTextureAtlas, this, "player.png", 0, 0, 3, 4);
    this.mPlayerBitmapTextureAtlas.load();

    this.mOnScreenControlTexture = new BitmapTextureAtlas(this.getTextureManager(), 256, 128, TextureOptions.BILINEAR);
    this.mOnScreenControlBaseTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mOnScreenControlTexture, this, "onscreen_control_base.png", 0, 0);
    this.mOnScreenControlKnobTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mOnScreenControlTexture, this, "onscreen_control_knob.png", 128, 0);
    this.mOnScreenControlTexture.load();

    pOnCreateResourcesCallback.onCreateResourcesFinished();
}
@Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
        throws Exception {

    this.mGameScene = new Scene();

    initPhysics(this.mGameScene);

    for(int i = 0; i <= 50; i++) {
        Sprite sprite = new Sprite(i*32, this.mCamera.getHeight() - this.mBoxTextureRegion.getHeight(), this.mBoxTextureRegion, this.getVertexBufferObjectManager());
        createBody(sprite, BodyType.StaticBody, 1, 0, 0, BodyId.BOX);
        this.mGameScene.attachChild(sprite);
    }

    /* Calculate the coordinates for the face, so its centered on the camera. */
    final float playerX = (CAMERA_WIDTH - this.mPlayerTextureRegion.getWidth()) / 2;
    final float playerY = CAMERA_HEIGHT - this.mPlayerTextureRegion.getHeight() - 128;

    this.mPlayer = new AnimatedSprite(playerX, playerY, this.mPlayerTextureRegion, this.getVertexBufferObjectManager()) {

        @Override
        protected void onManagedUpdate(float pSecondsElapsed) {
            super.onManagedUpdate(pSecondsElapsed);
            switch (mPlayerDirection) {
            case RIGHT:
                if (!mPlayerDirection.equals(mLastPlayerDirection)) {
                    mLastPlayerDirection = Direction.RIGHT;
                    GameActivity.this.mPlayer.animate(new long[]{200, 200, 200}, 3, 5, true);
                }
                break;
            case LEFT:
                if (!mPlayerDirection.equals(mLastPlayerDirection)) {
                    mLastPlayerDirection = Direction.LEFT;
                    GameActivity.this.mPlayer.animate(new long[]{200, 200, 200}, 9, 11, true);
                }
                break;
            case NONE:
                mLastPlayerDirection = Direction.NONE;
                GameActivity.this.mPlayer.setCurrentTileIndex(6);
                GameActivity.this.mPlayer.stopAnimation();
                break;
            default:
                mLastPlayerDirection = Direction.NONE;
                GameActivity.this.mPlayer.setCurrentTileIndex(6);
                GameActivity.this.mPlayer.stopAnimation();
                break;
            }
        }
    };

    this.mPlayer.setScaleCenterY(this.mPlayerTextureRegion.getHeight());
    this.mPlayer.setScale(2);
    this.mGameScene.attachChild(this.mPlayer);

    this.mCamera.setChaseEntity(mPlayer);

    this.mPlayerBody = createMovingBody(this.mPlayer, BodyType.DynamicBody, 1, 0, 0, BodyId.PLAYER);

    this.mAnalogOnScreenControl = new AnalogOnScreenControl(32, CAMERA_HEIGHT - this.mOnScreenControlBaseTextureRegion.getHeight() - 32, this.mCamera, this.mOnScreenControlBaseTextureRegion, this.mOnScreenControlKnobTextureRegion, 0.1f, 200, this.getVertexBufferObjectManager(), new IAnalogOnScreenControlListener() {
        @Override
        public void onControlChange(final BaseOnScreenControl pBaseOnScreenControl, final float pValueX, final float pValueY) {

            GameActivity.this.mPlayerBody.setLinearVelocity(new Vector2(pValueX*10, GameActivity.this.mPlayerBody.getLinearVelocity().y));

            if (pValueX > 0)
                GameActivity.this.mPlayerDirection = Direction.RIGHT;
            else if (pValueX < 0)
                GameActivity.this.mPlayerDirection = Direction.LEFT;
            else
                GameActivity.this.mPlayerDirection = Direction.NONE;
        }

        @Override
        public void onControlClick(
                AnalogOnScreenControl pAnalogOnScreenControl) {
            GameActivity.this.mPlayerBody.setLinearVelocity(new Vector2(GameActivity.this.mPlayerBody.getLinearVelocity().x, -8.0f));
        }
    });

    this.mAnalogOnScreenControl.getControlBase().setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    this.mAnalogOnScreenControl.getControlBase().setAlpha(0.2f);
    this.mAnalogOnScreenControl.getControlBase().setScaleCenter(0, 128);
    this.mAnalogOnScreenControl.getControlBase().setScale(1.25f);
    this.mAnalogOnScreenControl.getControlKnob().setScale(1.25f);
    this.mAnalogOnScreenControl.refreshControlKnobPosition();

    this.mGameScene.setChildScene(this.mAnalogOnScreenControl);

    pOnCreateSceneCallback.onCreateSceneFinished(this.mGameScene);
}
@Override
public void onPopulateScene(Scene pScene,
        OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {

    this.mEngine.registerUpdateHandler(new TimerHandler(3f, true, new ITimerCallback() {
        @Override
        public void onTimePassed(TimerHandler pTimerHandler) {
            // TODO Auto-generated method stub

        }

    }));

    pOnPopulateSceneCallback.onPopulateSceneFinished();
}

private void initPhysics(Scene pScene)
{
    mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
    pScene.registerUpdateHandler(mPhysicsWorld);
}

private Body createBody(Sprite pSprite, BodyType pBodyType, float pDensity, float pElasticity, float pFriction, BodyId pBodyId)
{
    final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(pDensity, pElasticity, pFriction);
    Body body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, pSprite, pBodyType, objectFixtureDef);
    body.setUserData(pBodyId);
    return body;
}

private Body createMovingBody(Sprite pSprite, BodyType pBodyType, float pDensity, float pElasticity, float pFriction, BodyId pBodyId) {
    Body body = createBody(pSprite, pBodyType, pDensity, pElasticity, pFriction, pBodyId);
    mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(pSprite, body, true, false));
    return body;
}

2 个答案:

答案 0 :(得分:2)

我认为这可能是因为CPU速度不足造成的。当处理器无法满足Box2D的要求时,仿真就会受到影响。这些物体可以稍微落入地板所占据的空间中,并在下一个模拟周期中向上推动。当某些后台应用程序导致CPU负载激增时,也会发生这种情况。

尝试在速度更快的手机上运行应用程序,或者在后台运行其他应用程序时运行我使用伟大的MaxStepPhysicsWorld解决了类似的问题,可以在这里找到:http://www.andengine.org/forums/features/max-step-physics-to-avoid-choppyness-and-bad-simulation-t1271.html

它的工作方式是,当引擎无法每秒执行足够的模拟步骤时,MaxStepPhysicsWorld会放弃实时,而是每“秒”执行足够的模拟步骤,从而确保良好的模拟。

答案 1 :(得分:2)

好的,我已经解决了!

如果有人有兴趣: 我使用here的功能,因为我想检查我的身体从哪一侧与其他人发生碰撞。我改变了这个功能供我使用,所以:

  1. 我修改了它的shrinkToFactor值用法,因此它实际上并没有改变所有三角形的大小,而是在角落之间留出空间,所以如果你触地,你不会碰撞3个三角形,但是只是其中一个。 (但这是另一个故事,也许有人需要它或者会发现它有用)
  2. 我略微'切割'了底部夹具的边缘,所以它在边缘上滑动而不是被它们挡住,这是我的底部夹具矢量定义:

        final Vector2[] vertices2 = { // DOWN
                new Vector2((wd2 - shrinkToFactor - 1) / P2M, (hd2 - 1) / P2M),
                new Vector2((wd2 - shrinkToFactor) / P2M, hd2 / P2M),
                new Vector2((-wd2 + shrinkToFactor) / P2M, hd2 / P2M),
                new Vector2((-wd2 + shrinkToFactor + 1) / P2M, (hd2 - 1) / P2M),
                new Vector2(0 / P2M, 0 / P2M)
        };
    
  3. 这是我的全部功能。

        public static Body createPlayerBody(final MaxStepPhysicsWorld pPhysicsWorld, final Sprite pSprite, final FixtureDef pFixtureDef, final float pPixelToMeterRatio, final BodyType bodyType, final float shrinkToFactor) {
            final BodyDef bodyDef = new BodyDef();
            bodyDef.type = bodyType;
            final float P2M = pPixelToMeterRatio;
    
            final float[] sceneCenterCoordinates = pSprite.getSceneCenterCoordinates();
            bodyDef.position.x = sceneCenterCoordinates[Constants.VERTEX_INDEX_X] / P2M;
            bodyDef.position.y = sceneCenterCoordinates[Constants.VERTEX_INDEX_Y] / P2M;
    
            final Body boxBody = pPhysicsWorld.createBody(bodyDef);
    
            final float wd2 = (pSprite.getWidth() / 2);
            final float hd2 = (pSprite.getHeight() / 2);
    
            final Vector2[] vertices1 = { // RIGHT
                    new Vector2(wd2 / P2M, (hd2 - shrinkToFactor) / P2M),
                    new Vector2(0 / P2M, 0 / P2M),
                    new Vector2(wd2 / P2M, (-hd2 + shrinkToFactor) / P2M)
            };
            final Vector2[] vertices2 = { // DOWN
                    new Vector2((wd2 - shrinkToFactor - 1) / P2M, (hd2 - 1) / P2M),
                    new Vector2((wd2 - shrinkToFactor) / P2M, hd2 / P2M),
                    new Vector2((-wd2 + shrinkToFactor) / P2M, hd2 / P2M),
                    new Vector2((-wd2 + shrinkToFactor + 1) / P2M, (hd2 - 1) / P2M),
                    new Vector2(0 / P2M, 0 / P2M)
            };
            final Vector2[] vertices3 = { // LEFT
                    new Vector2(-wd2 / P2M, (hd2 - shrinkToFactor) / P2M),
                    new Vector2(-wd2 / P2M, (-hd2 + shrinkToFactor) / P2M),
                    new Vector2(0 / P2M, 0 / P2M)
            };
            final Vector2[] vertices4 = { // UP
                    new Vector2((-wd2 + shrinkToFactor) / P2M, -hd2 / P2M),
                    new Vector2((wd2 - shrinkToFactor) / P2M, -hd2 / P2M),
                    new Vector2(0 / P2M, 0 / P2M)
            };
    
            PolygonShape poly = new PolygonShape();
            pFixtureDef.shape = poly;
            poly.set(vertices1);
            final Fixture f1 = boxBody.createFixture(pFixtureDef);
            f1.setUserData(BodyId.PLAYER);
            poly.set(vertices2);
            final Fixture f2 = boxBody.createFixture(pFixtureDef);
            f2.setUserData(BodyId.PLAYER_FOOT);
            poly.set(vertices3);
            final Fixture f3 = boxBody.createFixture(pFixtureDef);
            f3.setUserData(BodyId.PLAYER);
            poly.set(vertices4);
            final Fixture f4 = boxBody.createFixture(pFixtureDef);
            f4.setUserData(BodyId.PLAYER_HEAD);
            poly.dispose();
    
            return boxBody;
    }