IEnumerator FloodFill(IntGrid floodFilledCells, ObjectPool filledTiles, Point point) { Point up = point + Vector2.up; Point down = point + Vector2.down; Point left = point + Vector2.left; Point right = point + Vector2.right; if (point.x < 0 || point.y < 0 || point.x > dungeonWidth - 1 || point.y > dungeonHeight - 1) { floodFilledPointCount--; yield break; } if (floodFilledCells[point.x, point.y] != 0) { floodFilledPointCount--; yield break; } floodFilledCells[point.x, point.y] = 2; ObjectPool.PooledObject pooledObj = filledTiles.GetObjectFromPool; pooledObj.position = new Vector2( point.x - (dungeonWidth / 2) + (pooledObj.scale.x / 2), point.y - (dungeonHeight / 2) + (pooledObj.scale.y / 2) ); SpriteRenderer r = pooledObj.gameObject.GetComponent <SpriteRenderer>(); if (r != null) { r.color = Color.red; } yield return(null); if (dungeon[up] == 0) { floodFilledPointCount++; StartCoroutine(FloodFill(floodFilledCells, filledTiles, up)); } if (dungeon[down] == 0) { floodFilledPointCount++; StartCoroutine(FloodFill(floodFilledCells, filledTiles, down)); } if (dungeon[left] == 0) { floodFilledPointCount++; StartCoroutine(FloodFill(floodFilledCells, filledTiles, left)); } if (dungeon[right] == 0) { floodFilledPointCount++; StartCoroutine(FloodFill(floodFilledCells, filledTiles, right)); } floodFilledPointCount--; }
public Maze(int width, int height, float complexity = 0.75f, float density = 0.75f) { this.width = width; this.height = height; this.shape = new int[] { height, width }; this.complexity = (int)(complexity * (5.0f * (this.shape[0] + this.shape[1]))); this.density = (int)(density * ((this.shape[0] / 2) * (this.shape[1] / 2))); this._mazeGrid = new IntGrid(this.shape[1], this.shape[0]); GenerateMaze(); }
public Maze(IntGrid maze, bool shouldGenerate = false, float complexity = 0.75f, float density = 0.75f) { int width = maze.GetLength(0); int height = maze.GetLength(1); this.width = width; this.height = height; this.shape = new int[] { height, width }; this.complexity = (int)(complexity * (5.0f * (this.shape[0] + this.shape[1]))); this.density = (int)(density * ((this.shape[0] / 2) * (this.shape[1] / 2))); this._mazeGrid = maze; if (shouldGenerate) { GenerateMaze(); } }
// TODO: Refactor this to use a different maze gen algorithm, this one kinda blows public void GenerateMaze(IntGrid _maze = null) { IntGrid mazeArray = this._mazeGrid; // Generate inner maze for (int i = 0; i < this.density; i++) { int x = Random.Range(0, this.shape[1] / 2) * 2; int y = Random.Range(0, this.shape[0] / 2) * 2; if (mazeArray[x, y] == 0) { mazeArray[x, y] = 1; for (int j = 0; j < this.complexity; j++) { List <Vector3> neighbours = new List <Vector3>(); if (x > 1) { neighbours.Add(new Vector3(x - 2, y)); } if (x < this.shape[1] - 2) { neighbours.Add(new Vector3(x + 2, y)); } if (y > 1) { neighbours.Add(new Vector3(x, y - 2)); } if (y < this.shape[0] - 2) { neighbours.Add(new Vector3(x, y + 2)); } if (neighbours.Count > 0) { int randIndex = Random.Range(0, neighbours.Count); Vector3 neighbour = neighbours[randIndex]; int x_ = (int)neighbour.x; int y_ = (int)neighbour.y; if (mazeArray[x_, y_] == 0) { mazeArray[x_, y_] = 1; mazeArray[x_ + (x - x_) / 2, y_ + (y - y_) / 2] = 1; x = x_; y = y_; } } } } } // Border the maze int mazeWidth = mazeArray.GetLength(0); int mazeHeight = mazeArray.GetLength(1); for (int i = 0; i < mazeArray.GetLength(0); i++) { for (int j = 0; j < mazeArray.GetLength(1); j++) { if (i == 0 || j == 0 || i == mazeWidth - 1 || j == mazeHeight - 1) { mazeArray[j, i] = 1; } } } this._mazeGrid = mazeArray; }
IEnumerator GenerateDungeon() { if (dungeonHeight % 2 == 0) { throw new System.FormatException("dungeonHeight should be an odd number"); } if (dungeonWidth % 2 == 0) { throw new System.FormatException("roomMaxDimension should be an odd number"); } if (roomMinDimension % 2 == 0) { throw new System.FormatException("roomMinDimension should be an odd number"); } if (roomMaxDimension % 2 == 0) { throw new System.FormatException("roomMaxDimension should be an odd number"); } if (tileSize % 2 == 0) { throw new System.FormatException("tileSize should be an odd number"); } isGenerating = true; retryCount = 0; dungeonRect = Rect.zero; dungeonRect.height = dungeonHeight - 2; // minus 2 to give a 1 unit edge padding around the whole dungeon dungeonRect.width = dungeonWidth - 2; // minus 2 to give a 1 unit edge padding around the whole dungeon dungeonRect.center = transform.position; if (tiles != null) { tiles.ClearPool(); } Camera.main.orthographicSize = Mathf.Max(dungeonWidth / 2, dungeonHeight / 2) + 2; dungeon = new IntGrid(dungeonWidth, dungeonHeight); tiles = new ObjectPool(roomPrefab, dungeonWidth * dungeonHeight, false, false, transform); // make retryAttempts attempts to place rooms randomly within the dungeon while (retryCount < retryAttempts) { Vector2 randomPosition = new Vector2(ClampValueToOddNumber(Random.Range(0, dungeonWidth) - dungeonWidth / 2f), ClampValueToOddNumber(Random.Range(0, dungeonHeight) - dungeonHeight / 2f)); Vector2 randomScale = new Vector2(ClampValueToOddNumber(Random.Range(roomMinDimension, roomMaxDimension)), ClampValueToOddNumber(Random.Range(roomMinDimension, roomMaxDimension))); Collider2D overlapBox = Physics2D.OverlapBox(randomPosition, randomScale + (Vector2.one * minDistanceBetweenRooms * 2), 0f); if (overlapBox == null && IsRoomInBounds(randomPosition, randomScale)) { ObjectPool.PooledObject room = tiles.GetObjectFromPool; room.SetActive(true); room.position = randomPosition; room.scale = randomScale; yield return(new WaitForSeconds(0.1f)); } else { retryCount++; } } // carve out the rooms from the array of cells and disable the rooms in the pool foreach (KeyValuePair <string, ObjectPool.PooledObject> entry in tiles.GetObjectPool) { if (entry.Value.activeInHierarchy) { Vector3 roomPositionOffset = new Vector3(dungeonWidth / 2f, dungeonHeight / 2f); GameObject room = entry.Value.gameObject; Vector3 scale = room.transform.localScale; for (float x = -scale.x / 2; x <= scale.x / 2; x++) { for (float y = -scale.y / 2; y <= scale.y / 2; y++) { Point point = new Point((int)x, (int)y) + room.transform.position + roomPositionOffset; dungeon[point.x, point.y] = 2; } } tiles.Disable(entry.Key); yield return(null); } } // generate the maze in the empty space of the dungeon dungeon = new Maze(dungeon, true).mazeGrid; yield return(StartCoroutine(RenderDungeon())); yield return(StartCoroutine(StartFloodFill())); yield return(StartCoroutine(RenderDungeon())); yield return(StartCoroutine(RemoveDeadEnds())); yield return(StartCoroutine(RenderDungeon())); isGenerating = false; }
IEnumerator StartFloodFill() { floodFilledPointCount = 0; IntGrid floodFilledCells = new IntGrid(dungeonWidth, dungeonHeight); ObjectPool filledTiles = new ObjectPool(roomPrefab, 0, true, true, new GameObject("Filled Tiles").transform); for (int i = 0; i < dungeonWidth; i++) { for (int j = 0; j < dungeonHeight; j++) { floodFilledCells[i, j] = dungeon[i, j]; } } int x = Random.Range(0, dungeonWidth - 1); int y = Random.Range(0, dungeonHeight - 1); while (floodFilledCells[x, y] == 1) { x = Random.Range(0, dungeonWidth); y = Random.Range(0, dungeonHeight); } floodFilledPointCount++;; StartCoroutine(FloodFill(floodFilledCells, filledTiles, new Point(x, y))); while (floodFilledPointCount > 0) { yield return(null); } int filledCount = 0; for (int i = 0; i < dungeonWidth; i++) { for (int j = 0; j < dungeonHeight; j++) { if (floodFilledCells[i, j] == 2) { filledCount++; } } } if (filledCount < (dungeonHeight * dungeonWidth * 0.045f)) // filled count < 10% of 45% of tile count { if (fillAttempts >= 0) { filledTiles.ClearPool(); Debug.Log("Fill quality below threshold, restarting fill"); fillAttempts--; StartCoroutine(StartFloodFill()); } else { Debug.Log("Refill attemps reached, restarting dungeon generation"); StartCoroutine(GenerateDungeon()); } } else { for (int i = 0; i < dungeonWidth; i++) { for (int j = 0; j < dungeonHeight; j++) { if (floodFilledCells[i, j] == 0) { floodFilledCells[i, j] = 1; } } } } filledTiles.ClearPool(); dungeon = floodFilledCells; }