简体   繁体   English

Andengine / Box2D平台的物理和重力

[英]Physics and gravity in Andengine/Box2D platformer

I'm putting together a 2D platformers using Andengine with the Box2D extension using the PhysicsJumpExample ( https://code.google.com/p/andengineexamples/source/browse/src/org/anddev/andengine/examples/PhysicsJumpExample.java ) as a base. 我正在使用Andengine和Box2D扩展使用PhysicsJumpExample( https://code.google.com/p/andengineexamples/source/browse/src/org/anddev/andengine/examples/PhysicsJumpExample.java )组合2D平台游戏。作为基础。 I'm also using the TMX extension for level loading. 我也使用TMX扩展来进行级别加载。

My level, player controls etc seem to be working OK but I'm really struggling with the Box2D physics in terms of gravity. 我的水平,玩家控制等似乎工作正常,但我真的在重力方面与Box2D物理学斗争。 The AnimatedSprite being controlled is being acted upon by gravity but the descent is sooo slow when using "Earth" gravity (~-9.8). 被控制的AnimatedSprite正在被重力作用,但是当使用“地球”引力(〜-9.8)时,下降速度太慢。 If I increase this gravity then the descent is quicker but then the Sprite bounces up and down on the solid "floor" and sideways movement is greatly reduced (due to friction I would assume). 如果我增加这个重力然后下降速度更快但是Sprite在坚固的“地板”上上下跳动并且侧向运动大大减少(由于我假设的摩擦)。

Finally, for some reason, every example I've looked at has used a positive value for gravity when instantiating the PhysicsWorld but I've had to reverse it in order to have gravity act "as normal". 最后,出于某种原因,我所看到的每个例子在实例化PhysicsWorld时都使用了重力的正值,但为了让重力“正常”,我不得不反转它。

Obviously I'm doing something very wrong and would greatly appreciate some pointers in getting this sorted out. 显然我正在做一些非常错误的事情,并且非常欣赏一些关于解决这个问题的建议。

Code for the 2 classes in question below. 下面有两个类的代码。

public class GameActivity extends SimpleBaseGameActivity {

private final static String TAG = "GameActivity";

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

private HUD _hud;
private Text _score;
private Text _debug;
private PhysicsWorld mPhysicsWorld;
private PhysicsHandler _playerPhysics;
private TMXTiledMap _map;
private PlayerSprite _player;
private BitmapTextureAtlas mOnScreenControlTexture;
private TextureRegion mOnScreenControlBaseTextureRegion;
private TextureRegion mOnScreenControlKnobTextureRegion;
private Scene mScene;
private Font mFont;

private ITexture mPlayerTexture;
private TiledTextureRegion mPlayerTextureRegion;

@Override
public EngineOptions onCreateEngineOptions() {
    final BoundCamera camera = new BoundCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
    EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
    engineOptions.getAudioOptions().setNeedsMusic(true).setNeedsSound(true);
    engineOptions.setWakeLockOptions(WakeLockOptions.SCREEN_ON);
    return engineOptions;
}

@Override
public void onCreateResources() throws IOException {
}

@Override
public Scene onCreateScene() {
    this.mEngine.registerUpdateHandler(new FPSLogger());
    this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, 0 - (SensorManager.GRAVITY_EARTH)), false);
    this.mScene = new Scene();
    this.mScene.getBackground().setColor(Color.BLACK);
    try {
        createFont();
        createWorld();
        createPlayer();
        createControllers();
        createHUD();
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }
    this.mScene.registerUpdateHandler(this.mPhysicsWorld);
    return mScene;
}

private void createFont() {
    FontFactory.setAssetBasePath("media/fonts/");
    final ITexture mainFontTexture = new BitmapTextureAtlas(getTextureManager(), 256, 256, TextureOptions.NEAREST);
    mFont = FontFactory.createStrokeFromAsset(getFontManager(), mainFontTexture, getAssets(), "game.otf", 40f, true, android.graphics.Color.WHITE, 2f,
        android.graphics.Color.BLACK);
    mFont.load();
}

private void createHUD() {
    Log.d(TAG, "createHud");
    _hud = new HUD();
    _score = new Text(mEngine.getCamera().getCameraSceneWidth() - 80, mEngine.getCamera().getCameraSceneHeight() - 20, mFont, "0123456789", new TextOptions(
        HorizontalAlign.RIGHT), getVertexBufferObjectManager());
    _score.setText("0000");
    _hud.attachChild(_score);
    _debug = new Text(150, mEngine.getCamera().getCameraSceneHeight() - 20, mFont, "abcdefghijklmnopqrstuvwxyz0123456789.,()[] ", new TextOptions(HorizontalAlign.LEFT),
        getVertexBufferObjectManager());
    _debug.setText("");
    _hud.attachChild(_debug);
    mEngine.getCamera().setHUD(_hud);
}

private void createPlayer() throws Exception {
    Log.d(TAG, "createPlayer");
    this.mPlayerTexture = new AssetBitmapTexture(getTextureManager(), getAssets(), "media/sprites/p1.png");
    this.mPlayerTextureRegion = TextureRegionFactory.extractTiledFromTexture(this.mPlayerTexture, 5, 2);
    this.mPlayerTexture.load();
    _player = new PlayerSprite(50, 320, this.mPlayerTextureRegion, mEngine.getCamera(), this.mPhysicsWorld, getVertexBufferObjectManager());
    _player.setUserData(_player.getBody());
    _playerPhysics = new PhysicsHandler(_player);
    this.mPhysicsWorld.setContactListener(new ContactListener() {

        @Override
        public void preSolve(Contact contact, Manifold oldManifold) {
            // TODO Auto-generated method stub

        }

        @Override
        public void postSolve(Contact contact, ContactImpulse impulse) {
            // TODO Auto-generated method stub

        }

        @Override
        public void endContact(Contact contact) {
            // TODO Auto-generated method stub

        }

        @Override
        public void beginContact(Contact contact) {
            if (contact == null || contact.getFixtureA() == null || contact.getFixtureB() == null)
                return;
            if (contact.getFixtureA().getBody().getUserData() == null || contact.getFixtureB().getBody().getUserData() == null)
                return;
            if (contact.getFixtureA().getBody().getUserData().toString().equals("player") || contact.getFixtureB().getBody().getUserData().toString().equals("player")) {
                _player.setJumping(false);
            }
        }
    });
    _player.registerUpdateHandler(_playerPhysics);
    this.mScene.attachChild(_player);
}

private void createControllers() {
    Log.d(TAG, "createControllers");
    BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("media/");
    mOnScreenControlTexture = new BitmapTextureAtlas(getTextureManager(), 256, 128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
    mOnScreenControlBaseTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mOnScreenControlTexture, this, "images/controller.png", 0, 0);
    mOnScreenControlKnobTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mOnScreenControlTexture, this, "images/controller_top.png", 128, 0);
    getTextureManager().loadTexture(mOnScreenControlTexture);
    final float x1 = mOnScreenControlBaseTextureRegion.getWidth();
    final float y1 = (this.mEngine.getCamera().getCameraSceneHeight() - mOnScreenControlBaseTextureRegion.getHeight());
    final DigitalOnScreenControl velocityOnScreenControl = new DigitalOnScreenControl(x1, y1, this.mEngine.getCamera(), this.mOnScreenControlBaseTextureRegion,
        this.mOnScreenControlKnobTextureRegion, 0.1f, true, getVertexBufferObjectManager(), new IOnScreenControlListener() {

            @Override
            public void onControlChange(BaseOnScreenControl pBaseOnScreenControl, float pValueX, float pValueY) {
                float x = 0, y = 0;
                if (pValueX == -1 && pValueY == 0) {
                    if (_player.getDirection() != PlayerDirection.LEFT) {
                        _player.setRotation(-1);
                        _player.animate(75);
                    }
                    x = pValueX * 8;
                    y = pValueY * 8;
                    _player.setDirection(PlayerDirection.LEFT);
                } else if (pValueX == -1 && pValueY == 1) {
                    if (!_player.isJumping()) {
                        if (_player.getDirection() != PlayerDirection.UP_LEFT) {
                            _player.animate(25);
                        }
                        x = SensorManager.GRAVITY_EARTH * -10;
                        y = SensorManager.GRAVITY_EARTH * -10;
                        _player.setDirection(PlayerDirection.UP_LEFT);
                    }
                } else if (pValueX == 0 && pValueY == 1) {
                    if (!_player.isJumping()) {
                        if (_player.getDirection() != PlayerDirection.UP) {
                            _player.animate(75);
                        }
                        y = SensorManager.GRAVITY_EARTH * 2;
                        _player.setDirection(PlayerDirection.UP);
                    }
                } else if (pValueX == 1 && pValueY == 1) {
                    if (!_player.isJumping()) {
                        if (_player.getDirection() != PlayerDirection.UP_RIGHT) {
                            _player.animate(25);
                        }
                        x = SensorManager.GRAVITY_EARTH * 10;
                        y = SensorManager.GRAVITY_EARTH * -10;
                        _player.setDirection(PlayerDirection.UP_RIGHT);
                    }
                } else if (pValueX == 1 && pValueY == 0) {
                    if (_player.getDirection() != PlayerDirection.RIGHT) {
                        _player.animate(75);
                    }
                    x = pValueX * 8;
                    y = pValueY * 8;
                    _player.setDirection(PlayerDirection.RIGHT);
                } else if (pValueX == 1 && pValueY == -1) {
                    _player.setDirection(PlayerDirection.DOWN_RIGHT);
                } else if (pValueX == 0 && pValueY == 1) {
                    _player.setDirection(PlayerDirection.DOWN);
                } else if (pValueX == -1 && pValueY == -1) {
                    _player.setDirection(PlayerDirection.DOWN_LEFT);
                } else {
                    _player.setDirection(PlayerDirection.NONE);
                    if (!_player.isJumping()) {
                        _player.stopAnimation(0);
                    }
                }
                final Vector2 velocity = Vector2Pool.obtain(x, y);
                _player.getBody().setLinearVelocity(velocity);
                Vector2Pool.recycle(velocity);
                _debug.setText(_player.getDirection().toString() + ": " + (pValueX * 60) + "," + (pValueY * 60));
            }
        });
    velocityOnScreenControl.getControlBase().setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    velocityOnScreenControl.getControlBase().setAlpha(0.5f);

    this.mScene.setChildScene(velocityOnScreenControl);
}

private void createWorld() {
    Log.d(TAG, "createWorld");
    try {
        final TMXLoader tmxLoader = new TMXLoader(getAssets(), getTextureManager(), TextureOptions.NEAREST, getVertexBufferObjectManager());
        _map = tmxLoader.loadFromAsset("media/levels/1/1.tmx");
        final TMXLayer tmxLayer = _map.getTMXLayers().get(0);
        tmxLayer.detachSelf();
        this.mScene.attachChild(tmxLayer);
        ((BoundCamera) this.mEngine.getCamera()).setBounds(0, 0, tmxLayer.getHeight(), tmxLayer.getWidth());
        ((BoundCamera) this.mEngine.getCamera()).setBoundsEnabled(true);

        float height = tmxLayer.getHeight();
        float width = tmxLayer.getWidth();

        final IShape bottom = new Rectangle(0, height - 2, width, 2, getVertexBufferObjectManager());
        bottom.setVisible(false);
        final IShape top = new Rectangle(0, 0, width, 2, getVertexBufferObjectManager());
        top.setVisible(false);
        final IShape left = new Rectangle(0, 0, 2, height, getVertexBufferObjectManager());
        left.setVisible(false);
        final IShape right = new Rectangle(width - 2, 0, 2, height, getVertexBufferObjectManager());
        right.setVisible(false);

        final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 1f);
        PhysicsFactory.createBoxBody(this.mPhysicsWorld, bottom, BodyType.StaticBody, wallFixtureDef);
        PhysicsFactory.createBoxBody(this.mPhysicsWorld, top, BodyType.StaticBody, wallFixtureDef);
        PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
        PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);

        this.mScene.attachChild(bottom);
        this.mScene.attachChild(top);
        this.mScene.attachChild(left);
        this.mScene.attachChild(right);

        float yOffset = _map.getTMXLayers().get(0).getHeight();
        for (final TMXObjectGroup group : _map.getTMXObjectGroups()) {
            if (group.getTMXObjectGroupProperties().containsTMXProperty("solid", "true")) {
                for (final TMXObject object : group.getTMXObjects()) {
                    final Rectangle rect = new Rectangle(object.getX() + object.getWidth() / 2, yOffset - object.getY() - object.getHeight() / 2, object.getWidth(),
                        object.getHeight(), getVertexBufferObjectManager());
                    final FixtureDef boxFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 1f);
                    Body b = PhysicsFactory.createBoxBody(this.mPhysicsWorld, rect, BodyType.StaticBody, boxFixtureDef);
                    b.setUserData("solid");
                    rect.setVisible(false);
                    rect.setZIndex(0);
                    this.mScene.attachChild(rect);
                }
            }
        }
    } catch (final TMXLoadException e) {
        Log.e(TAG, e.getMessage());
    }
}

@Override
public void onDestroyResources() throws IOException {
    Log.d(TAG, "onDestroyResources: Cleanup scenes/resources");
    super.onDestroyResources();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    System.exit(0);
}

} }

public class PlayerSprite extends AnimatedSprite {

public enum PlayerDirection {
    NONE, LEFT, UP_LEFT, UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT
}

private Body _body;
private PlayerDirection _direction = PlayerDirection.NONE;
private boolean _jumping = false;

public PlayerSprite(float pX, float pY, ITiledTextureRegion region, Camera camera, PhysicsWorld physics, VertexBufferObjectManager vbo) {
    super(pX, pY, region, vbo);
    createPhysics(camera, physics);
    camera.setChaseEntity(this);
}

public Body getBody() {
    return _body;
}

public PlayerDirection getDirection() {
    return _direction;
}

public void setDirection(PlayerDirection direction) {
    _direction = direction;
}

public boolean isJumping() {
    return _jumping;
}

public void setJumping(boolean jumping) {
    _jumping = jumping;
}

private void createPhysics(final Camera camera, PhysicsWorld physics) {
    _body = PhysicsFactory.createBoxBody(physics, this, BodyType.DynamicBody, PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f));
    _body.setUserData("player");
    physics.registerPhysicsConnector(new PhysicsConnector(this, _body, true, true));
}

} }

So as is always the case simply posting and asking for help has miraculously resulted in self resolution. 因此,只是发布和寻求帮助的情况总是奇迹般地导致自我解决。

For anybody else who encounters something similar (though I doubt anyone could be so silly!) the problem was that the "controller" was enacting forces upon the player (left, right, jump etc) but the OnControlChange event of IOnScreenControlListener gets called constantly and I had "_player.getBody().setLinearVelocity(velocity);" 对于遇到类似事情的其他人(虽然我怀疑任何人都可能如此愚蠢!)问题是“控制器”正在对玩家施加力量(左,右,跳等)但是IOnScreenControlListener的OnControlChange事件会被不断调用我有“_player.getBody()。setLinearVelocity(velocity);” (with the velocity being a default 0, 0) called repeatedly thereby negating some of the gravitational force. (速度为默认值0,0)反复调用,从而抵消了一些重力。

Doh! 卫生署!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM