游戏引擎学习第87天
当直接使用内存时,可能会发生一些奇怪的事情
在直接操作内存时,一些意外的情况可能会发生。由于内存实际上只是一个大块的空间,开发者可以完全控制它,而不像高级语言那样必须遵守许多规则,因此很容易发生错误。在一个具体的例子中,本应使用临时存储的内存区域,但错误地使用了存储大小作为内存指针,尽管这种做法本应导致崩溃,却意外地没有崩溃。
这个错误之所以没有导致崩溃,是因为临时存储大小恰好是一个合法的内存边界(比如1GB),因此它指向了一个合法的内存区域。即使实际的存储内存与这个内存边界并不匹配,系统依然允许访问这个内存区域,尽管这实际上是错误的做法。由于该内存区域之前没有被分配任何数据,所以程序可以正常写入并执行,这就造成了一个“幸运”的情况,尽管这种错误本应导致崩溃。
这种情况展示了内存管理中的潜在风险,因为错误的类型转换可能会导致不可预料的结果。在实际的代码中,应该使用正确的指针进行内存初始化,而不是错误地使用存储大小作为指针。尽管这次错误没有立即引发崩溃,但实际上它是一个严重的错误,应该及时修正。
回到我们之前的工作,即制作无缝地面瓷砖
在继续进行地面纹理的处理时,首先需要将现有的纹理从带有接缝的状态转换为无缝的状态,以确保它们与相邻的区域始终对齐,不显示边界上的接缝或伪影。虽然看起来这可能有些复杂,但由于架构的设计,这个过程实际上并不难。
接下来,还需要解决另一个问题,这个问题相对更具挑战性,即如何处理性能问题,特别是如何让纹理生成在后台进行,而不会影响前台的性能。这个问题暂时不会处理,重点是继续优化和调整。
在纹理缓存方面,目前缓存中的地面纹理不会被清除,导致当缓存中的纹理用尽时,系统就没有足够的纹理来填充。这就需要实现一个机制来清除不再需要的旧纹理,以腾出空间来生成新的纹理。
这个清除旧纹理并生成新纹理的机制是接下来的任务,它涉及到设计一个有效的“驱逐”策略来管理纹理缓存的内容,确保系统在缓存用尽时能自动回收并生成新的纹理。
Blackboard: 如何制作无缝瓷砖
首先,目标是使地面纹理无缝拼接。目前我们正在将软边缘的纹理“撒入”到瓷砖中,通过这种方法产生漂亮的地面纹理,但问题在于,这些纹理被撒入时没有考虑到硬边界的限制。因此,目标是将纹理的接缝处理为无缝,使得所有相邻的瓷砖之间的纹理能够对齐。
为了解决这个问题,可以采取的方式是将整个3x3区域的纹理撒入,最终只提取中间部分。这样做的前提是保证每个瓷砖的纹理与其周围的瓷砖一致,确保纹理能够顺畅地拼接。这种方法有效的原因在于,如果我们确保每个瓷砖的处理顺序一致,就能保证所有的重叠部分一致,从而实现无缝拼接。
此外,由于现有的位图代码已经处理了裁剪,我们无需做额外的处理,只需设置裁剪区域,进行纹理撒入。裁剪会提前剔除不需要的部分,避免浪费内存和计算资源。因此,在优化之前,现有的裁剪机制就已经能为实现无缝拼接提供一定的性能提升。
遍历3 * 3网格中的瓷砖
为了修复无缝拼接的地面纹理,计划的做法是对现有的处理方法进行修改。具体而言,目标是使用3x3区域来进行纹理撒入,而不只是填充中间的部分。为了实现这一点,需要使用一个随机种子,并结合当前的块坐标(chunkX 和 chunkY)来生成新的合成坐标。尽管目前不涉及Z轴处理,Z轴的坐标将始终保持不变,因为当前的工作不需要在三维纹理中处理Z轴的无缝拼接。
对于X轴和Y轴,将循环遍历每个块,从当前的块坐标出发,首先往回一步,再向前一步。这样就能覆盖一个3x3的区域,确保邻近区域的纹理能够无缝衔接。在执行这些操作时,选择的循环顺序并不重要,只要保持一致性,就能实现无缝拼接。
接下来,继续使用现有的绘制循环来完成纹理的撒入,只不过这次是覆盖整个3x3的区域,而不仅仅是中心部分。最终的任务是确保中心位置能够准确反映不同块之间的关系,从而保证纹理的无缝连接。
确保中心正确反映出我们处于不同的区域
为了计算中心点并进行无缝拼接,决定修改循环结构,采用动态计算的方式来处理块的偏移量。具体来说,循环的偏移量从 -1 到 1,将每次偏移与当前的块坐标(chunkX 和 chunkY)结合。这使得可以在每次迭代中动态计算新的块坐标,从而生成正确的纹理区域。
通过这种方式,可以确保在X和Y方向上处理所有9个区域(包括 -1、0 和 1)。此外,还可以根据需要将Z坐标添加到计算中,尽管目前Z轴的处理并不影响无缝拼接。
在计算这些块坐标后,接下来需要确定纹理图像的中心点。具体而言,需要考虑如何准确地计算位图的实际中心,以确保在纹理的生成过程中无缝拼接得以实现。
Blackboard: 中心的考虑
在之前的实现中,使用了位图中心来决定纹理的绘制位置,从中心点开始向外扩展。但是,随着每个纹理块的独立处理,实际上每个块的“中心”并不再是固定的,而是每个块自己相对于周围区域的中心。因此,需要重新计算每个区域的中心点,以便在每个独立的纹理块上正确地进行操作,而不是直接使用原始的位图中心。这种变化使得每个纹理块的处理更加灵活,能够适应无缝拼接的需求。
改变中心的含义
为了实现无缝拼接,需要调整计算中心点的方式。原本的中心点是固定的,但现在每个纹理块的中心点应该是该块的相对中心。因此,需要根据每个块的位置调整中心点,即从原来的中心点减去一个偏移量,然后根据偏移量来确定新的中心点位置。这一过程通过调整每个块的宽度和高度,并根据每个块的具体位置来调整随机种子的值,从而保证每次生成的纹理块使用相同的随机偏移量,确保纹理块间的无缝拼接。
在游戏中查看结果并检查代码
在检查生成的纹理时,发现它们并不无缝,仍然存在一些问题。分析后,发现问题出在随机种子的计算上,尽管应该使用基于块的绝对索引来生成一个固定的随机种子,但是生成的中心点还是存在偏差。
具体来说,中心点的计算方法应该是:从纹理的顶部开始,减去一半的宽度和高度,之后根据当前块的偏移量调整。然而,原先的偏移量计算有误,导致了纹理拼接不准确,产生了接缝问题。
修正计算
发现之前的计算有误,问题在于块的偏移量应该是从-1、0到+1,而不是从0、1、2开始。因此,中心点的计算需要根据正确的偏移范围进行调整。原本的计算错误导致了不正确的移动,无法正确定位到左上角和右下角。
调整后,从中心点开始的计算将正确地将纹理从左上角移动到右下角,解决了之前的问题。
看看我们目前的进展
当前的情况还是没有解决问题,纹理的对齐看起来仍然偏差较大,说明存在较为严重的逻辑错误。由于目前还没有完善的调试工具,问题只能通过直觉来推测,虽然问题不应太难解决。需要进一步检查和调整,确保各部分正确对齐并符合预期。
再看一遍,看看有什么不同
发现了一个问题,原本的代码中有一部分没有被使用,导致计算出错。需要将相关部分重新启用,以确保计算的正确性。这个问题非常明显,应该能够通过调整来解决。
因为我们忘记使用新的中心了
意识到之前的错误,修改代码时没有仔细检查,导致了计算问题。原本应该使用上角点进行偏移计算,而不是直接应用宽度和高度的随机值。这提醒了在修改代码之前,要先确认每一部分的作用,避免不必要的错误。
我们现在在X轴上是无缝的,但Y轴上不是
目前在X轴方向已经实现无缝对接,但Y轴方向仍然存在问题。看起来是Y轴的计算出现了错误,可能是因为Y轴方向的偏移处理存在反转或者其他计算上的问题,导致没有正确对接。
我的X Y轴都有问题
代码的ChunkX,ChunkY,ChunkZ 好像没使用
忘记使用ChunkX,ChunkY,ChunkZ
关闭草丛,看看我们在Y轴上的处理有何不同
在检查Y轴的计算时,发现bitmap的中心和偏移量计算是正确的,应该能够正确绘制。然而,问题依然存在,可能是因为Y轴的某些计算方式不对,或者存在其他未发现的逻辑问题。为了更简单地调试,已将某些元素从计算中移除,但Y轴的计算仍然没有解决。
考虑一下这个问题,尝试交换X和Y,看看哪个是主要轴
在调试时,交换X轴和Y轴的计算顺序,发现问题并不在于计算顺序或重叠问题,而是在Y轴的处理方式上。因此,可以确认问题出在Y轴的处理逻辑上,需要重新审视Y轴的计算方法。
我们的Y轴处理出了什么问题?
关于Y轴的处理方式似乎没有问题。当进行“ChunkY”操作时,看起来是正确的。同时,涉及到宽度和高度的部分也显示为正确。不过,需要考虑一些细节,尤其是在高度的计算上,虽然目前看起来是正确的。
我们的边缘可能顺序错了
由于地面块的填充方式与坐标系统的翻转有关,导致堆叠顺序出现问题。猜测可能是由于边界对齐的顺序错误,具体来说,顶部和底部的边界可能被颠倒了,因为方向处理不当。
检查一下是否是这种情况(在游戏中)
检查后发现,问题确实是由于Y轴翻转导致的,需要始终考虑到这一点。现在,地面纹理已经可以无限平铺,虽然纹理本身并不是特别理想,因为在合成过程中没有做过多优化,但目前的效果已经不错。为了使效果更加直接,考虑将纹理固定为某一种类型,比如草地或石头,这样效果会更好。
尝试了将纹理类型统一后,发现效果提升了不少,尽管在某些地方,像是某些接缝处,可能会有一些伪影,看起来有些奇怪,这可能是因为某些细节问题。不过,整体效果已经相当不错了,随着更多纹理的加入,以及将区域划分为不同类型(如草地、石头等),效果将更加完善。这些是未来需要进一步实现的功能。
恢复草丛
决定将纹理切换回草地并重新添加毛球,同时确保毛球没有重叠问题,并计划暂时停止改进这一部分。这个系统可以在未来逐步扩展。观察到纹理中的毛球看起来有些集中,可能是因为当前使用的随机数生成器在生成过程中出现了问题,导致了随机性不足,进而出现了明显的规律性。
虽然不认为这会是一个严重问题,但可以看到随机数生成器的漏洞。如果问题确实与随机数生成器有关,那么可能需要进一步调整。此外,另一个潜在问题是如果精灵周围有透明区域,也可能导致这种效果。
显示缓冲太小改大一点
给它一些松动空间
考虑到可能出现的问题,决定为毛球添加一些“松散”参数,以检查是否能够解决集中现象。虽然一开始认为毛球之间需要有一定的接触,但在使用中心点后,意识到这种方式并不完全适用。因此,推测问题可能与随机数生成器有关,考虑在未来使用更高质量的随机数生成器。
目前,认为系统已经处于良好状态,整体效果可以接受,因此决定开始处理下一个问题。不过,决定在开始之前先解决一些其他小问题,确保继续推进。
恢复打开石头绘制
强制我们进入一个很快就会没有瓷砖的情况
为了更快速地看到问题的发生,决定通过调整瓦片数量来加速这一过程。之前需要走很长一段路才能看到瓦片用完的情况,因此现在通过减少瓦片的数量,使得在短时间内就能观察到瓦片耗尽的情况,从而验证驱逐机制是否正常工作。
调整了瓦片数量后,虽然最初的猜测并不完全准确,但通过进一步减少瓦片数量到16个,终于实现了快速耗尽瓦片的效果。接下来,目标是确保能够通过重复使用旧的瓦片来填补空缺。
通过重用旧瓷砖来填充每个空的缓冲区
首先,现有的循环已经能够进行地面块填充,但问题在于目前没有有效的方式在预分配的16个缓冲区填满后获取更多的空缓冲区。因此,目标是找到一种方法,能够确定目前存在的16个块中,哪个最不重要,最适合被替换。
考虑到目前的情况,虽然有多种解决方案,但由于还处于初期阶段,决定暂时不使用过于复杂的策略(比如LRU算法),而是采用一种简单且直接的方法,即遍历整个缓冲区。虽然这种方法效率较低,但可能是目前最合适的选择,避免过早引入复杂的机制。
保留最远离相机的区域
在这个过程中,目标是通过遍历缓冲区来确定哪个地面块最远离相机,从而决定替换哪个块。通过计算每个块相对于相机的位置,使用相对位置的平方长度来衡量与相机的距离。对于每个地面块,只考虑其XY平面的位置,而不关心高度。
为了实现这一点,首先需要检查缓冲区是否有效。如果缓冲区从未被使用过,那它将成为最佳选择,因为它是空的,最适合替换。接着,初始化一个变量来存储最远的缓冲区,最初设定为一个非常大的值(比如最大值),确保该值不会被遗漏。
虽然这种方法有点昂贵,但目前并不关心性能,更多的是确保功能正常运作。一旦性能优化变得更为关键时,可以考虑通过存储上次计算的结果来减少计算量。
引入Real32Maximum
决定使用平台定义的最大浮动值(real32
)来初始化最远缓冲区的距离。这个最大值是在limits.h
头文件中由C编译器定义的,具体值取决于当前编译平台。当然,如果需要的话,也可以手动定义这个最大值,因为它是32位浮动数值。
通过将最远距离初始化为最大值,可以确保在选择替换缓冲区时,如果没有已经选中的缓冲区,就会优先选取一个新的缓冲区。这种方式保证了即使没有其他缓冲区,依然能够正确地做出选择。
找到最适合替换的缓冲区
在这段代码中,首先设置了最远缓冲区的初始值为最大浮动值(real32
),确保没有任何缓冲区会优先被选中。然后,通过计算每个地面块的相对距离,比较它们与当前最远缓冲区的距离,选择距离相机最远的缓冲区进行替换。
这个方法是非常基础的,属于暴力破解式的实现,遍历所有16个地面缓冲区,每次都进行比较。尽管这种方式非常低效,但由于目前还不关心性能,所以决定暂时使用它。未来在引擎优化时,会考虑重新设计替换逻辑,以避免过早进行性能优化,毕竟现在的实现方式可能会随着需求变化而被改进。
编译并查看代码
在这段代码中,首先初始化最远缓冲区的距离为零,意味着任何缓冲区都将被认为比这个初始值更远。然后,通过遍历所有地面缓冲区,检查每个缓冲区是否与当前绘制的区域相同。如果是相同的区域,就跳过该缓冲区,因为不需要填充它。如果是不同的区域,就计算该缓冲区与相机的距离,并与当前已找到的最远缓冲区进行比较。如果该缓冲区更远,就更新最远缓冲区。
如果缓冲区无效(没有内容),则选择该缓冲区进行填充,因为我们不希望填充已经有内容的缓冲区。最终,通过这种方式确保填充最适合的缓冲区,同时避免不必要的填充。
看起来16个地面缓冲区太少了
目前的填充系统看起来已经基本正常,之前设置的16个缓冲区显然太少,导致地面区域填充不足,修改为32个缓冲区后效果有所改善,可以持续走动而不会耗尽地面。然而,可能需要进一步优化绘制的范围边界,以避免溢出。
在当前的实现上,暂时不打算增加更复杂的地面元素如草地或石块的生成,因为这些更像是与世界生成相关的内容,可能会在之后的开发阶段处理。总的来说,系统已经取得了较好的进展,接下来可以考虑进入新的开发任务。
最后处理细节图层
发现了一个问题,地面上的某些区域被覆盖了,这主要是由于有两个地面层的缘故,导致细节层的内容被地面层覆盖。为了解决这个问题,可以将地面处理分成两次迭代,先处理底层地面,再处理细节层的地面,这样就能够避免覆盖问题。
通过这种方式,可以确保细节层总是位于底层地面之上。调整之后,重新测试时,发现问题已解决,效果变得更加理想。虽然这个解决方案目前有效,但以后可能需要进一步优化地面合成器,使其更智能,处理更多复杂情况。不过,这个方法足以解决当前的问题。
接下来该做什么?
可以考虑开始处理地面块的多层Z轴支持。这是一个值得着手的方向,而且也能为明天的工作做好铺垫。
另外,还可以尝试实现一个功能,在代码重新加载时自动更新。通过在Win32层实现代码重新加载时,增加一个智能检测机制,能够在代码重新加载后自动触发重新生成的操作,这样可以提高开发效率,避免手动干预。
让代码重新加载时告诉我们何时加载完成
在Win32层,可以加入一个变量来标记可执行文件是否已经重新加载。当通过游戏内存传递数据时,可以引入一个类似于“executable reloaded”的标志。这会帮助在调试过程中执行特定的操作,例如清空缓存。
具体做法是:当检测到可执行文件已经重新加载时,通过该标志来清空相关缓存。这样做能够确保在重新加载后,缓存中的内容被重置,以便进行新的操作。
实现时,可以在Win32的代码加载部分检查是否执行了重新加载,如果是,就将该标志设置为true,表示重新加载了可执行文件。如果没有重新加载,则保持为false。这样,简单的标志机制能够帮助在特定情况下执行清理操作。
测试新改进的实时代码编辑
通过启用即时代码编辑,可以在修改地面渲染逻辑时立即查看效果。例如,当关闭草地渲染(即不再显示草地丛)的功能时,修改后的效果会立即生效,不需要重新编译。这种即时反馈使得调整和实验变得更加高效,尤其在调试和优化时,可以节省大量的时间。即时代码编辑不仅提高了开发效率,而且使得开发过程更加有趣,即使只是为了体验这种不需要等待编译结果的乐趣。
有些担心我们绘制的内容太多了…
在调试时,怀疑绘制的区域过多,因此决定进一步调查为什么16个缓冲区不够用。通过修改绘制矩形的调用,尤其是绘制矩形轮廓的部分,尝试找出绘制过多区域的原因。这有助于更精确地控制绘制区域,避免不必要的绘制工作,进而优化性能。
调整代码
为了调试,将绘制缓冲区的操作提前到上方,这样可以直接查看调试区域。尽管这个顺序不符合理想的逻辑(因为通常填充和绘制应该分开),但由于绘制操作会在一个独立的线程中执行,所以不需要过多关注顺序上的细节。这一改变有助于更好地观察调试信息。
计算屏幕上能容纳多少个地面缓冲区
通过调试,发现16个块实际上不足以覆盖所有显示区域,尽管32个可能过多,16个的数量确实不够。调整后,边界显示清晰,结果令人满意。
评估我们当前的情况
在完成当前的调整后,整体状态非常良好,下一步将开始处理与RZ层相关的问题,可能会在明天进行。虽然需要继续观察内存占用和地面块的大小是否合适,但目前的工作进展顺利。最终,决定暂时注释掉一些代码,以便需要时重新启用。整体来说,地面纹理现在运行正常,达到了预期效果
随机生成的地板瓷砖已经缓存了吗?
它们已经被缓存了
你认为像使用static_cast来增加更多检查(例如从int到指针的转换)相比标准的C风格转换有用吗?它不会忽略所有类型检查吗?如果使用static_cast,难道不是一开始就能发现那个bug吗?
在讨论是否使用 static_cast
来增加类型检查时,提到需要权衡在代码中加入新特性的价值。虽然 static_cast
比 C 风格的类型转换更严格,但并不是所有情况下都值得引入更多检查。尤其是在考虑到未来语言变化的情况下,比如 C++ 可能会逐渐被淘汰,可能会转向某种包含 C 特性的语言,但不再包含 C++ 的复杂性,因此尽量避免在代码中加入不必要的 C++ 特性可能是明智的。
关于引入更多检查的实际意义,强调了应该只在频繁出现且难以调试的错误上增加防护。如果某个问题很少出现且不容易调试,就不需要花费过多时间去处理。实际工作中,不应花费过多时间去防范不常见的错误,因为这可能只是浪费时间。比如,遇到一个流中的 bug,虽然出现过一次,但不代表需要专门添加检查,只要这类错误不频繁发生,就不必专门做防范。
如果遇到的错误变得频繁或影响开发效率,那么增加检查措施就变得更有意义。
你认为这种团块感实际上是由于从区块中心的喷洒距离造成的吗?
在讨论草丛的聚集性时,最初怀疑是由于草的分布受到了随机数表的影响。为了解决这一问题,可以通过使用 C 的随机数生成器来进行检查,尽管 C 的随机数生成器本身并不完美,但它不会遇到随机数表的问题。通过调整参数,可以观察草丛的分布,发现并不如预期的那样聚集。后来,发现问题其实是因为在之前的实现中,草的绘制没有执行第二次渲染,从而导致相邻的对象覆盖了草的部分区域,而不是随机数本身的问题。
修复了这个渲染问题后,草的分布看起来更自然了,尽管随机数表依然不完美,但问题并不出在这里。最终决定回到一个合适的草的数量,而草通常应该只出现在草地上,这部分的细节可以稍后再处理。
你知道为什么有时树木会晃动吗?
当前游戏没有真正的渲染器,只使用了一个简单的位图渲染调用,这导致屏幕上出现了一些视觉伪影。这些伪影的出现是因为没有进行物体的排序处理,物体的显示顺序取决于它们被处理的顺序,因此可能会出现物体穿透其他物体的情况。另一种问题是物体的位置没有进行子像素精度处理,物体的坐标是浮动的,但会被强制四舍五入到整数坐标。这样,物体在移动时会出现轻微的抖动,尤其是在物体的两个坐标分别进位到下一个整数时,彼此之间的距离会发生变化。这些问题在未来的渲染器中会得到解决,渲染器会支持子像素精度,从而使运动更加平滑,特别是在处理缓慢移动的物体时,这也会改善游戏的视觉效果。
是什么导致了延迟?
当前的延迟问题有两个主要原因。第一个原因是背景块的生成没有在独立的线程中进行,而是在需要的时候同步生成,这个操作非常耗费资源,因此导致了延迟。如果将这些操作放到独立线程中,处理就不会影响帧率。然而,即便如此,这个操作本身的开销不足以造成明显的帧率影响。真正导致显著延迟的原因是,目前生成地面块时使用了非常慢的位图填充过程,这是将位图渲染到屏幕上最低效的方式,且此过程中没有进行任何优化。除此之外,编译模式也没有启用发布模式(Release Mode),如果切换到发布模式,程序性能将有所提升,延迟会减小。例如,在构建过程中通过调整编译选项来进行代码优化,就可以明显减少延迟,让卡顿时间变短。总之,这些延迟主要是因为没有进行足够的代码优化所导致的。
现在地面瓷砖中还会看到背景颜色透过吗?
目前,背景颜色透过地面瓦片的情况应该已经不再出现,但还没有做完全的检查来确保这一点。问题更多地与地面瓦片的生成方式有关。为了更容易地检查这个问题,可以使用一种明显的颜色(如鲜艳的粉红色)作为临时标记,虽然这不是一种完美的检查方法,但它能帮助更清楚地看到问题区域。通过这种方式,可以确定是否还有背景透过地面瓦片显示出来。尽管如此,也能发现当瓦片尚未完全填充时,它们在屏幕上出现时会闪烁。未来可能需要进一步优化,做出预测,提前加载尚未显示的瓦片,以避免类似问题的发生。
这个区块代码已经准备好添加地面上的洞了吗?
当前的地面块生成代码已经为添加地面上的洞洞做好了准备,可以创建任意大小的洞。实现这个功能只需要修改绘制位图的代码,通过调整 Alpha 通道的值来切割出洞。具体来说,使用一个填充透明度(Alpha)的位图方法,如果将源 Alpha 通道的值反转,并与目标 Alpha 通道相乘,就能有效地减少源图像的透明度,从而实现打洞效果。这是一种非常简单的方式,可以根据需要生成不同形状的洞并穿透显示下面的内容。
通过这种方法,可以在地面块中轻松地添加洞洞,并看到透明区域,原本绘制的背景颜色(如粉红色)会在洞中显示出来。实现这一功能时,创建洞的过程并不复杂,只需用一个指定形状的位图来“打洞”。
你能否编写代码以确保特定的帧率,但利用额外的空闲时间在后台生成地面纹理,可能先生成低质量版本以避免没有纹理?
可以编写代码来保证特定的帧率,同时利用多余的时间在后台生成地面纹理,甚至可以生成低质量的版本以避免完全没有纹理。实现这一目标有两个方面:低质量与高质量纹理的生成,以及帧率的保证。现代处理器,尤其是像树莓派这样的四核处理器,要求有效利用多核处理能力。把这些任务放在主循环中进行帧率限制并不是最优选择。为了充分利用处理器的多核,通常需要将任务分配给多个线程处理,这样可以利用空闲的 CPU 时间。通过这种方式,能够更高效地进行后台操作,而不是简单地通过主循环来限制帧率。
回顾,展望未来并结束语
游戏的开发进展顺利,目前已经完成了一部分地面纹理的生成,并且实现了可以处理任意数量Z层的功能,允许在多个层次上生成地面纹理。这个新系统支持缓存任何位置的瓦片,增加了灵活性。在未来的工作中,计划开始进行最终的Z层处理,尤其是实现房间之间的视角关系,让上层房间能够俯视下层房间。这项工作会需要一定的时间和精力,但这是开发过程中重要的一步。
接下来,计划继续进行图形优化和功能完善,确保开发的各个模块能够顺利协同工作。之后还将继续完善地面纹理和Z层的交互效果。