【问题标题】:Box2D Linear Velocity Causes Gap Between Two Touching BodiesBox2D 线速度导致两个接触体之间的间隙
【发布时间】:2018-01-29 03:09:09
【问题描述】:

我正在开发一个通过 LibGDX 使用 Box2D 的 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;
    }
}

【问题讨论】:

  • 我对 Box2D 不是很熟悉,但请问您为什么要更改身体的恢复(弹性)?突然增加弹性可能是它弹起的原因,如果它以某种方式被压缩或在你松开手指时处于奇怪的位置。如果您始终将其设置为 0.3,会发生什么?
  • 我正在设置身体的恢复,因为我希望它在用户将它扔到其他身体或重力将它拉到另一个身体时在屏幕上反弹。如果身体没有从其他身体反弹,它看起来很不自然。我只是尝试在拖动时将恢复原状保持在 0.3,但问题仍然存在。
  • 我怀疑你看到的差距是形状的“皮肤”。除非您使用的尺寸小于建议的范围,例如十分之一米到 10 米左右(我不记得具体细节),否则这些不会显示。您可以尝试更改缩放比例,使其不是 1:1,而是更像 10:1,其中世界比屏幕尺寸大 10 倍,并查看间隙是否相对于形状小 10 倍。稍后我可能会给你更多的细节,但必须运行 ATM。希望这会为您指明正确的方向!
  • 随着向下速度的增加,差距实际上变得更大。这似乎是 Box2D 保持初始恢复的问题,即使在触摸框时它被设置为零。不过,我找到了解决方法。请参阅下面接受的解决方案。

标签: android libgdx box2d


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    • 2014-03-16
    • 1970-01-01
    相关资源
    最近更新 更多