简体   繁体   English

Box2D线速度导致两个接触体之间出现间隙

[英]Box2D Linear Velocity Causes Gap Between Two Touching Bodies

I'm working on an Android project using Box2D through LibGDX in which I plan on having multiple dynamic bodies that can be dragged and thrown around the screen. 我正在使用通过LibGDX使用Box2D的Android项目,在该项目中,我计划有多个可在屏幕上拖动和抛出的动态实体。 There will be a few static bodies on the screen as well and the dynamic bodies should never be allowed to pass through them. 屏幕上也会有一些静态物体,并且绝对不允许动态物体通过它们。 I coded up a simple application that contains a static body platform and a dynamic body square which falls onto the platform as a first attempt. 我编写了一个简单的应用程序,其中包含一个静态的身体平台和一个动态的身体方块,该方块第一次落入平台。

There seems to be a bit of a problem relating to the behavior of the box. 似乎与盒子的行为有关的问题。 When I start this app, gravity pulls the box from the top of the screen down to the platform where it rests. 当我启动该应用程序时,重力将框从屏幕顶部下拉到其放置的平台。 If I touch the box and try to drag it downward through the platform, the box actually levitates upward a bit and shoots upward when I release my finger (sometimes it even quickly rotates back and forth before shooting up). 如果我触摸该框并尝试将其向下拖动通过平台,则该框实际上会向上浮动并在松开手指时向上射击(有时甚至在向上射击之前,它会快速地来回旋转)。 However, if I drag the box around and manually place it on the platform, then try to pull the box through the platform, it behaves as I would expect in that it does not move at all and does not shoot upward when I release my finger. 但是,如果我拖动框并将其手动放置在平台上,然后尝试将框拉过平台,它的行为将与我期望的一样,因为它完全不会移动,并且在我松开手指时不会向上射击。 The issue only shows when gravity is responsible for pulling it to the platform. 该问题仅显示重力何时将其拉到平台。 My questions regarding this are below: 我对此的疑问如下:

Why does the box levitate/rotate when I try to drag it through the platform after it has naturally rested on the platform? 当盒子自然地放在平台上时,为什么要将其拖动通过平台,它为什么会悬浮/旋转?

Why does the box behave correctly (sits still) when I drag it around a bit, then try to drag it through the platform? 为什么当我将其拖动一点点然后尝试将其拖动到平台上时,该盒子的行为正确(静止不动)?

Currently, I'm setting the restitution on the box to zero whenever it is touched and resetting it back to 0.3 when it is released and this issue is showing. 当前,我将盒子上的归还位置设置为零,每当它被释放并显示此问题时,将其重置为0.3。 The strange thing is, if I set the restitution to zero when the box is created and leave it as such, this issue seems to disappear completely. 奇怪的是,如果在创建盒子时将恢复原状设置为零,并保持原样,则此问题似乎会完全消失。 I don't want to leave the restitution set to zero though. 我不想将恢复原状设置为零。

I was dragging down on the box (default Bad Logic logo) in this screenshot. 我在此屏幕快照中向下拖动了框(默认为Bad Logic徽标)。 Notice the gap between it and the platform. 注意它和平台之间的间隙。 Screenshot Image 屏幕截图

Here's my code. 这是我的代码。 Any help will be greatly appreciated! 任何帮助将不胜感激! package com.mygdx.game; 包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;
    }
}

It seems Box2D does not work well with changes to restitution within a fixture after the fixture has been created. 创建夹具后,Box2D似乎无法与夹具中恢复原状的更改配合使用。 This line is the culprit: 这是罪魁祸首:

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

I found a work around for this issue though. 我找到了解决该问题的方法。 If I destroy the fixture from the body, create a new fixture with the desired restitution, and add the new fixture to the body, this problem disappears. 如果我从身体上销毁了灯具,创建了具有所需恢复性的新灯具,然后将新灯具添加到车身,则此问题将消失。 Something like below (although you'd probably want to extract the Fixture creation into a new function): 如下所示(尽管您可能希望将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);

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

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