在Libgdx Box2d World上使用像素每米时的巨大图像



大家好,我正在尝试实现一个box2d世界。我读到box2d使用米。您需要将其从像素转换为米。

我试着画了一幅图像,但我必须缩小图像吗?我认为这是一个糟糕的主意。我想画一张图像,图像非常巨大,不知道该怎么做才能使它与每米box2d像素的一起工作

public class TestScreen extends ScreenAdapter {
    private final Body body;
    private int V_WIDTH = 320;
    private int V_HEIGHT = 480;
    private int PPM = 100;
    private SpriteBatch batch;
    private OrthographicCamera camera;
    private World world;
    private Sprite sprite;
    Box2DDebugRenderer box2DDebugRenderer;
    public TestScreen(){
        batch = new SpriteBatch();
        camera = new OrthographicCamera();
        camera.setToOrtho(false, V_WIDTH / PPM, V_HEIGHT / PPM);
        camera.position.set(0,0,0);
        world = new World(new Vector2(0,0) , true);
        sprite = new Sprite(new Texture("test/player.png"));
        box2DDebugRenderer = new Box2DDebugRenderer();
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyDef.BodyType.KinematicBody;
        body = world.createBody(bodyDef);
        FixtureDef fixtureDef = new FixtureDef();
        PolygonShape shape = new PolygonShape();
        shape.setAsBox(sprite.getWidth()/2 / PPM, sprite.getHeight()/2 / PPM);
        fixtureDef.shape = shape;
        body.createFixture(fixtureDef);
        sprite.setPosition(body.getPosition().x - sprite.getWidth() /2 ,body.getPosition().y - sprite.getHeight() / 2  );
    }
    @Override
    public void render(float delta) {
        super.render(delta);
        camera.position.set( body.getPosition().x, body.getPosition().y , 0);
        camera.update();
        world.step(1/60.0f, 6, 2);
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        sprite.draw(batch);
        batch.end();
        box2DDebugRenderer.render(world, camera.combined);
    }
}

无ppm

带有PPm

我应该缩小图像的比例吗?绘制图像的最佳方法是什么

您不需要从像素转换为米。事实上,你应该忘记像素。它们只存在于你的屏幕上,你的游戏逻辑不应该知道你的屏幕。这就是相机或视口的用途,您可以指定要显示世界的多少,以及显示是否应该拉伸或黑框或其他什么。所以没有像素,周期。他们是邪恶的,给你错误的想法。

现在,如果你创建自己的游戏,你可以说一个单位代表1毫米、34厘米或几光年。你告诉负责显示你的游戏的对象要显示多少这些单位。但是,您使用的是Box2D,并且Box2D已经为您填写了1 unit == 1m单元。也许可以改变这一点,或者至少创建一个包装类,将单位转换为Box2D单位。

保持Box2D单元的真实性很重要,原因如下。如果你把一块大理石掉在地上,它似乎比天空中的太阳移动得更快。但相信我,太阳移动得更快,但由于它离得更远,它似乎移动得很慢。由于Box2D都是关于运动的,所以你应该忠于这个单元,否则事情就会开始变得奇怪。

让我们现在只使用1 unit == 1m,突然间,通过询问视图问题,一切都会变得简单得多。

  • 你想用米来展示你的游戏世界的多少?

    float width = 20; // 20 meters
    //You can calculate on your chosen width or height to maintain aspect ratio
    float height = (Gdx.graphics.getHeight() / Gdx.graphics.getWidth()) * width;        
    camera = new OrthographicCamera(width, height);
    //Now the center of the camera is on 0,0 in the game world. It's often more desired and practical to have it's bottom left corner start out on 0,0
    //All we need to do is translate it by half it's width and height since that is the offset from it's center point (and that is currently set to 0,0.
    camera.translate(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
    camera.update();
    
  • 我们的物体有多大?请记住,质量、重量和尺寸是完全不同的。

    Sprite mySprite = new Sprite(myTexture);
    //position it somewhere within the bounds of the camera, in the below case the center
    //This sprite also gets a size of 1m by 1m
    mySprite.setBounds(width / 2, height / 2, 1, 1);
    
  • 我们希望如何将SpriteBatch绘制到屏幕上?

    //We tell the SpriteBatch to use out camera settings to draw
    spriteBatch.setProjectionMatrix(camera.combined);
    //And draw the sprite using this SpriteBatch
    mySprite.draw(spriteBatch);
    

Box2dDebugRenderer实现的计数相同。如果你想显示形状,你需要再次使用相机中的组合矩阵来绘制。

    box2DDebugRenderer.render(world, camera.combined);

当然,当事物移动时,你需要相应地更新你的精灵位置。您可以从box2d.Body对象获取此信息。但这超出了你的问题范围。

最终向您展示问题所在:

camera.setToOrtho(false, V_WIDTH / PPM, V_HEIGHT / PPM);

您的相机显示游戏世界的320/100 == 3.2f x 480/100 == 4.8f。您的精灵可能是64x64像素。你不会告诉任何地方以什么大小绘制你的精灵,所以它将假设1像素=1个单位,你将相机设置为显示3.2f个单位的宽度。我们可以也应该将像素排除在等式之外,只需询问您希望对象的大小。然后将精灵设置为该大小。在这里,你可以看到像素思维只会给你带来问题。

对于一个太空游戏,你用第三个人驾驶一艘100x20米的飞船,你可能希望你的相机视口非常大。但对于蚂蚁游戏,你的蚂蚁是真实大小的,你需要一个非常小的相机视口。一定要想想现实生活中的物理学。伽利略发现物体以相同的速度下落,而不考虑阻力。所以,如果蚂蚁掉下一粒沙子,它看起来会掉得很快,因为你的屏幕代表的米要少得多。

关于丢球的实现,请看我的答案。它创建了一个box2D实体,并在上面附加了一个图像。我将球的功能封装在Ball()类中。(免责声明:我刚刚玩了一点Box2D,我不知道足球的确切物理行为,所以我并不是说这是一个正确的实现,但它确实展示了如何设置场景并让图像代表你的Box2D身体)。

最新更新