Проблема с рандомом и генерацией

Программирование на Юнити.

Проблема с рандомом и генерацией

Сообщение Heliosis 08 мар 2020, 21:01

Бомжур, возникла следующая проблема: я, значит, пытаюсь сгенерировать комнату (по клеточкам) с рандомной длинной, шириной и количеством выемок в стенах (то бишь дверей/коридоров/как угодно)
Сперва (как мне показалось) все работало, но происходит вот что - генератор выбирает несколько определенных шаблонов (для куска кода, представленного ниже это 2 шаблона, один из них, к слову, невозможен по условиям генерации) и начинает гонять по ним по кругу (!), совершенно не предпринимая попыток придумать новые шаблоны. Время от времени (по неустановленной закономерности) он решает при запуске сцены/игры заново сгенерировать сперва одну комнату, потом другую, третью, а потом вновь возвращается к предопределенным шаблонам.
Более того, эта последовательность шаблонов сохраняется и при перезапуске сцены. Я перезапускал также Юнити, это помогло на первые 5-6 генераций, потом он снова взялся за свое.
Судя по наблюдениям, шаблоны он выбирает исходя, в частности, из максимальной длины комнаты (она вообще выбирается СЛУЧАЙНО от 4 до 8, но если поставить от 4 до 9, например, то шаблоны будут иные), а также из стартовой клетки, из которой начинается генерация.

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

Синтаксис:
Используется csharp
[System.Serializable]
public class GenerationMapTile
{
    public int x, y;
    // 0 - empty space
    // 1 - wall
    // 2 - floor
    public int floorType = 0;
    public int roomNumber;
    public bool isJoint;
    public bool isJointDenied;
    // 1 - up
    // 2 - right
    // 3 - down
    // 4 - left
    public int jointDirection;
    public bool frontSideIsConnected, rearSideIsConnected;
}

public class MapGenerator : MonoBehaviour
{
    public int maxAttemptsCount;
    public GenerationMapTile[,] tiles;
    public List<GenerationMapTile> unfinishedJoints;
    public int maxMapSizeX = 200,
               maxMapSizeY = 200;
    public GenerationMapTile currentJoint;
    public int currentRoomNumber = 0;

    public Tilemap tilemap;
    public TileBase floorTile, wallTile;

    private void Start()
    {
        tiles = new GenerationMapTile[maxMapSizeX, maxMapSizeY];
        for (int x = 0; x < maxMapSizeX; x++)
            for (int y = 0; y < maxMapSizeY; y++)
            {
                tiles[x, y] = new GenerationMapTile
                {
                    x = x,
                    y = y,
                    floorType = 0,
                    isJoint = false,
                    roomNumber = -1
                };
            }

        tiles[50, 50].isJoint = true;
        tiles[50, 50].jointDirection = 1;
        tiles[50, 50].floorType = 2;
        currentJoint = tiles[50, 50];
        RoomGenerationWave();

        for (int x = 0; x < maxMapSizeX; x++)
            for (int y = 0; y < maxMapSizeY; y++)
            {
                if (tiles[x, y].floorType == 1)
                    tilemap.SetTile(new Vector3Int(x, y, 0), wallTile);
                if (tiles[x, y].floorType == 2)
                    tilemap.SetTile(new Vector3Int(x, y, 0), floorTile);
            }
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

    public void RoomGenerationWave()
    {
        if (currentJoint.isJointDenied == false)
        {
            currentRoomNumber++;
            int jointsCount = 1;
            int maxJointCounts = Random.Range(1, 5);
            if (currentJoint.jointDirection == 1)
            {
                bool impossibleToContinue = false;
                int maxRoomLength = Random.Range(4, 8);

                int shiftToLeft = Random.Range(0, 7);
                int shiftToRight = Random.Range(7 - shiftToLeft - 2, 7 - shiftToLeft);
                if (shiftToRight < 0) shiftToRight = 0;

                int y = 1;
                for (int i = 0; i < maxRoomLength; i++)
                {
                    for (int x = -shiftToLeft; x <= shiftToRight; x++)
                    {
                        if (tiles[currentJoint.x + x, currentJoint.y + y].floorType != 0)
                        {
                            impossibleToContinue = true;
                            break;
                        }
                    }

                    if (impossibleToContinue == true) break;
                    else
                    {
                        for (int x = -shiftToLeft; x <= shiftToRight; x++)
                        {
                            tiles[currentJoint.x + x, currentJoint.y + y].floorType = 2;
                            tiles[currentJoint.x + x, currentJoint.y + y].roomNumber = currentRoomNumber;
                        }
                        y++;
                    }
                }

                int maxY = y;
                for (y = 0; y <= maxY; y++)
                {
                    if (y == maxY)
                    {
                        for (int x = -shiftToLeft - 1; x <= shiftToRight; x++)
                        {
                            if (tiles[currentJoint.x + x, currentJoint.y + y].isJoint == false)
                            {
                                if (x != -shiftToLeft - 1 && x != shiftToRight + 1 && Random.Range(0f, 100f) < 15f)
                                {
                                    tiles[currentJoint.x + x, currentJoint.y + y].floorType = 2;
                                    tiles[currentJoint.x + x, currentJoint.y + y].isJoint = true;
                                    tiles[currentJoint.x + x, currentJoint.y + y].jointDirection = 1;
                                    tiles[currentJoint.x + x, currentJoint.y + y].rearSideIsConnected = true;
                                    if (tiles[currentJoint.x + x, currentJoint.y + y + 1].floorType == 2)
                                        tiles[currentJoint.x + x, currentJoint.y + y].frontSideIsConnected = true;
                                    else unfinishedJoints.Add(tiles[currentJoint.x + x, currentJoint.y + y]);
                                }
                                else tiles[currentJoint.x + x, currentJoint.y + y].floorType = 1;
                            }
                            else
                            {
                                if (tiles[currentJoint.x + x, currentJoint.y + y].frontSideIsConnected == false)
                                    tiles[currentJoint.x + x, currentJoint.y + y].frontSideIsConnected = true;
                                else tiles[currentJoint.x + x, currentJoint.y + y].rearSideIsConnected = true;
                                jointsCount++;
                            }
                        }
                    }
                    else if (y == 0)
                    {
                        for (int x = -shiftToLeft - 1; x <= shiftToRight; x++)
                        {
                            if (tiles[currentJoint.x + x, currentJoint.y + y].isJoint == false)
                            {
                                if (x != -shiftToLeft - 1 && x != shiftToRight + 1 && Random.Range(0f, 100f) < 15f)
                                {
                                    tiles[currentJoint.x + x, currentJoint.y + y].floorType = 2;
                                    tiles[currentJoint.x + x, currentJoint.y + y].isJoint = true;
                                    tiles[currentJoint.x + x, currentJoint.y + y].jointDirection = 1;
                                    tiles[currentJoint.x + x, currentJoint.y + y].rearSideIsConnected = true;
                                    if (tiles[currentJoint.x + x, currentJoint.y + y + 1].floorType == 2)
                                        tiles[currentJoint.x + x, currentJoint.y + y].frontSideIsConnected = true;
                                    else unfinishedJoints.Add(tiles[currentJoint.x + x, currentJoint.y + y]);
                                }
                                else tiles[currentJoint.x + x, currentJoint.y + y].floorType = 1;
                            }
                            else
                            {
                                if (tiles[currentJoint.x + x, currentJoint.y + y].frontSideIsConnected == false)
                                    tiles[currentJoint.x + x, currentJoint.y + y].frontSideIsConnected = true;
                                else tiles[currentJoint.x + x, currentJoint.y + y].rearSideIsConnected = true;
                                jointsCount++;
                            }
                        }
                    }
                    else
                    {
                        if (tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].isJoint == false)
                        {
                            if (Random.Range(0f, 100f) < 15f)
                            {
                                tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].floorType = 2;
                                tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].isJoint = true;
                                tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].jointDirection = 4;
                                tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].rearSideIsConnected = true;
                                if (tiles[currentJoint.x - shiftToLeft - 2, currentJoint.y + y].floorType == 2)
                                    tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].frontSideIsConnected = true;
                                else unfinishedJoints.Add(tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y]);
                            }
                            else tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].floorType = 1;
                        }
                        else
                        {
                            if (tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].frontSideIsConnected == false)
                                tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].frontSideIsConnected = true;
                            else tiles[currentJoint.x - shiftToLeft - 1, currentJoint.y + y].rearSideIsConnected = true;
                            jointsCount++;
                        }

                        if (tiles[currentJoint.x + shiftToRight, currentJoint.y + y].isJoint == false)
                        {
                            if (Random.Range(0f, 100f) < 15f)
                            {
                                tiles[currentJoint.x + shiftToRight, currentJoint.y + y].floorType = 2;
                                tiles[currentJoint.x + shiftToRight, currentJoint.y + y].isJoint = true;
                                tiles[currentJoint.x + shiftToRight, currentJoint.y + y].jointDirection = 2;
                                tiles[currentJoint.x + shiftToRight, currentJoint.y + y].rearSideIsConnected = true;
                                if (tiles[currentJoint.x + shiftToRight + 1, currentJoint.y + y].floorType == 2)
                                    tiles[currentJoint.x + shiftToRight, currentJoint.y + y].frontSideIsConnected = true;
                                else unfinishedJoints.Add(tiles[currentJoint.x + shiftToRight + 1, currentJoint.y + y]);
                            }
                            else tiles[currentJoint.x + shiftToRight, currentJoint.y + y].floorType = 1;
                        }
                        else
                        {
                            if (tiles[currentJoint.x + shiftToRight, currentJoint.y + y].frontSideIsConnected == false)
                                tiles[currentJoint.x + shiftToRight, currentJoint.y + y].frontSideIsConnected = true;
                            else tiles[currentJoint.x + shiftToRight, currentJoint.y + y].rearSideIsConnected = true;
                            jointsCount++;
                        }
                    }
                }
            }
        }
    }
}

Буду благодарен за помощь или хотя бы за подсказку.
Heliosis
UNIт
 
Сообщения: 146
Зарегистрирован: 10 фев 2016, 20:50

Re: Проблема с рандомом и генерацией

Сообщение Tolking 08 мар 2020, 21:57

Думаю,для начала, имеет смысл узнать как работает рандом...
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2449
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6