【问题标题】:Libgdx box2d body moves slowLibgdx box2d 身体移动缓慢
【发布时间】:2016-02-20 07:06:05
【问题描述】:

这是一个非常简单的 box2d 场景。我尝试了不同的视口和不同的屏幕尺寸。我不明白为什么身体下降得很慢。实际上,我不太确定它很慢,原因可能是视口设置等。 这是主类:

public class Main extends Game {
LevelScreen levelScreen;

@Override
public void create () {
    levelScreen = new LevelScreen();
    setScreen(levelScreen);

}

@Override
public void render () {
    super.render();
}
}

和水平屏:

public class LevelScreen extends Stage implements Screen {

private Batch batch;
private Camera camera;
private Texture ballTexture;
private Sprite ball;
private Viewport viewport;
//com

private Vector3 point = new Vector3();

private World world;
private Box2DDebugRenderer box2DDebugRenderer;

private CircleShape circleShape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;

private static final float SCENE_WIDTH = 1080;
private static final float SCENE_HEIGHT = 1920f;


public LevelScreen() {
    super(new FitViewport(SCENE_WIDTH, SCENE_HEIGHT,  new OrthographicCamera(SCENE_WIDTH, SCENE_HEIGHT)));


    batch = getBatch();
    camera = getCamera();
    viewport = getViewport();

    world = new World(new Vector2(0,-9.8f), true);
    box2DDebugRenderer = new Box2DDebugRenderer();
    bodyDef = new BodyDef();
    bodyDef.type = BodyDef.BodyType.DynamicBody;
    bodyDef.position.set(600, 1000);

    ballTexture = new Texture("ball.png");
    ball = new Sprite(ballTexture);
    ball.setPosition(0,0);

    circleShape = new CircleShape();
    circleShape.setRadius(25f);

    fixtureDef = new FixtureDef();
    fixtureDef.shape = circleShape;
    fixtureDef.density = 0.5f;
    fixtureDef.friction = 0.4f;
    fixtureDef.restitution = 0.6f;

    circleBody = world.createBody(bodyDef);
    circleBody.createFixture(fixtureDef);

    box2DDebugRenderer = new Box2DDebugRenderer(
            true, /* draw bodies */
            false, /* don't draw joints */
            true, /* draw aabbs */
            true, /* draw inactive bodies */
            false, /* don't draw velocities */
            true /* draw contacts */);

    Gdx.input.setInputProcessor(this);


}

@Override
public void show() {
    System.out.println("show");
}

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(1, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.setProjectionMatrix(camera.combined);

    batch.begin();
    ball.draw(batch);

    batch.end();

    world.step(1 / 60f, 6, 2);
    ball.setPosition(circleBody.getPosition().x - 25f, circleBody.getPosition().y - 25f);
    box2DDebugRenderer.render(world, viewport.getCamera().combined);

}

@Override
public void resize(int width, int height) {
    viewport.update(width, height);
    System.out.println("resize");
}

@Override
public void pause() {
    System.out.println("pause");
}

@Override
public void resume() {
    System.out.println("resume");
}

@Override
public void hide() {
    System.out.println("hide");
}

@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    viewport.getCamera().unproject(point.set(screenX, screenY, 0));
    return false;
}
}

【问题讨论】:

  • Box2D 中的 1 个单位代表我相信的米。因此,如果你给一个直径为 50 米的足球,它看起来就像是在缓慢下落。这就像你看到地球绕太阳旋转需要 365 天,但速度为108.000 km/h。如果你放大地球,它会在纳秒内消失,但如果你缩小太阳系,你甚至不会看到它移动。尝试circleShape.setRadius(.11f); 并放大。或者增加重力,但这可能会导致以后出现问题。
  • 纹理呢?如果我放大它们会很大。
  • 你的红色背景会很大,是的,但是球的纹理会被适当地缩放,因为你把它做得很小。所以你需要把所有东西都变小。大小在游戏开发中是相对的。
  • 你能给出一个示例代码吗?我的球纹理是 50x50px。我应该怎么画它才不会很大。我应该做类似 sprite.scale(1/100) 的事情吗?
  • 你不懂。不要再考虑像素和大小,一切都是相对的。你的球在屏幕上应该保持相同的大小。首先你缩小它,然后你把相机靠近。再次阅读我的第一条评论。如果我将一枚硬币放在我的面前,它会在几毫秒内通过我的视野。现在站在一栋高楼前,这样您就可以在一个视图中看到顶部阳台和地面。在这里,您要求朋友放下另一个对象。现在这个物体在你体内的传播时间更长了,因为你被缩小了。

标签: libgdx box2d


【解决方案1】:

好吧,我似乎无法通过简单的评论让您理解。让我们通过代码尝试:

屏幕

public class TestScreen implements Screen {
    SpriteBatch batch;
    OrthographicCamera camera;

    World world;
    Box2DDebugRenderer dr;

    Ball ball;


    public TestScreen() {
        batch = new SpriteBatch();
        camera = new OrthographicCamera(1.6f, 1f); // <---- Very small camera so it passes by fast since less surface is being shown

        world = new World(new Vector2(0, -9.8f), true);

        ball = new Ball(.11f, world); // <---- Create ball and pass in the diameter

        //Try playing with the value of camera let's say we have a ball the size of planet earth:
        //ball = new Ball(6371, world);

        //Now zoom out the screen so we can see our planet sized ball
        //camera = new OrthographicCamera(16000, 10000);

        //Believe me, our planet ball falls as fast as the little soccer ball.       //But since you zoomed out each pixel represents so much more distance.


        dr = new Box2DDebugRenderer(true, false, false, false, false, false);
    }

    @Override
    public void show() {

    }

    @Override
    public void render (float delta) {
        Gdx.gl.glClearColor(.1f, .1f, .14f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.setProjectionMatrix(camera.combined);

        world.step(Gdx.graphics.getDeltaTime(), 6, 2);

        batch.begin();
        ball.draw(batch);
        batch.end();

        dr.render(world, camera.combined);

    }
 //... Other mandatory screen methods
}

Ball.java

public class Ball {

    private float radius;

    private CircleShape shape;
    private FixtureDef fixtureDef;
    private BodyDef bodyDef;
    private Body circleBody;

    private Texture ballTexture;

    public Ball(float radius, World world) {
        this.radius = radius;

        ballTexture = new Texture("sprites/soccerball.png");

        bodyDef = new BodyDef();
        bodyDef.type = BodyDef.BodyType.DynamicBody;
        bodyDef.position.set(0, 0);

        shape = new CircleShape();
        shape.setRadius(radius);

        fixtureDef = new FixtureDef();
        fixtureDef.shape = shape;
        fixtureDef.density = 0.5f;
        fixtureDef.friction = 0.4f;
        fixtureDef.restitution = 0.6f;

        circleBody = world.createBody(bodyDef);
        circleBody.createFixture(fixtureDef);
    }

    public void draw(SpriteBatch batch)
    {
        batch.draw(ballTexture, circleBody.getPosition().x - radius, circleBody.getPosition().y - radius,
                radius * 2, radius * 2); // <---- draw the size you give it in the physics engine
    }
}

让我们开始你做错了什么:

你给了世界 9,8 个单位的重力。这些不是像素,也不是距离,也不是任何东西。当你决定这些是米(代表地球上的重力)时,它们才会是米,你应该坚持这个比例。

接下来,您制作一个半径为 25 米的球,然后将相机拉远以显示 1920 米高的区域。在现实生活中,将一个物体从 2 公里坠落到地面需要一段时间。因此,由于您在现实世界中使用的是每秒 9.8m 的速度,因此您的应用程序也需要一些时间才能落地。

所以你想做的就是缩小规模。一个足球的半径只有 11 厘米,所以我创建了一个半径为 0.11 米的球。但是您将看不到这一点,因为到目前为止,如果您的相机缩小,它只是一个像素的一小部分。所以放大你的相机(因为它是正交的,你只需设置它的视口尺寸)。

对于有关绘制正确大小的球的后续问题,您只需使用前面给出的半径即可。正如你所看到的球,摄像机 vp 非常小,球也非常小。对于行星大小的例子,相机被拉得很远,行星是我们自己地球的大小。然而我只是根据它的半径画球,一切都会好起来的。

希望你明白,也许你必须停止想太多,因为这个概念很简单。

【讨论】:

  • 解释得很好!
【解决方案2】:

您应该为 box2d 使用小型相机,因为 box2d 在 0-10 值中效果更好。 这是你的关卡屏幕类。试试吧。

    public class LevelScreen extends Stage implements Screen {

         private Batch batch;
         private Camera camera;
         private Texture ballTexture;
         private Sprite ball;
         private Viewport viewport;


         private Vector3 point = new Vector3();

private World world;
private Box2DDebugRenderer box2DDebugRenderer;

private CircleShape circleShape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;

private static final float SCENE_WIDTH = 28;
private static final float SCENE_HEIGHT = 48f;


public LevelScreen() {
    super(new FitViewport(SCENE_WIDTH, SCENE_HEIGHT,  new OrthographicCamera(SCENE_WIDTH, SCENE_HEIGHT)));


    batch = getBatch();
    camera = getCamera();
    viewport = getViewport();

    world = new World(new Vector2(0,-9.8f), true);
    box2DDebugRenderer = new Box2DDebugRenderer();
    bodyDef = new BodyDef();
    bodyDef.type = BodyDef.BodyType.DynamicBody;
    bodyDef.position.set(10, 28);

    ballTexture = new Texture("ball.png");
    ball = new Sprite(ballTexture);
    ball.setPosition(0,0);

    circleShape = new CircleShape();
    circleShape.setRadius(1f);

    fixtureDef = new FixtureDef();
    fixtureDef.shape = circleShape;
    fixtureDef.density = 0.5f;
    fixtureDef.friction = 0.4f;
    fixtureDef.restitution = 0.6f;

    circleBody = world.createBody(bodyDef);
    circleBody.createFixture(fixtureDef);

    box2DDebugRenderer = new Box2DDebugRenderer(
            true, /* draw bodies */
            false, /* don't draw joints */
            true, /* draw aabbs */
            true, /* draw inactive bodies */
            false, /* don't draw velocities */
            true /* draw contacts */);

    Gdx.input.setInputProcessor(this);


}

@Override
public void show() {
    System.out.println("show");
}

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(1, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.setProjectionMatrix(camera.combined);

    batch.begin();
    ball.draw(batch);

    batch.end();

    world.step(1 / 60f, 6, 2);
    ball.setPosition(circleBody.getPosition().x - 25f, circleBody.getPosition().y - 25f);
    box2DDebugRenderer.render(world, viewport.getCamera().combined);

}

@Override
public void resize(int width, int height) {
    viewport.update(width, height);
    System.out.println("resize");
}

@Override
public void pause() {
    System.out.println("pause");
}

@Override
public void resume() {
    System.out.println("resume");
}

@Override
public void hide() {
    System.out.println("hide");
}

@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    viewport.getCamera().unproject(point.set(screenX, screenY, 0));
    return false;
}
}

【讨论】:

  • “0-10 值”是什么意思? 28 和 48 不在 0-10 之间。我会尽快尝试代码。谢谢
  • 28 和 48 是相机尺寸,因此我们不需要将像素转换为米。0-10 表示身体的密度、恢复原状、速度等。
  • 我试过代码。 Box2D 看起来不错,但是,纹理是缩放的。球现在填满了屏幕。这是一个 50x50 像素的 png 文件。该怎么做才能解决这个问题?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多