Camera 如何在 Libgdx 中以及与 Viewport 一起工作

How Camera works in Libgdx and together with Viewport

如果您使用 LibGdx,您很快就会看到相机和视口。如果您是第一次使用相机和视口,您会遇到一些有关其工作原理和使用方法的问题。所以:

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

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

首先,我们创建一个 OrthographicCamera 一个 SpriteBatch 和一个 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");
}

我们创建一个 OrthographicCamera 并在构造函数中定义如果我们通过这个相机观察我们的世界,我们会看到多少个世界单位。在我们的示例 50 x 50 世界单位中,这些是视口宽度和高度。 所以我们创建了一个视口宽度和高度为 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();
}

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

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

(3) 现在我们在位置 0,0 上绘制我们的 img 但是 0, 0 并不意味着在像素位置 0,0 上它意味着图像也将在世界位置 0,0 上绘制宽度和高度不是以像素为单位,而是以世界单位为单位,因此 img 将绘制在位置 0,0 25x25 世界单位大上。因此,在 50x50 视口上,图像会填满整个屏幕的 one-quarter。

整个屏幕的图像填充 one-quarter 完全符合预期。但是为什么是右上角而不是左下角呢?

问题是相机点的中心在位置 0,0

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

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

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

现在图片在左下方。

像素在哪里?

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

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

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

Box2d

如果您使用 Box2d,考虑世界单位也很重要,因为 Box2d 使用米。因此,如果您创建一个 Body,x 轴上的 Force off 为 5,则 Body 为 5 m/s fast.

现在使用世界单位非常酷,因为你可以说 1 世界单位 = 1 米,这样你就可以创建宽度为 10 的 object,一秒钟后你就会知道 Body 将位于 Object 的中心。如果您使用 Pixels,如果屏幕尺寸不同,就会遇到问题。

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

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

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

首先什么是视口。

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

添加视口Object:

private Viewport viewport;

和 resize() 方法:

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

StretchViewport

创建一个 StretchViewport:

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

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

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

FitViewport

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

x 和 y 的比率表示:是 Object 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);

现在图像将始终为正方形。要查看侧面的条形图,请绘制与我们的视口一样大的图像:

batch.draw(img, 0, 0, 50, 50);

由于 50(宽度)/50(高度)= 1,图像的比率为 1,因此图像将始终具有相同的宽度和高度。侧面的条形图在我们的视口之外,将以您在此处定义的颜色绘制: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();

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

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

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

如果您愿意了解更多、阅读和查看一些教程并阅读 LibGdx wiki:https://github.com/libgdx/libgdx/wiki

,我希望这会解决一些关于相机和视口的问题