我正在使用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;
}
}
答案 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);