Это поведение, которое вы ищете?
Если у вас есть двумерная сетка байтового типа, вы можете использовать DFS или BFS для достичь этого. В моем случае я создал класс Cell со свойством Value, которое при его установке автоматически обновляет текст и цвет ячейки.
Затем я создал диспетчер сетки, хранящий 2D-сетку ячеек. Функция триггера находится в диспетчере. Всякий раз, когда я запускаю определенную ячейку, запускается DFS для обновления, начиная с этой ячейки. У лога DFS c есть условия для проверки границ и стен, а также ограничения переполнения водой.
void Trigger(int x, int y)
{
bool[,] visited = new bool[yCount, xCount];
for(int i=0; i<yCount; i++)
{
for(int j=0; j<xCount; j++)
{
visited[i, j] = false;
}
}
DfsUpdate(y, x, visited);
}
void DfsUpdate(int i, int j, bool[,] visited)
{
// Check out of bounds
if (i < 0 || i >= yCount) return;
if (j < 0 || j >= xCount) return;
if (visited[i, j]) return;
// Mark as visited
visited[i, j] = true;
if (cells[i, j].Value == 55) // Its a wall
return;
if (cells[i, j].Value == 0)
{
// Needs 1 update and return
cells[i, j].Value++;
return;
}
// Restrict upto 4 if its water
cells[i, j].Value = (byte) Mathf.Min(cells[i, j].Value + 1, 4);
// Recursively call neighbouting cells
DfsUpdate(i + 1, j, visited);
DfsUpdate(i - 1, j, visited);
DfsUpdate(i, j + 1, visited);
DfsUpdate(i, j - 1, visited);
}
Вы также можете использовать BFS, но DFS работает нормально, и реализация проще в случае DFS.
Редактировать:
Теперь для заполнения сетки требуется 72 клика. Проверьте в левом нижнем углу, чтобы увидеть количество щелчков мыши.
Я изменил код. Теперь, когда я нажимаю на ячейку, если она уже 4 (заполнена), она находит ближайшую сетку, которая не полностью заполнена, и добавляет 1 к ней, в противном случае она заполняется сама. В методе Update я выполняю итерацию по сетке с определенной скоростью и проверяю, есть ли ячейки, имеющие соседа, так что их уровни воды имеют разницу в два. Я заполняю эту ячейку и отмечаю ее как обновленную, чтобы они не обновлялись снова в текущем кадре.
Метод обновления сетки - это простая BFS, которая добавляет 1 к ближайшему незаполненному соседу, если таковой существует .
В методе обновления с использованием таймера при каждом пересечении определенной задержки я перебираю сетку, чтобы выровнять различия в уровне воды.
Вот код.
void GridUpdate(int i, int j)
{
bool[,] visited = new bool[yCount, xCount];
Queue<int> iQ = new Queue<int>();
Queue<int> jQ = new Queue<int>();
iQ.Enqueue(i);
jQ.Enqueue(j);
while(iQ.Count > 0)
{
int si = iQ.Dequeue();
int sj = jQ.Dequeue();
if (!CheckBounds(si, sj)) continue;
if (cells[si, sj].Value == 55) continue;
if (cells[si, sj].Value < 4)
{
cells[si, sj].Value++;
return;
}
// Up
iQ.Enqueue(si - 1);
jQ.Enqueue(sj);
// Down
iQ.Enqueue(si + 1);
jQ.Enqueue(sj);
// Left
iQ.Enqueue(si);
jQ.Enqueue(sj - 1);
// Right
iQ.Enqueue(si);
jQ.Enqueue(sj + 1);
}
}
void Update()
{
timer += Time.deltaTime * 1000f;
if (timer >= updateDelay)
{
timer -= updateDelay;
bool[,] updated = new bool[yCount, xCount];
for (int i = 0; i < yCount; i++)
{
for (int j = 0; j < xCount; j++)
{
if (updated[i, j] || cells[i,j].Value == 55) continue;
if (CheckBounds(i-1, j) && !updated[i-1, j] && cells[i, j].Value - cells[i - 1, j].Value >= 2)
{
updated[i - 1, j] = true;
cells[i - 1, j].Value++;
cells[i, j].Value--;
}
else if (CheckBounds(i+1, j) && !updated[i + 1, j] && cells[i, j].Value - cells[i + 1, j].Value >= 2)
{
updated[i + 1, j] = true;
cells[i + 1, j].Value++;
cells[i, j].Value--;
}
else if (CheckBounds(i, j-1) && !updated[i, j-1] && cells[i, j].Value - cells[i, j-1].Value >= 2)
{
updated[i, j-1] = true;
cells[i, j-1].Value++;
cells[i, j].Value--;
}
else if (CheckBounds(i, j+1) && !updated[i, j + 1] && cells[i, j].Value - cells[i, j + 1].Value >= 2)
{
updated[i, j + 1] = true;
cells[i, j + 1].Value++;
cells[i, j].Value--;
}
}
}
}
}
// Checks if a given i and j are not out of bounds of the grid
bool CheckBounds(int i, int j)
{
if (j < 0 || j >= xCount) return false;
if (i < 0 || i >= yCount) return false;
return true;
}
Надеюсь, это поможет!