如果您所做的只是在 2D 世界中绘制精灵,那么您基本上需要跟踪两件事,以便决定在屏幕上绘制哪些精灵以及在屏幕上的哪个位置绘制它们。你必须把你的精灵想象成存在于世界上的某个位置,而你在屏幕上看到的只是世界的一个视图,专注于一个区域。
您需要跟踪的两件事是:
- 每个精灵都需要在世界中拥有自己的位置
- 您的“相机”需要跟踪其相对于世界的位置。
所以,假设你有一个很大的世界,2D 坐标 (x, y) 空间为 1,000,000 x 1,000,000 像素(我在这里使用像素作为度量单位,但这是一个任意选择,并且世界无所谓,我只是选择了一个大的)。然后,假设您有一个指向那个世界的“相机”,并且该相机的视图就是您屏幕上显示的内容。相机为您提供的显示尺寸为 1024x768 像素。
还假设您使用箭头键在世界各地移动该相机。
因此,您的世界坐标空间映射到您的屏幕,如下所示:
(0, 0) +x
+------------------>
|
+y |
| * <= example sprite in your world @ coordinates (x=200, y=200)
|
\ /
当您的精灵“向右”移动时,它们会增加x
坐标。当它们“向左”移动时,它们会减小x
坐标。当“向上”移动时,它们会减小它们的y
坐标(因为y
在监视器上向下增加),而当“向下”移动时,精灵会增加它们的y
坐标。
现在,再次,您在我们的屏幕上看到的只是相机对世界的看法。所以,让我们设置相机的左上角在(x=500, y=500)
。这看起来像:
(0, 0) +x
+---------------------------------->
|
+y |
| * <= example sprite in your world @ coordinates (x=200, y=200)
|
|
| +===================+
| | the area |
| | that the camera |
| | "sees" and |
| | shows on your |
| | screen |
| +===================+
\ /
使用该设置,假设相机位于 (500, 500)(即相机视图的左上角,如本例所示,位于世界坐标 (500, 500)。因为相机向您显示大小为 1024x768 的区域,然后对面的右下角为 (500+1024, 500+768) = (x=1524, y=1268)
。
请注意,我们世界中的精灵不在相机的视野范围内。这意味着,当我们在屏幕上渲染相机的视图时,我们不会看到精灵。
相反,如果相机移动到 (200, 200),那么相机的视图区域将覆盖从左上角 @ (200, 200) 到右下角 @ (1224, 968) 的世界坐标,并且看起来像什么像这样:
(0, 0) +x
+---------------------------------->
|
+y | +===================+
| | |
| | * <= sprite |
| | |
| | | <= camera's view of the world
| +===================+
|
|
|
|
\ /
当相机在这个位置时,精灵是可见的。如果精灵是@(500, 500),并且相机在(200, 200),那么当我们在屏幕上绘制精灵时,精灵就会出现在我们屏幕上的坐标300, 300。
为什么?
因为,这确实是您问题的答案,您在屏幕上绘制东西的位置是精灵的世界位置(500, 500),减去相机的位置(200, 200),等于 (300, 300)。
所以,回顾一下:
您使用箭头键(或鼠标,或您想要的任何其他控制方案)在世界范围内移动相机的位置,并通过获取精灵的位置并减去相机的位置来渲染相对于相机位置的精灵位置,并且你得到的是精灵应该出现的屏幕坐标。
但还有一件事...
绘制世界上的每一个精灵确实效率低下。您只需要绘制相机视图内的精灵,否则您将绘制在屏幕上看不到的东西,因此会浪费渲染/CPU/GPU 时间。
因此,当您渲染相机的视图时,您需要遍历您的精灵,检查它们是否“在相机上”(即,它们是否在相机的视图内),并且只绘制如果他们在这个视图中。
为此,您必须获取相机的尺寸(在我们的示例中为 1024x768),并检查精灵的位置是否在相机视图的矩形内 - 这是相机左上角的位置角,加上相机的宽度和高度。
因此,如果我们的相机向我们展示了一个大小为 1024x768 像素的视图,并且它的左上角位于 (200, 200),那么该视图矩形为:
(200, 200) (1224, 200)
+===================+
| |
| * |
| |
| |
+===================+
(200, 968) (1224, 968)
在这种情况下,精灵的位置 @ (500, 500) 在相机的视野内。
如果您需要更多示例,我有一个名为Pedestrians的有效 Slick2D 技术演示,其中包含您可以查看的代码。有关我如何计算应该渲染的世界区域的详细信息,请查看此文件render
中的方法,并特别注意, , ,变量,这些变量对我来说控制着我将要绘制的精灵的区域。还应该注意的是,我的精灵(或“行人”)存在于 a 上,因此它们的大小不是 1 个像素 - 它们有自己的宽度和高度。这为如何决定绘制什么增加了一点复杂性,但它基本上归结为“绘制相机视野内的东西,加上边缘周围的一些额外内容”。startX
startY
stopX
stopY
TileMap
在您自己的机器上克隆 Pedeestrians 存储库,通过向项目添加与任何其他 Slick2D 项目相同的依赖项来使其工作,并播放/修改渲染代码,直到您了解发生了什么。只有通过实践和学习,您才能了解其工作原理的所有细节。好消息是,一旦您弄清楚如何使用这种基本的 2D 世界与相机方法进行渲染,您就会非常了解如何为所有 2D 应用程序渲染图形,因为这些概念可以翻译成所有语言。
我还在我的 YouTube 频道上播放了各种行人视频(最相关的视频可能是这个视频,它显示了我的基本行人被渲染,并且相机四处移动),所以你可以看到这一切看起来像什么,而不必先建项目。