簡體   English   中英

Andengine / Box2D平台的物理和重力

[英]Physics and gravity in Andengine/Box2D platformer

我正在使用Andengine和Box2D擴展使用PhysicsJumpExample( https://code.google.com/p/andengineexamples/source/browse/src/org/anddev/andengine/examples/PhysicsJumpExample.java )組合2D平台游戲。作為基礎。 我也使用TMX擴展來進行級別加載。

我的水平,玩家控制等似乎工作正常,但我真的在重力方面與Box2D物理學斗爭。 被控制的AnimatedSprite正在被重力作用,但是當使用“地球”引力(〜-9.8)時,下降速度太慢。 如果我增加這個重力然后下降速度更快但是Sprite在堅固的“地板”上上下跳動並且側向運動大大減少(由於我假設的摩擦)。

最后,出於某種原因,我所看到的每個例子在實例化PhysicsWorld時都使用了重力的正值,但為了讓重力“正常”,我不得不反轉它。

顯然我正在做一些非常錯誤的事情,並且非常欣賞一些關於解決這個問題的建議。

下面有兩個類的代碼。

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

}

因此,只是發布和尋求幫助的情況總是奇跡般地導致自我解決。

對於遇到類似事情的其他人(雖然我懷疑任何人都可能如此愚蠢!)問題是“控制器”正在對玩家施加力量(左,右,跳等)但是IOnScreenControlListener的OnControlChange事件會被不斷調用我有“_player.getBody()。setLinearVelocity(velocity);” (速度為默認值0,0)反復調用,從而抵消了一些重力。

衛生署!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM