相机如何在 Libgdx 和视口中工作

Mor*_*hul 2 java camera viewport libgdx

如果您使用 LibGdx,它很快就会来到相机和视口。如果您第一次使用相机和视口工作,您会遇到一些关于它如何工作以及如何使用它的问题。所以:

  • 如何在 LibGdx 中使用相机?什么是视口宽度和高度?
  • 什么是视口,我如何使用它以及它如何与相机一起工作?

Mor*_*hul 13

如何在 LibGdx 中使用相机?什么是视口宽度和高度?

首先,重要的是您要知道相机适用于世界单位而不是像素。世界单位不是常规单位。您可以自行定义一个世界单位是多少。后来更多。

首先,我们创建一个OrthographicCameraaSpriteBatch和 a Texture

private OrthographicCamera camera;
private SpriteBatch batch;
private Texture img;

@Override
public void create () {
    //We create a OrthographicCamera through which we see 50x50 World Units
    camera = new OrthographicCamera(50,50);
    batch = new SpriteBatch();
    img = new Texture("badlogic.jpg");
}
Run Code Online (Sandbox Code Playgroud)

我们创建一个OrthographicCamera并在构造函数中定义如果我们通过这个摄像机观察我们的世界,我们会看到多少个世界单位。在我们的示例 50 x 50 World Units 中,这些是视口的宽度和高度。所以我们创建了一个视口宽度和高度为 50 的相机。

在 render() 方法中,我们渲染图像:

@Override
public void render () {
    //Clear the screen (1)
    Gdx.gl.glClearColor(1, 1, 1, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    //Set ProjectionMatrix of SpriteBatch (2)
    batch.setProjectionMatrix(camera.combined);

    batch.begin();
    //Draw image on position 0, 0 with width 25 and height 25 (3)
    batch.draw(img, 0, 0, 25, 25); 
    batch.end();
}
Run Code Online (Sandbox Code Playgroud)

(1) 清除屏幕,如果我们不这样做,每个纹理都会绘制在另一个之上,如果我们绘制动画,我们将看到旧的帧。

(2) 这batch是我们的抽屉,他绘制我们的图像、动画等。默认情况下,他绘制了一个世界,它有很多世界单位,比如屏幕有像素,所以在这种情况下,1 世界单位 = 1 像素。但是现在我们将看到 50 x 50 World Units,不管屏幕有多大。要说 Batch 应该绘制我们通过相机看到的内容,我们必须调用:batch.setProjectionMatrix(camera.combined);

(3) 现在我们img在位置 0,0 上绘制但是 0, 0 并不意味着在像素位置 0,0 上它意味着图像将在世界位置 0,0 上绘制,宽度和高度也不在它们所在的像素中世界单位因此img将绘制在位置 0,0 25x25 世界单位大上。因此,在 50x50 视口上,图像会占满整个屏幕的四分之一。

在此处输入图片说明

图像完全按预期填充整个屏幕的四分之一。但是为什么它在右上角而不是在左下角呢?

问题是相机的中心点在位置 0,0 在此处输入图片说明

所以我们的图像绘制在位置 0,0 他填充右上角。我们必须设置相机的位置,使 0,0 位于左下角:

camera = new OrthographicCamera(50,50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
Run Code Online (Sandbox Code Playgroud)

在 render() 方法中,我们必须添加,camera.update()因为每次我们更改位置或比例或相机的其他内容时,我们都必须更新相机。

现在图像在左下角。

像素在哪里?

我们总是谈论世界单位,但像素在哪里?像素还在。如果我们的屏幕尺寸为 200 x 200 像素,批处理将始终绘制 200 x 200 像素。用这个方法batch.setProjectionMatrix(camera.combined);我们只说batch多少World Units是一个Pixel。

如果我们有一个 200 x 200 像素的屏幕,并且我们创建了一个具有 50 x 50 世界单位视口的相机,则 SpriteBatch 知道 1 WorldUnit = 4 像素。现在我们绘制一个 25 x 25 世界单位大的图像,SpriteBatch 知道他必须绘制 25 * 4 = 100 像素大的图像。

所以像素仍然存在,但在世界单位中更容易思考。如果还不够清楚,这里有更详细的描述:Libgdx's World Units

Box2d

如果您使用 Box2d,考虑世界单位也非常重要,因为 Box2d 与米一起工作。因此,如果您在 x 轴上创建一个力为 5 的物体,则该物体的速度为 5 m/s。

现在使用 World Units 非常酷,因为您可以说 1 World Unit = 1 Meter,因此您可以创建一个宽度为 10 的对象,并且一秒钟后您就会知道 Body 将位于对象的中心。如果您使用像素,如果您有不同的屏幕尺寸,您将遇到问题。

什么是视口,我如何使用它以及它如何与相机一起工作?

现在我们有关于不同屏幕尺寸的大问题。突然,我们的屏幕大小变成了 350 x 200 像素,现在图像将被拉伸,看起来不像以前那么漂亮了。

对于这个问题,我们使用视口,一些视口是StretchViewportFitViewportExtendViewport。您可以在此处找到的所有视口:https : //github.com/libgdx/libgdx/wiki/Viewports

首先什么是视口。

想象一下,相机是一个会说英语的演讲者。不同的屏幕尺寸是其他说德语、法语、中文等的人,视口是翻译器。翻译者并没有改变说英语的人所说的话,而是对其进行改编,以便其他人能够理解。相机和视口也是如此。如果您运行该程序,视口不会说明或更改您可以在屏幕上看到的内容。他只处理您在不同屏幕尺寸上总是看到相同的情况。相机可以在没有视口的情况下生活。一个不是没有相机的视口。

添加视口对象:

private Viewport viewport;
Run Code Online (Sandbox Code Playgroud)

和 resize() 方法:

@Override
public void resize (int width, int height) {
    viewport.update(width, height);
}
Run Code Online (Sandbox Code Playgroud)

拉伸视口

创建一个 StretchViewport:

camera = new OrthographicCamera(50, 50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
viewport = new StretchViewport(camera.viewportWidth, camera.viewportHeight, camera);
Run Code Online (Sandbox Code Playgroud)

在 StretchViewport 构造函数中,我们定义了视口宽度和高度以及相机。

现在我们得到和以前一样的结果,如果我们有不同的屏幕尺寸,图像将被拉伸。

适合视口

也许我们不会拉伸我们的图像,我们会关心 x 和 y 的比例。

x 和 y 的比率意味着: 对象 2 的宽度和 1 的高度,他总是宽度是高度的两倍,例如 200x100、30x15 但不是 20x15。

创建一个 FitViewport:

camera = new OrthographicCamera(50, 50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
viewport = new FitViewport(camera.viewportWidth, camera.viewportHeight, camera);
Run Code Online (Sandbox Code Playgroud)

现在图像将永远是一个正方形。要查看侧面的条形,让我们绘制与视口一样大的图像:

batch.draw(img, 0, 0, 50, 50);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 在此处输入图片说明

由于 50(width)/50(height) = 1,图像的比率为 1,因此图像将始终具有相同的宽度和高度。侧面的 Bars 在我们的视口之外,将以您在此处定义的颜色绘制:Gdx.gl.glClearColor(1, 1, 1, 1);

扩展视口

也许我们不会在旁边使用 Bars 然后我们可以使用 ExtendViewport。ExtendViewport 通过在一个方向上扩展世界来保持没有条的世界纵横比。意味着在宽度和高度之间的纵横比更大的屏幕上,您将看到更多的世界。

在 400x200 宽高比 = (400/200 = 2) 的屏幕上,您会看到比在 300x200 (300/200 = 1.5) 的屏幕上更多的东西;

为了显示这一点,创建一个 ExtendViewport 并绘制大于视口的图像和第二个小图像:

camera = new OrthographicCamera(50, 50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
viewport = new ExtendViewport(camera.viewportWidth, camera.viewportHeight, camera);

// in render() method
batch.begin();
batch.draw(img, 0, 0, 100, 50);
batch.draw(img, -20, 0, 20, 20);
batch.end();
Run Code Online (Sandbox Code Playgroud)

如果我们现在以 200x200 的屏幕尺寸启动我们的程序,我们会看到:

在此处输入图片说明

如果我们在 x 轴上调整屏幕大小以使屏幕更宽:

在此处输入图片说明

现在我们可以从第一个图像和附加的第二个图像中看到更多,但比例将始终相同。图像只是因为我们将其绘制为 100x50 而被拉伸,而不是因为调整大小。

我希望这会清除一些关于相机和视口的问题,如果你能学到更多,阅读和查看一些教程并阅读 LibGdx wiki:https : //github.com/libgdx/libgdx/wiki