如果你所做的只是在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) 位于摄像机的视图中。
如果你需要更多的例子,我有一个工作Slick2D技术演示,叫做行人,里面有你可以查看的代码。有关如何计算应渲染的世界面积的详细信息,请查看此文件中的方法,并特别注意 、 、 、 变量,它们控制着我要绘制的精灵区域。还应该注意的是,我的精灵(或“行人”)存在于 一个 上,因此它们的大小不是1个像素 - 它们有自己的宽度和高度。这为如何决定绘制什么增加了一点复杂性,但它基本上归结为,“绘制相机视图中的内容,加上边缘周围的一点额外内容。render
startX
startY
stopX
stopY
TileMap
在您自己的计算机上克隆 Pedeestrians 存储库,通过向项目添加与任何其他 Slick2D 项目相同的依赖项来使其正常工作,并播放/修改渲染代码,直到您了解发生了什么。只有通过练习和学习,你才能从它的工作原理中得到所有的小细节。好消息是,一旦你弄清楚了如何使用这个基本的2D世界与相机方法进行渲染,你就会知道如何为所有2D应用程序渲染图形,因为这些概念可以翻译成所有语言。
我还有各种行人视频在我的YouTube频道上运行(最相关的视频可能是这个视频,它显示了我的基本行人被渲染,摄像机四处移动),所以你可以看到这一切的样子,而不必先构建项目。