Box2D线速度导致两个触摸体之间的间隙

时间:2018-01-29 03:09:09

标签: android libgdx box2d

我正在使用Box2D通过LibGDX开发一个Android项目,我计划在其中设置多个可以在屏幕上拖动和抛出的动态实体。屏幕上也会有一些静态物体,永远不允许动态物体穿过它们。我编写了一个简单的应用程序,它包含一个静态的身体平台和一个动态的正方形,作为第一次尝试落在平台上。

似乎有一些与盒子行为有关的问题。当我启动这个应用程序时,重力将盒子从屏幕顶部向下拉到它所在的平台。如果我触摸盒子并尝试将其向下拖动通过平台,当我松开手指时,盒子实际上向上悬浮一点并向上射击(有时甚至在拍摄前快速来回旋转)。但是,如果我拖动盒子并手动将它放在平台上,然后尝试将盒子拉过平台,它的行为与我预期的一样,它根本不会移动,当我松开手指时它不会向上射击。该问题仅显示重力负责将其拉到平台的时间。我对此的疑问如下:

为什么当盒子在平台上自然停留后,试图将它拖过平台时,盒子会悬浮/旋转?

当我将它拖动一点时,为什么盒子表现正常(静止不动),然后尝试将它拖过平台?

目前,无论何时触摸,我都会将框中的恢复原状设置为零,并在发布时将其重置为0.3并显示此问题。奇怪的是,如果我在创建框时将恢复原状设置为零并保持原样,则此问题似乎完全消失。我不想将恢复原状设置为零。

我在此屏幕截图中拖动了该框(默认Bad Logic徽标)。注意它和平台之间的差距。 Screenshot Image

这是我的代码。任何帮助将不胜感激!     包com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;

public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
    private static float VIEWPORT_WIDTH = 4.8f;
    private static float VIEWPORT_HEIGHT = 8f;
    private static float PPM = 300f;
    private static float BOX_RESTITUTION = 0.3f;

    World world;
    OrthographicCamera camera;
    Box2DDebugRenderer renderer;
    Body squareBody;
    SpriteBatch batch;
    Sprite box;
    boolean draggingBox = false;
    Vector2 touchPoint;

    @Override
    public void create () {
        Gdx.input.setInputProcessor(this);

        this.batch = new SpriteBatch();
        this.world = new World(new Vector2(0f, -9.81f), true);
        this.renderer = new Box2DDebugRenderer();
        this.camera = new OrthographicCamera();
        this.camera.setToOrtho(false, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);

        // Platform
        BodyDef platformBodyDef = new BodyDef();
        platformBodyDef.type = BodyDef.BodyType.StaticBody;
        platformBodyDef.position.set(VIEWPORT_WIDTH / 2, 2f);
        Body platformBody = this.world.createBody(platformBodyDef);
        PolygonShape platformShape = new PolygonShape();
        platformShape.setAsBox(VIEWPORT_WIDTH / 2 - 0.2f, 0.5f / 2);
        FixtureDef platformFixtureDef = new FixtureDef();
        platformFixtureDef.shape = platformShape;
        platformFixtureDef.friction = 1f;
        platformFixtureDef.restitution = 0f;
        platformFixtureDef.density = 3f;
        platformBody.createFixture(platformFixtureDef);

        // Box sprite
        this.box = new Sprite(new Texture("badlogic.jpg"));

        // Square
        BodyDef squareBodyDef = new BodyDef();
        squareBodyDef.type = BodyDef.BodyType.DynamicBody;
        squareBodyDef.position.set(VIEWPORT_WIDTH / 2, 7.5f);
        this.squareBody = this.world.createBody(squareBodyDef);
        PolygonShape squareShape = new PolygonShape();
        squareShape.setAsBox(this.box.getWidth() / PPM / 2, this.box.getHeight() / PPM / 2);
        FixtureDef squareFixtureDef = new FixtureDef();
        squareFixtureDef.shape = squareShape;
        squareFixtureDef.friction = 1f;
        squareFixtureDef.restitution = BOX_RESTITUTION;
        squareFixtureDef.density = 1f;
        this.squareBody.createFixture(squareFixtureDef);
    }

    @Override
    public void render () {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        this.camera.update();
        this.world.step(1/60f, 6, 2);
        this.renderer.render(this.world, this.camera.combined);

        // Set the velocity so the box will follow the users finger when dragged.
        if (this.draggingBox == true) {
            Vector2 velocity = this.touchPoint.cpy();
            velocity.sub(new Vector2(this.box.getX() / PPM, this.box.getY() / PPM));
            velocity.scl(10f);
            this.squareBody.setLinearVelocity(velocity);
        }

        // Update the position/rotation of the box sprite to match the physics body.
        this.box.setPosition(
                this.squareBody.getPosition().x * PPM - (this.box.getWidth() / 2),
                this.squareBody.getPosition().y * PPM - (this.box.getHeight() / 2));
        this.box.setRotation((float) Math.toDegrees(this.squareBody.getAngle()));

        this.batch.begin();
        this.box.draw(this.batch);
        this.batch.end();
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        Vector3 touchPoint3D = this.camera.unproject(new Vector3(screenX, screenY, 0));
        Vector2 touchPoint2D = new Vector2(touchPoint3D.x, touchPoint3D.y);

        // Get the box boundary and convert it to meters.
        Rectangle boxBoundary = this.box.getBoundingRectangle();
        boxBoundary.setX(boxBoundary.getX() / PPM);
        boxBoundary.setY(boxBoundary.getY() / PPM);
        boxBoundary.setWidth(boxBoundary.getWidth() / PPM);
        boxBoundary.setHeight(boxBoundary.getHeight() / PPM);

        // If the box boundary contains the touch point, start the dragging and remove restitution.
        if (boxBoundary.contains(touchPoint2D)) {
            this.draggingBox = true;
            this.touchPoint = touchPoint2D;
            this.squareBody.getFixtureList().get(0).setRestitution(0);
        }

        return true;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        this.draggingBox = false;
        this.touchPoint = null;
        this.squareBody.getFixtureList().get(0).setRestitution(BOX_RESTITUTION);
        return true;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        Vector3 touchPoint3D = this.camera.unproject(new Vector3(screenX, screenY, 0));
        this.touchPoint = new Vector2(touchPoint3D.x, touchPoint3D.y);

        return true;
    }

    @Override
    public void dispose () {
        this.box.getTexture().dispose();
        batch.dispose();
    }

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

1 个答案:

答案 0 :(得分:0)

在创建夹具后,Box2D似乎不能很好地修复夹具内的恢复。这条线是罪魁祸首:

this.squareBody.getFixtureList().get(0).setRestitution(0);

我找到了解决这个问题的方法。如果我从身体上摧毁固定装置,创建一个具有所需恢复原状的新固定装置,并将新固定装置添加到身体,这个问题就会消失。类似下面的内容(尽管你可能想要将Fixture创建提取到一个新函数中):

// Destroy the current Fixture that exists on the Body. Multiple Fixtures can be assigned, but in this case there is only one.
this.squareBody.destroyFixture(this.squareBody.getFixtureList().get(0));

// Create a new shape to define a new Fixture.
PolygonShape squareShape = new PolygonShape();
squareShape.setAsBox(this.box.getWidth() / PPM / 2, this.box.getHeight() / PPM / 2);

// Create a new Fixture with the desired restitution value.
FixtureDef squareFixtureDef = new FixtureDef();
squareFixtureDef.shape = squareShape;
squareFixtureDef.friction = 1f;
squareFixtureDef.restitution = 0;
squareFixtureDef.density = 1f;

// Add the new Fixture to the Body.
this.squareBody.createFixture(squareFixtureDef);