Как определить равновесие в этом конкретном c графе узла моделирования воды - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть сетка на основе массива, которая представляет местность, и я пытаюсь смоделировать распространение воды по местности. Сетка представляет собой массив байтов ax, y, z, в котором каждый байт представляет различный тип местности, в этом случае значение 55 представляет стену solid, 0 представляет воздух, и от 1 до 10 представляют количество воды внутри данной ячейки. В этой системе я заполняю одну ячейку водой, щелкая по ней, что приводит к увеличению количества воды на 1. Если есть соседние ячейки с меньшим количеством воды, вода течет к ним и пытается удержать уровень (одна ячейка не может подняться до 4 воды до того, как все остальные доступные ячейки достигнут 3).

Это вид сверху вниз, и когда я говорю уровень воды, я обращаюсь к байтовому значению (от 1 до 10) ячеек

Я использую аналогичный метод для слива воды из системы, щелкнув одну ячейку для слива воды, можно будет сливать воду из всех остальных ячеек до тех пор, пока все они не будут на одном уровне, прежде чем другим позволят понизить уровень воды.

Однако я теперь возникают проблемы с разрушением стен, которые содержат много воды, и распространение воды. Я использую комбинацию стока и потока, сливаю воду из большого бассейна и стекаю в пустые пространства.

Вот видео системы, работающей, чтобы дать лучшую идею: https://www.youtube.com/watch?v=o2KG1p6gj4E

вот соответствующий код:

    public IEnumerator FlowRoutine(int x, int y, int z, Dictionary<Vector3Int, byte> dictcrossed)
    {
        V3IntByte ValidWaterFlowCell = new V3IntByte();

        ValidWaterFlowCell = FindNextFlowCell(x, y, z, dictcrossed);

        if (ValidWaterFlowCell.pos != InvalidVector2 )
        {
            GridArray[x, y, z] -= 1;
            GridArray[ValidWaterFlowCell.pos.x, ValidWaterFlowCell.pos.y, ValidWaterFlowCell.pos.z] += 1;
            dictcrossed.Add(ValidWaterFlowCell.pos, GridArray[ValidWaterFlowCell.pos.x, ValidWaterFlowCell.pos.y, ValidWaterFlowCell.pos.z]);

            yield return StartCoroutine(FlowRoutine(ValidWaterFlowCell.pos.x, ValidWaterFlowCell.pos.y, ValidWaterFlowCell.pos.z, dictcrossed));

        }


        UpdateAllButtons();

        yield return null;
    }
    public V3IntByte FindNextFlowCell(int x, int y, int z, Dictionary<Vector3Int, byte> dictzito)
    {
        V3IntByte SelectedCell = new V3IntByte(InvalidVector2, 0);

        Vector3Int WaterFinder = KeepPosInBounds(new Vector3Int(x - 1, y, z));

        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] + 1 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x, y + 1, z));

        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] + 1 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x + 1, y, z));

        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] + 1 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x, y - 1, z));

        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] + 1 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }
        ///
        WaterFinder = KeepPosInBounds(new Vector3Int(x - 1, y, z));

        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > 0 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x, y + 1, z));
        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > 0 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x + 1, y, z));
        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > 0 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x, y - 1, z));

        if (GridArray[x, y, z] > GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > 0 && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
            return SelectedCell;
        }

        return SelectedCell;
    }


    public IEnumerator DrainRoutine(int x, int y, int z, Dictionary<Vector3Int, byte> dictdrained)
    {
        dictdrained.Add(new Vector3Int(x, y, z), GridArray[x, y, z]);

        V3IntByte HighestValidAdjacentWater = FindHighestAdjacentWater(x,y,z,dictdrained);

        if (GridArray[x, y, z] < HighestValidAdjacentWater.water )
        {
            GridArray[x, y, z] += 1;
            GridArray[HighestValidAdjacentWater.pos.x, HighestValidAdjacentWater.pos.y, HighestValidAdjacentWater.pos.z] -= 1;

            yield return StartCoroutine(DrainRoutine(HighestValidAdjacentWater.pos.x, HighestValidAdjacentWater.pos.y, HighestValidAdjacentWater.pos.z, dictdrained));
        }

        UpdateAllButtons();

        yield return null;
    }
    public V3IntByte FindHighestAdjacentWater(int x, int y, int z, Dictionary<Vector3Int, byte> dictzito)
    {


        V3IntByte SelectedCell = new V3IntByte(InvalidVector4FirstDrain, 0);

        Vector3Int WaterFinder = KeepPosInBounds(new Vector3Int(x - 1, y, z));

        if (GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > SelectedCell.water && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 1)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x, y + 1, z));

        if (GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > SelectedCell.water && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 1)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
        }


        WaterFinder = KeepPosInBounds(new Vector3Int(x + 1, y, z));

        if (GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > SelectedCell.water && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 1)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
        }

        WaterFinder = KeepPosInBounds(new Vector3Int(x, y - 1, z));

        if (GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] > SelectedCell.water && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 55 && dictzito.ContainsKey(WaterFinder) == false && GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z] != 1)
        {
            SelectedCell.pos = WaterFinder;
            SelectedCell.water = GridArray[WaterFinder.x, WaterFinder.y, WaterFinder.z];
        }


        return SelectedCell;
    }


    public IEnumerator BridgeRoutine(int x, int y, int z)
    {
        StartCoroutine(DrainRoutine(x, y, z, new Dictionary<Vector3Int, byte>()));

        //
        StartCoroutine(FlowRoutine(x, y, z, new Dictionary<Vector3Int, byte>()));
        Debug.Log("running bridge");

        yield return null;
    }
    public IEnumerator MassBridgeRoutine(int x, int y, int z)
    {
        int counter = 0;

        while ( counter<100 )
        {
            counter++;
            yield return StartCoroutine(BridgeRoutine(x, y, z));
        }

        Debug.Log(counter);
        yield return null;
    }

    ///
    public Vector3Int KeepPosInBounds(Vector3Int newPos)
    {
        if (newPos.x < 0) { newPos.x = XGridSize - 1; }
        if (newPos.y < 0) { newPos.y = YGridSize - 1; }
        if (newPos.z < 0) { newPos.z = ZGridSize - 1; }
        if (newPos.x >= XGridSize) { newPos.x = 0; }
        if (newPos.y >= YGridSize) { newPos.y = 0; }
        if (newPos.z >= ZGridSize) { newPos.z = 0; }

        return newPos;
    }

Я использую словари для хранения скрещенных клеток в моих методах заполнения и слива, чтобы убедиться, что вода никогда не удваивается и правильно не заполняет каждый доступная ячейка, прежде чем ее разрешат поднять на уровень.

Однако я столкнулся с проблемой, заключающейся в том, что, когда я запускаю свой метод моста, я не могу понять, как определить, что система достигла равновесия, и мой метод моста продолжает сливать и впускать воду в себя в бесконечном количестве l oop, хотя конечное состояние количества воды остается неизменным.

Я хотел бы обнаружить это равновесие, не выполняя проверку всей сетки каждый кадр для изменения, потому что я собираюсь запустить эту систему в очень крупномасштабных сетках.

Вот видео о метод assbridge, который быстро зацикливает метод bridge на заполнение пустого пространства: https://www.youtube.com/watch?v=-4WUivwnMZ0

Однако я не могу понять, когда остановить l oop.

Конкретный фрагмент кода, на котором я застрял, - это часть:

        while (  )
        {
            yield return StartCoroutine(BridgeRoutine(x, y, z));
        }

Я не знаю, что вводить в качестве условия в это время, пока l oop, так что он останавливается, когда система находится в Равновесие без проверки каждой отдельной ячейки от шага к шагу.

Когда система достигает равновесия, она просто сливает воду из ячейки, имеющей 3, течет в одну, имеющую 2, что приводит к ее повышению до 3 и позволяет ей быть истощенным снова.

Буду признателен за любые советы, заранее спасибо!

1 Ответ

0 голосов
/ 08 апреля 2020

Решено путем проверки равновесия только в ячейке и 4 смежных местах, которые послужили основой для моста

...