Unity — Игра о соединении водопроводных труб. Проблема с проверкой, подключены ли объекты pipes к центральному источнику

#c# #unity3d

#c# #unity-игровой движок

Вопрос:

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

Проблема, с которой я застрял, заключается в следующем:

Шаг 1:

введите описание изображения здесь

Шаг 2:

введите описание изображения здесь

Шаг 3:

введите описание изображения здесь

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

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

Коллайдеры — Сцена:

введите описание изображения здесь

Коллайдеры — иерархия:

введите описание изображения здесь

Если столкнувшийся объект подключен к water (с помощью bool), он добавляет столкнувшийся объект в список. Если список больше 0, активируется синий спрайт. Если список пуст, деактивирует синий спрайт. Как показано в примере кода ниже.

Триггеры, которые проверяют, подключен ли объект к воде:

 private void OnTriggerEnter2D(Collider2D other) {
    if (other.GetComponent<FlipPipes2>() != null) {
        isFlowingWater = other.GetComponent<FlipPipes2>().flowingWater;
    }
    if (other.CompareTag("WaterPipe")) {
        if (other.name == "Filled_Cross" || isFlowingWater) {
            myFlipPipes.flowingWater = true;
        }
        TestingScoreStatic.connectedPipes  ;
    }
}

private void OnTriggerStay2D(Collider2D other) {
    if (!inList) {
        myFlipPipes.collidedObjectsList.Add(other.gameObject);
        inList = true;
    }
    if (other.name == "Filled_Cross" || isFlowingWater) {
        myFlipPipes.flowingWater = true;
    }
}

private void OnTriggerExit2D(Collider2D other) {
    if (other.CompareTag("WaterPipe")) {
        myFlipPipes.collidedObjectsList.Remove(other.gameObject);
        myFlipPipes.flowingWater = false;
        isConnectedToWater = false;
        TestingScoreStatic.connectedPipes--;
        inList = false;
    }
}
  

Пример кода фактического изменения спрайта:

 private void Update() {
    if (collidedObjectsList.Count > 0) {
        filledPipe.SetActive(true);
    } else {
        filledPipe.SetActive(false);
    }
}
  

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

Как я могу проверить, существует ли допустимый путь к источнику воды? Или любой другой способ сделать то, что мне нужно?

Вот несколько других примеров кода, которые могут помочь:

Метод, который создает плату:

 private void SetUp() {
    for (int i = 0; i < width; i  ) {
        for (int j = 0; j < height; j  ) {
            Vector2 tempPosition = new Vector2(i, j);
            int tempIndex = levelManager.levelOne[pipeIndex];
            GameObject pipe = Instantiate(pipes[tempIndex], tempPosition, Quaternion.identity);
            pipe.transform.parent = transform;
            allPipes[i, j] = pipe;
            if (!pipe.CompareTag("WaterPipe")) {
                shuffleSpawnedPipes.pipes.Add(pipe);
            }
            pipeIndex  ;
        }
    }
    shuffleSpawnedPipes.ShufflePipes();
}
  

(Ужасно) Попытка проверить каждую трубу с помощью двойного for цикла:

 void IsConnectedToWater() {
    if (column > 0 amp;amp; column < board.width - 1) {
        GameObject leftPipe1 = board.allPipes[column - 1, row];
        GameObject rightPipe1 = board.allPipes[column   1, row];
        if (leftPipe1.tag == this.gameObject.tag amp;amp; rightPipe1.tag == this.gameObject.tag) {
            leftPipe1.GetComponent<Pipe>().connectedToWater = true;
            rightPipe1.GetComponent<Pipe>().connectedToWater = true;
            connectedToWater = true;
        }
    }
}
  

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

Комментарии:

1. «Возможно ли что-нибудь?» Это не полезный вопрос, на него можно было бы ответить простым «да», абсолютно обоснованным, но бесполезным. Рассмотрите возможность добавления некоторого кода с реальной попыткой решения проблемы и конкретной проблемы.

2. Спасибо @bradbury9, я улучшу сообщение и перефразирую вопрос.

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

Ответ №1:

Что вам нужно, так это алгоритм поиска пути.

Создайте рекурсивную функцию, которая будет проверять пути к вашему источнику воды. Вместо проверки каждого элемента, подключен ли он к water, проверьте, есть ли ваш объект watersource в списке подключенных объектов этого проверяемого канала. Если это не так, сохраните этот объект pipe в списке checkedObjects и перейдите к следующему подключенному объекту, повторяйте, пока не проверите все объекты pipe, подключенные друг к другу. Если ни у одного из объектов не было вашего источника воды в списке подключенных объектов, это означает, что все объекты на checkedObjects пути не подключены к воде, и вы можете отключить спрайт воды на всех из них.