Тело Libgdx Box2d теряет скорость при падении

Я очень новичок в Box2d, и я пытаюсь создать простую программу для падения тела со спрайтом, нарисованным поверх него. Когда я запускаю свою программу, все работает, кроме того, что тело продолжает падать со скоростью, но все еще ускоряется. Например, скорость идет 0, -10, -20, -30, -40, -50, -60, -20, -30, -40, -50... и так далее. Вполне возможно, что я делаю что-то очень неправильное, так как я очень новичок в этом. Спасибо вам за помощь!

package com.davejones.spritetest;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
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.Vector2;
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.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;

public class SpriteTest extends ApplicationAdapter {

private SpriteBatch batch;
private World world;
private BodyDef bodyDef;
private Body body;
private Texture texture;
private Sprite sprite;
private OrthographicCamera camera;
private Box2DDebugRenderer debugRenderer;

@Override
public void create () {
    debugRenderer = new Box2DDebugRenderer();
    debugRenderer.setDrawBodies(false);
    camera = new OrthographicCamera();
    batch = new SpriteBatch();
    texture = new Texture("badlogic.jpg");
    sprite = new Sprite(texture);

    sprite.setPosition(Gdx.graphics.getWidth() / 2 - sprite.getWidth() / 2, Gdx.graphics.getHeight() / 2);

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

    bodyDef = new BodyDef();

    bodyDef.type = BodyDef.BodyType.DynamicBody;

    bodyDef.position.set(sprite.getX(), sprite.getY());
    body = world.createBody(bodyDef);

    PolygonShape shape = new PolygonShape();
    shape.setAsBox(sprite.getWidth()/2, sprite.getHeight()/2);

    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = shape;
    fixtureDef.density = 1f;

    Fixture fixture = body.createFixture(fixtureDef);

    shape.dispose();
}

@Override
public void resize(int width, int height) {
    super.resize(width, height);
    float cameraWidth = Gdx.graphics.getWidth();
    float cameraHeight = Gdx.graphics.getHeight();
    camera.setToOrtho(false, cameraWidth, cameraHeight);
    camera.position.set(Gdx.graphics.getWidth() / 2 - sprite.getWidth() / 2, Gdx.graphics.getHeight() / 2 - sprite.getHeight() / 2, 0);
}


@Override
public void render () {
    world.step(Gdx.graphics.getDeltaTime(), 8, 3);

    sprite.setPosition(body.getPosition().x, body.getPosition().y);

    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.begin();
    batch.draw(sprite, sprite.getX(), sprite.getY());
    batch.end();

    System.out.println(body.getLinearVelocity().y);

    camera.update();
    debugRenderer.render(world, camera.combined);
}

@Override
public void dispose () {
    batch.dispose();
    texture.dispose();
    world.dispose();
    debugRenderer.dispose();
}

}

1 ответ

Решение

Box2d лучше всего использовать со значениями от 0,1 до 10, поскольку значения этих размеров начинают терять точность. Каждый блок Box2D должен представлять 1 метр, поэтому ваш объект имеет размер 256 на 256 метров, что огромно. Это в сочетании с тем фактом, что Box2D имеет ограничение на максимальную скорость для объекта в 2 метра на шаг, означает, что ваш квадратный 256-метровый объект падает со скоростью 120 метров в секунду со скоростью 60 кадров в секунду, что превышает 250 миль в час.

Этому обычно противостоит использование некоторой формы преобразования между единицами экрана и единицами box2d. Либо используя постоянное значение для преобразования 256 в диапазон от 0,1 до 10, либо с помощью матрицы камеры для визуализации объекта на экране.

Я обновил ваш пример, чтобы использовать область просмотра. Это не решит проблему с максимальной скоростью Box2D, но должно помочь уменьшить эффекты, используя меньшие объекты, которые соответствуют единицам, с которыми Box2D разработан, чтобы работать лучше всего.

package com.mygdx.gtest;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
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.Vector2;
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.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.viewport.ExtendViewport;

public class Test extends ApplicationAdapter {

    private SpriteBatch batch;
    private World world;
    private BodyDef bodyDef;
    private Body body;
    private Texture texture;
    private Sprite sprite;
    private Box2DDebugRenderer debugRenderer;
    private ExtendViewport viewport;

    @Override
    public void create() {
        debugRenderer = new Box2DDebugRenderer(true,true,true,true, true, true);
        viewport = new ExtendViewport(64,48); // adding viewport so we can use multiple resolutions easily
        viewport.getCamera().position.set(32, 24, 0); // set cam position to make 0,0 bottom left corner
        batch = new SpriteBatch();
        batch.setProjectionMatrix(viewport.getCamera().combined); // tell the batch how things should be rendered 
        texture = new Texture("badlogic.jpg");
        sprite = new Sprite(texture);
        sprite.setSize(10,10); // set the size of the sprite in box2d units (10 meters x 10 meters)

        // not needed as position is set in update method
        //sprite.setPosition(Gdx.graphics.getWidth() / 2 - sprite.getWidth() / 2,   Gdx.graphics.getHeight() / 2);

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

        bodyDef = new BodyDef();

        bodyDef.type = BodyDef.BodyType.DynamicBody;

        bodyDef.position.set(32 , 47);
        body = world.createBody(bodyDef);

        PolygonShape shape = new PolygonShape();
        shape.setAsBox(5,5);

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = shape;
        fixtureDef.density = 1f;

        Fixture fixture = body.createFixture(fixtureDef);

        shape.dispose();
    }

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

    @Override
    public void render() {
        world.step(Gdx.graphics.getDeltaTime(), 8, 3);

        sprite.setPosition(body.getPosition().x - (sprite.getWidth()/2), body.getPosition().y -(sprite.getHeight()/2));

        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.setProjectionMatrix(viewport.getCamera().combined);  // tell the batch how things should be rendered incase of resized window
        batch.begin();
        batch.draw(sprite, sprite.getX(), sprite.getY(),sprite.getWidth(),sprite.getHeight());
        batch.end();

        System.out.println(body.getLinearVelocity().y);

        debugRenderer.render(world, viewport.getCamera().combined);
    }

    @Override
    public void dispose() {
        batch.dispose();
        texture.dispose();
        world.dispose();
        debugRenderer.dispose();
    }
}
Другие вопросы по тегам