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

Huge Image when Using Pixel Per Meter on 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);
    }
}

with out ppm

with PPm

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

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

现在,如果您创建自己的游戏,您可以说一个单位代表 1 毫米、34 厘米或几光年。您告诉 object 负责显示您的游戏的这些单位要显示多少。不过你用的是Box2D,Box2D已经帮你填好了单位1 unit == 1m。可能会更改此设置或至少创建一个包装器 class 将您的单位转换为 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();
    
  • 我们的object有多大?请记住,质量、重量和尺寸是完全不同的东西。

    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 object 中获取此信息。但这超出了你的问题范围。

最后向您展示出了什么问题:

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

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

对于一个 space 游戏,你在第三人称驾驶 100x20 米的船,你可能希望你的相机视口非常大。但是对于蚂蚁真实大小的蚂蚁游戏,您需要非常小的相机视口。想想现实生活中的物理学。伽利略·伽利莱 (Galileo Galilei) 发现 object 的下落速度相同,而忽略阻力。所以如果那只蚂蚁掉下一颗沙粒,它看起来会掉得很快,因为你的屏幕代表的米要少得多。

对于下落足球的实现look at my answer here。它创建一个 box2D body 并将图像附加到它。我将球的功能封装在 Ball() class 中。 (免责声明:我刚刚玩了一些 Box2D,我不知道足球的确切物理行为,所以我并不是说这是一个正确的实现,但它确实展示了如何设置你的场景并获得图像代表你的 Box2D body).