你问题的第一部分真的很简单。对于每个立方体,如果它与另一个立方体直接相邻,则删除它与该立方体共享的面。
这不应该是性能问题(除了修改和上传更改的顶点数据的成本),因为您只会在放置或删除块时重新计算它。放置和移除方块的效果是相当局部的;它只会影响 6 个相邻的立方体及其本身,所以它应该不是问题。除了处理基于多维数据集的环境所需的明显数据结构外,您也不需要任何专门的数据结构。
建造地形的初始成本可能是一些东西,但这是您可以忍受的一次性成本。将其纳入您的加载时间。如果您在框架空间中进行大量放置和移除,这可能是个问题。
更困难的问题是拆除密封的内部。我的建议:不值得。通过尝试移除密封的内部,放置或移除块成为非本地操作。通过花时间优化批处理计数(尽可能使用纹理图集/数组)和顶点数据,您可能会获得更高的性能。
要移除密封的内部,您需要能够检测内部。因此,您需要维护相邻面的双向图。对于每个面,它将有四个相邻的面。由于位于两个相邻立方体之间而被剔除的面(此前称为“死面”)不应成为图形的一部分。
放置立方体时,您必须更新人脸图的邻接信息。死面需要去除。放置后活面的邻接需要合并由于放置的新块而添加的新面。如果您坐下来找出可能性,那么执行此操作的算法应该相当简单。例如,如果你有这个正方形:
A
+++++
+ +
+ + B
+ +
+++++
面 A 和 B 是相邻的。如果您放置一个新块,则会更改邻接关系:
+++++
+ +
C + +
+ +
A +++++
+++++ D
+ +
+ + B
+ +
+++++
A现在与C相邻,B与D相邻。
移除立方体后,您必须再次更新人脸图的邻接信息。本质上,您必须反转先前的操作。
这个邻接图的要点是:如果图中所有的非死面都连接起来,那么图的恰好一个循环将是可见的;所有其他图形周期都将不可见。图的循环是一组直接或间接相互连接的面。
最大的问题是:你如何找到可见的循环?下面的算法假设方块是由实体放置/移除的。这意味着放置的任何块的至少一个面是可见的。这也意味着任何通过移除块而变得活跃的死面都是可见的。
当您放置一个块时,您可以创建一个或多个新的面循环。为了检测到这一点,您首先找到您通过放置块创建的所有非死面(不直接与某物相邻的面)。其中至少有一个是可见的;找到那张脸。
然后,对于新块上的每个其他非死面,使用 A*(A 星)图搜索来找到该面。A* 是一种基于优先级队列的图搜索算法。在这种情况下,算法的“距离”是当前人脸所在的正方形与可见人脸所在的正方形之间的距离。
如果 A* 找不到人脸,那么您就知道您搜索过的每个人脸(您可能应该在测试它们时将它们存储在缓冲区中)是不可见循环的一部分,因此可以被剔除。您应该将这些面标记为不可见以供以后参考。
删除块要容易得多。当你移除一个块时,块的至少一个面必须是可见的(参见上面的假设)。因此,如果要移除的块有一些不可见的面,则循环中的每个面(包括那些不可见的面)都必须变为可见的。因此,在移除块之前,请检查它是否有任何不可见的面。如果有的话,使用深度优先搜索来查找该循环中的所有面,并将它们放入缓冲区中。移除块后,所有这些面现在都变得可见。
现在,如果你能够传送方块,事情就会变得更加复杂。当您放置一个块时,该块的所有面都可能不可见。所以你需要做的是在世界的某个地方找到一张可见的脸。然后像往常一样对那张脸进行 A* 搜索。如果可见的脸在附近的某个地方会很好,所以搜索不必走得太远。
移除后,您要做的就是找到与块相邻的所有不可见面循环。然后你需要像以前一样找到那一张可见的脸。然后你移除块并用 A* 搜索这些循环,看看它们是否能找到可见的脸。那些可以看到的周期。那些不可能的周期是不可见的。
此外,您需要有一个特殊情况来删除没有活动面的块(即:完全嵌入其他块中)。这将创建一个不可见的 6 面循环。
也许现在你明白为什么它可能不值得努力了吗?老实说,除非你手头有实际的分析数据表明你需要这个,否则我强烈建议你不要这样做。你可能会做比必要的工作更多的工作,并且可能会在不相关的事情上花费大量时间。
现在,我即兴写了这篇文章;我想到了我能用的最简单的算法。我还没有研究过这个算法的可能改进,比如先发制人地找到可以创建内部的块放置,或者找到如果移除会使内部可见的块。所以我坦率地承认这个算法是相当蛮力的。但是找到一个更好的需要一些努力,所以再一次,除非你有分析数据说你需要这样做才能达到你想要的性能,否则我建议不要这样做。