// Načte scénu s generátorem mapy (scéna s postavou je načtena) a odnačte scénu s výběrem úrovní IEnumerator LoadMazeAsync(string locationSceneName, MazeSettingsSO mazeSettings) { _loading = true; _loadingScreen.ShowLoadingScreen(); Player.SetActive(false); CurrentHubManager = null; CurrentMazeManager = null; AsyncOperation locationSceneLoadingTask = SceneManager.LoadSceneAsync(locationSceneName, LoadSceneMode.Additive); while (!locationSceneLoadingTask.isDone) { yield return(null); } SceneManager.SetActiveScene(SceneManager.GetSceneByName(locationSceneName)); while (CurrentMazeManager == null) { yield return(null); } string message = CurrentMazeManager.CreateMaze(mazeSettings); QuestUI.QueueMessage(message); CurrentHubManager = null; UnloadScene(HUB_SCENE_NAME); Player.SetActive(true); _loading = false; _loadingScreen.HideLoadingScreen(); }
// Vytvoří uzly k vyhledávání cesty podle podbuňek, které dostane v objektu Subcell Data public PathfindingNode[] GenerateNodes(MazeSettingsSO mazeSettings, SubcellData subcellData) { _pathfindingNodes = new PathfindingNode[subcellData.EmptySpotInArray * mazeSettings.pathfindingNodesInSubcell * mazeSettings.pathfindingNodesInSubcell]; _currentEmptyIndex = 0; float step = mazeSettings.distanceBetweenCells / mazeSettings.pathfindingNodesInSubcell * mazeSettings.nodeSpreadPercentage; Vector3 startPosition; Vector3 startOffset = new Vector3(((float)mazeSettings.distanceBetweenCells * mazeSettings.nodeSpreadPercentage - step) / 2f, 0, ((float)mazeSettings.distanceBetweenCells * mazeSettings.nodeSpreadPercentage - step) / 2f); foreach (Subcell subcell in subcellData.Subcells) { if (subcell == null) { continue; } // Projde všechny buňky a vytvoří v nich uzly k vyhledávání cesty subcell.LowestPathfindingNodeID = _currentEmptyIndex; startPosition = subcell.Position - startOffset; CreatePathfindingNodeGrid(startPosition, mazeSettings.pathfindingNodesInSubcell, step); ConnectNodesInSubcellToNeighbours(subcell, mazeSettings.pathfindingNodesInSubcell); subcell.NodesCreated = true; } return(_pathfindingNodes); }
// Přesvědčí se, zda se už něco nenačítá a poté zavolá Coroutine, která načte scénu, která vygeneruje mapu public void EnterMaze(MazeSettingsSO mazeSettings) { if (_loading) { return; } Player.GetComponent <PlayerController>().ResetStatsAndCleanInventory(); StartCoroutine(LoadMazeAsync(MAP_SCENE_NAME, mazeSettings)); }
// Vygeneruje mapu, jako parametry přijíma Maze Settings a IWinCondition, jinými slovy pravidla, jak se má mapa generovat, a podmínku pro splnění úrovně public PathfindingNode[] GenerateMaze(MazeSettingsSO mazeSettings, IWinCondition winCondition, out int nodeCount) { _mazeSettings = mazeSettings; _winCondition = winCondition; _generationsRules = _winCondition.SpecialGenerationRules(); // Vygeneruje buňky, pokud jich vygeneruje málo může generaci opakovat ICellGenerator cellGenerator = GetComponent <ICellGenerator>(); _startPoint = new Vector3(_mazeSettings.centerPoint.x - ((float)_mazeSettings.width / 2f) * _mazeSettings.distanceBetweenCells, _mazeSettings.centerPoint.y, _mazeSettings.centerPoint.z - ((float)_mazeSettings.length / 2f) * _mazeSettings.distanceBetweenCells); // RLpos int generationCounter = 0; while (generationCounter < _mazeSettings.triesToGenerateMaze) { _cellData = cellGenerator.GenerateCells(_mazeSettings, _startPoint); if ((float)_cellData.CellCount / (float)(_mazeSettings.length * _mazeSettings.width) >= _mazeSettings.minCellPercentage) { break; } generationCounter++; } // Rozdělí buňky na podbuňky ISubcellGenerator subcellGenerator = GetComponent <ISubcellGenerator>(); _subcellData = subcellGenerator.GenerateSubcells(_mazeSettings, _cellData, _startPoint, 1); // Pokud je u podmínky k zvítězení pravidlo na vedlejší místnost, tak ji vygeneruje if (_generationsRules.Contains(GenerationRule.OuterRoom)) { CreateOuterRoom(); } // Vytvoří na mapě části místností pro všechny podbuňky ITileGenerator tileGenerator = GetComponent <TileGenerator>(); tileGenerator.GenerateTiles(_subcellData, _generationsRules.Contains(GenerationRule.OuterRoom) ? (_subcellData.EmptySpotInArray - 1) : _subcellData.EmptySpotInArray); // Vytvoří vrcholy pro hledání cesty PathfindingNodeGenerator pathfindingNodeGenerator = GetComponent <PathfindingNodeGenerator>(); _pathfindingNodes = pathfindingNodeGenerator.GenerateNodes(_mazeSettings, _subcellData); GetComponent <Spawner>().SpawnReturnPortal(_subcellData.SpawnPoint); GameManager.Instance.Player.transform.position = new Vector3(_subcellData.SpawnPoint.x, _subcellData.SpawnPoint.y + _playerYOffset, _subcellData.SpawnPoint.z); SpawnEnemies(); nodeCount = _pathfindingNodes.Length; return(_pathfindingNodes); }
// Vytvoří podbuňky podle pravidel v Maze Settings public SubcellData GenerateSubcells(MazeSettingsSO mazeSettings, CellData cellData, Vector3 startPoint, int additionalArraySize) { _mazeSettings = mazeSettings; _cellData = cellData; _startPoint = startPoint; _emptySpotInArray = 0; _subcells = new Subcell[_cellData.MaximumSubcellCount + additionalArraySize]; Stack <Vector2Int> cellStack = new Stack <Vector2Int>(); // Vezme první buňku, vytvoří v ní podbuňky a vloží sousední buňky do zásobníku Vector3 spawnPoint = new Vector3(startPoint.x + (float)_cellData.XDistance[_cellData.FirstCell.y] * _mazeSettings.distanceBetweenCells, startPoint.y, startPoint.z + (float)_cellData.ZDistance[_cellData.FirstCell.x] * _mazeSettings.distanceBetweenCells); // RLpos CreateRoom(_cellData.FirstCell); PushNeighbouringCellsIntoStack(cellStack, _cellData.FirstCell); _cellData.Cells[_cellData.FirstCell.x, _cellData.FirstCell.y].generated = true; // Rozděluje buňky na podbuňky a vkládá do zásobníku sousední buňky, dokud zásobník není prázdný Vector2Int currentCell; // Z, X while (cellStack.Count > 0) { currentCell = cellStack.Pop(); if (_cellData.Cells[currentCell.x, currentCell.y].generated == true) { continue; } // Náhodně vybere, jestli to bude místnost nebo chodba if (Random.Range(0f, 1f) <= _mazeSettings.roomChance[_cellData.Cells[currentCell.x, currentCell.y].GetDoorCount() - 1]) { CreateRoom(currentCell); } else { CreateCorridor(currentCell); } PushNeighbouringCellsIntoStack(cellStack, currentCell); _cellData.Cells[currentCell.x, currentCell.y].generated = true; } return(new SubcellData(_subcells, _emptySpotInArray, spawnPoint)); }
// Přidá jeden komponent implementující interface Win Condition podle nastavení v Maze Settings public string CreateMaze(MazeSettingsSO mazeSettings) { LevelNumber = mazeSettings.levelNumber; IWinCondition winCondition; switch (mazeSettings.mazeWinCondition) { case WinConditionType.Boss: winCondition = gameObject.AddComponent <FindKey>(); break; case WinConditionType.ClearLocation: winCondition = gameObject.AddComponent <ClearLocation>(); break; case WinConditionType.CollectItems: winCondition = gameObject.AddComponent <CollectArtefacts>(); break; default: throw new System.Exception("Can't generate maze without win condition"); } winCondition.OnCompleted += WinConditionCompleted; MazeGenerator mazeGenerator = GetComponent <MazeGenerator>(); PathfindingNode[] nodes = mazeGenerator.GenerateMaze(mazeSettings, winCondition, out int nodeCount); Pathfinding <PathfindingNode> pathfinding = new Pathfinding <PathfindingNode>(nodes, nodeCount); EnemyController.Pathfinder = pathfinding; _winConditionMessages = winCondition.GetMessages(); return(_winConditionMessages[0]); }
// Vytvoří buňky a propojí je podle informací z Maze Settings public CellData GenerateCells(MazeSettingsSO mazeSettings, Vector3 startPoint) { _mazeSettings = mazeSettings; int cellCounter = 1; // Z, X _cells = new Cell[_mazeSettings.length, _mazeSettings.width]; _cellStack = new Stack <Vector2Int>(); _xDistance = new int[_mazeSettings.width + 1]; _zDistance = new int[_mazeSettings.length + 1]; _zDistance[0] = _xDistance[0] = 0; // Náhodně rozhodne o délce buňek for (int i = 1; i < _mazeSettings.length + 1; i++) { if (_mazeSettings.randomDistanceBetweenCells) { _zDistance[i] = _zDistance[i - 1] + Random.Range(_mazeSettings.minDistanceMultiplyer, _mazeSettings.maxDistanceMultiplyer); } else { _zDistance[i] = i; } } // Náhodně rozhodne o výšce buňek for (int i = 1; i < _mazeSettings.width + 1; i++) { if (_mazeSettings.randomDistanceBetweenCells) { _xDistance[i] = _xDistance[i - 1] + Random.Range(_mazeSettings.minDistanceMultiplyer, _mazeSettings.maxDistanceMultiplyer); } else { _xDistance[i] = i; } } // První buňka - přídá všechny sousedy do zásobníku, Z, X Vector2Int firstCell = new Vector2Int(Random.Range(1, _mazeSettings.length - 1), Random.Range(1, _mazeSettings.width - 1)); Vector2Int currentCellPositionInArray = firstCell; _cells[currentCellPositionInArray.x, currentCellPositionInArray.y] = new Cell(true, true, true, true); PushNeighbouringCells(currentCellPositionInArray); int maxNodeCount = (_zDistance[currentCellPositionInArray.x + 1] - _zDistance[currentCellPositionInArray.x]) * (_xDistance[currentCellPositionInArray.y + 1] - _xDistance[currentCellPositionInArray.y]); // Nové buňky se vytváří dokud zásobník není prázdný while (_cellStack.Count > 0) { currentCellPositionInArray = _cellStack.Pop(); if (_cells[currentCellPositionInArray.x, currentCellPositionInArray.y] != null) { continue; } CreateNewCell(currentCellPositionInArray); CreateNewDoors(currentCellPositionInArray); PushNeighbouringCells(currentCellPositionInArray); cellCounter++; maxNodeCount += (_zDistance[currentCellPositionInArray.x + 1] - _zDistance[currentCellPositionInArray.x]) * (_xDistance[currentCellPositionInArray.y + 1] - _xDistance[currentCellPositionInArray.y]); } // Vrátí vytvořené buňky a s nimi nutné informace o nich return(new CellData(_cells, firstCell, cellCounter, maxNodeCount, _xDistance, _zDistance)); }