【问题标题】:How Camera works in Libgdx and together with ViewportCamera 如何在 Libgdx 和 Viewport 中工作
【发布时间】:2019-06-09 10:52:28
【问题描述】:

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

  • 如何在 LibGdx 中使用相机?视口的宽度和高度是多少?
  • 什么是视口,如何使用它以及它如何与相机配合使用?

【问题讨论】:

    标签: java camera libgdx viewport


    【解决方案1】:

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

    首先,重要的是您要知道相机使用的是世界单位而不是像素。世界单位不是常规单位。您可以自己定义一个世界单位是多少。以后再说吧。

    首先,我们创建一个OrthographicCameraSpriteBatch 和一个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 世界单位,不管屏幕有多大。要说 Batch 应该画出我们通过相机看到的东西,我们必须调用:batch.setProjectionMatrix(camera.combined);

    (3) 现在我们在位置 0,0 上绘制 img 但是 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);
    

    在 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 World Units 大的图像,SpriteBatch 知道他必须绘制 25 * 4 = 100 像素大的图像。

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

    Box2d

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

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

    什么是视口,如何使用它以及它如何与相机配合使用?

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

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

    首先什么是视口。

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

    添加视口对象:

    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 的比率意味着:对象 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);
    

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

    扩展视口

    也许我们不会在旁边设置栏,然后我们可以使用 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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-05
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2017-09-29
      相关资源
      最近更新 更多