对于水管连接游戏,如何正确检查所有4个相邻的网格而无需回流或使用Update()/ LateUpdate()?

时间:2015-03-09 18:27:57

标签: c# unity3d

我正在尝试编码的游戏是一个管道连接游戏,其中有4个水源(左上角,左下角,右上角和右下角),目标是将它们连接到所有位于的11个建筑物网格的最上面一行。

我设置的网格是一个21 x 9的32x32px正方形列表,每个正方形都包含对null“Pipe”类的引用。我还在Grid< 0>处制作了一个水源(基本上是“hasWater = true”)。用于测试目的。

以下是我正在对Pipe类的插座标记进行操作:

`  public class Pipe {

   bool pipehasTop; // Top outlet flag
   bool pipehasRight; // Right outlet flag
   bool pipehasBottom; // Bottom outlet flag
   bool pipehasLeft; // Left outlet flag
   bool hasWater; // To determine pipe color and whether it can spread to other pipes
   bool outletCount; // No. of outlets (I pipe has 2, T pipe has 3, etc)
   bool connectedCount; // No. of outlets connected to adjacent grid's outlet
   }

旋转是单独完成的,当我按下鼠标中键时,它会根据管道类型(按预期工作)更改标志。

当我没有放置管道时,默认情况下,实例化的网格方块为null。当前的系统是我将按热键选择管道,如果需要可以旋转它,然后通过单击将管道放置到网格上,将空引用转换为选定的管道变体。因此,在我的代码中几乎无处不在,我需要为管道添加“if!= null”:(

我正在使用for循环首先水平遍历每个网格方块然后垂直 - 逻辑是检查每个相邻网格是否匹配标记以及相邻网格是否“hasWater”,如果all返回true则网格输入-question现在有水。

    for(int y = 0; y < rows; y++) {
        for(int x = 0; x < columns; x++) {
            int gridIndex = (y*columns) + x; // Horizontal 0, 1, 2, etc
                if(y > 0 && Grid[gridIndex - columns].pipe != null)
                    if(Grid[gridIndex - columns].pipe.pipehasBottom == true // Check if above grid has bottom flag
                      && Grid[gridIndex].pipe.pipehasTop == true // Check if current grid has top flag
                      && Grid[gridIndex - columns].pipe.hasWater == true) { // Check if above grid has water
                      Grid[gridIndex].pipe.hasWater == true;
                      }
            }
    }

我重复一遍右边,底部和左边的其他3个相邻的瓷砖。

起初我遇到了一个“鬼”水管问题,当管道链断开时,分离的管道将检查仍然有水并重新获得水的相邻网格,然后整个链条确实每组2个或更多的分离管道将自行维持,除非我将管道自行移除,然后才会检查没有水网,从而变得无水。

我通过在检查循环之前运行一个方法将所有pipe.hasWater变为false然后运行相邻检查

进行了小修复

然而,由于检查循环的水平性质,我坚持使用,当一切都是假的并且它逐行检查时,在一个有水的网格上放置一个新管道将不会检查它并放置一个新的在有水的网格左侧的管道也不会检查它。我无法删除“将所有水变为假”的方法,因为它会再次导致“鬼水管”问题。

enter image description here

我已经尝试了几天找到解决方法,这是我能想到的最好的...而且大多数管道检查逻辑都在 Update()和LateUpdate()下... 当我不这样做时,它会中途检查或只是在随机的地方休息。

我似乎无法为这个看似简单的检查找到一个平衡的解决方案。

感谢您的阅读,请帮助我理解这个动态管道检查逻辑!我会继续寻找解决方案。

1 个答案:

答案 0 :(得分:1)

您可能需要的是一种更好的算法来检查有水的管道的连通性。我的第一反应是制作一个算法,该算法基本上遵循来自源的水流并填充每个管道的hasWater标志。如果瓷砖被移除/添加到正确重新计算(如果有水),您可能希望运行此项。我在这里伪代码的是breadth first search

在伪代码中:

reset all hasWater flags to false

//Use a queue object to place the pipes that we are declaring as having water
//but that we still need to check if they have any neighbors that will get water
var pipesWithWaterToProcess = new Queue();

//seed the queue with pipes that connect to a water source (ie. one of the sources in the corners)
foreach waterSource in waterSources
    if exists an adjacent pipe that has an outlet that connects to the water source
        if pipe does not have water already
            add pipe to pipesWithWaterToProcess queue
            flip the has water flag to true
        end 
    end
end

while pipesWithWaterToProcess queue has items
    var currentPipe = pipesWithWaterToProcess.dequeue()
    for each adjoining tile to the currentPipe
        if tile has pipe (newPipe) and newPipe connects to currentPipe
            if newPipe does not have water
                flip the hasWater flag
                add newPipe to the pipesWithWaterToProcess queue
            end
        end
    end
end

假设您有这样的地图:

S-A-B-D-
  |   |
  C-
  |

(线是连接,S是水源)。

这种最终发生的事情是你从水源开始并将管道A添加到队列中。然后你看一下队列,看看有什么东西要处理。所以你拿A出去看看它的邻居。如果B和C连接到A,则声明B和C有水并将它们添加到队列中(因为现在需要检查所有邻居)。然后你做B. B.添加D.然后你做C,但是没有任何管道连接到C.然后你做D,它也没有添加管道。然后你就完成了,所有相关的东西都会显示为有水。