private GameObject SelectChunk(EdgeType exitType, Chunk.Direction exitDir, GameObject[] chunks, Vector3 position, out Chunk.EdgeDescription nextExit) { // Produce a list of all possible edges. var suitableEdges = new Dictionary <GameObject, List <Chunk.EdgeDescription> >(); foreach (GameObject chunk in chunks) { // Find details. Chunk details = chunk.GetComponent <Chunk>(); var edges = new List <Chunk.EdgeDescription>(); // Test edges using testChunk foreach (Chunk.EdgeDescription edge in details.Edges) { if (edge.type == exitType) { int rotations = edge.RotationsNeeded(exitDir); var rotatedEdge = details.RotateEdge(edge, rotations); if (TestChunk(details.Rotated(rotations), position - rotatedEdge.position - rotatedEdge.ExitVector)) { edges.Add(edge); } } } // If edges are found, add them to the dict. if (edges.Count != 0) { suitableEdges.Add(chunk, edges); } } if (suitableEdges.Count == 0) { nextExit = null; return(null); } // Select a chunk, and grab details. GameObject[] keys = new GameObject[suitableEdges.Keys.Count]; suitableEdges.Keys.CopyTo(keys, 0); GameObject selectedChunk = keys[rng.Next(keys.Length)]; // Select an edge. var possibleEdges = suitableEdges[selectedChunk]; nextExit = possibleEdges[rng.Next(possibleEdges.Count)]; return(selectedChunk); }
public bool generateTerrain() { // Initialise the dictionaries. initialise(); // Place start GameObject[] startChunks = GetChunks(ChunkType.Entrance); PlaceChunk(startChunks[rng.Next(startChunks.Length)], 0); placedCells[Vector3.zero].distance = 0; // Place blocks directly outward until the exit is placed. OuterWhile: while (openCells.Count != 0) { // Select next cell to fill. if (exitPosition == null) { openCells.Sort((Cell a, Cell b) => b.distance - a.distance); } else { openCells.Sort((Cell a, Cell b) => a.distance - b.distance); } Cell nextCell = openCells[0]; position = nextCell.position; // Get exits and check to see if map is complete. List <Chunk.Direction> validExits = GetValidExits(); // Try to place an exit. if (exitPosition == null) { ChunkType exit = ChunkType.Exit; if (nextCell.distance >= exitDifficulty) { if (remainingChunks[0] != exit) { remainingChunks.Insert(0, exit); } } else if (remainingChunks[0] == exit) { remainingChunks.RemoveAt(0); } } // Prepare variables. Chunk.Direction dir = Chunk.Direction.FORWARD; Chunk.EdgeDescription edge = null; GameObject nextChunk = null; while (nextChunk == null) { // If no exits can be built on, rebase. if (validExits.Count == 0) { deadEnds.Add(nextCell); openCells.Remove(nextCell); goto OuterWhile; } // Select a random exit. int selectedExit = rng.Next(validExits.Count); dir = validExits[selectedExit]; var exit = placedCells[position].edges[(int)dir]; // Select a chunk that fits there. var nextChunkType = remainingChunks.Count == 0 ? ChunkType.Edge : remainingChunks[0]; GameObject[] chunks = GetChunks(nextChunkType); nextChunk = SelectChunk(exit, dir, chunks, position, out edge); if (nextChunk == null) { validExits.RemoveAt(selectedExit); } } // Rotate it if needed, draw, and update x, y. Chunk details = nextChunk.GetComponent <Chunk>(); int rotations = edge.RotationsNeeded(dir); edge = details.RotateEdge(edge, rotations); details = details.Rotated(rotations); // Update position, place tile. position = position - edge.position - edge.ExitVector; PlaceChunk(nextChunk, rotations); // Empty the closed set. openCells.AddRange(deadEnds); deadEnds.Clear(); if (details.type == ChunkType.Exit) { exitPosition = position; } if (remainingChunks.Count > 0) { remainingChunks.RemoveAt(0); } } // Actually generate the terrain. if (remainingChunks.Count == 0 && exitPosition != null) { foreach (Cell cell in deadEnds) { // Place dead ends. GameObject[] blocks = GetChunks(ChunkType.Block); for (int dir = 0; dir < 4; dir++) { if (cell.edges[dir] != CLOSED) { position = cell.position + DirVector(dir); PlaceChunk(blocks[rng.Next(blocks.Length)], 0); } } } // Now instantiate the terrain, and create the grid. terrain = new GameObject(); terrain.name = "Chunks"; // To make the editor neater. foreach (InstantiateCall obj in instantiateCalls) { obj.Instantiate(terrain); } CreateGrid(); return(true); } else { return(false); } }