Last active
November 13, 2020 01:15
-
-
Save celechii/b3c0ff6351bbf6fb026990de4fae7c5c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class DirectionMaze : MonoBehaviour { | |
[System.Flags] | |
public enum Direction { | |
Up = 1 << 0, | |
Down = 1 << 1, | |
Left = 1 << 2, | |
Right = 1 << 3 | |
} | |
public Vector2Int mazeSize = new Vector2Int(15, 15); | |
[SerializeField] | |
private bool drawGizmos = true; | |
private Direction[, ] maze; | |
private Vector2Int prevSize; // delete this, the OnValidate() method, n the OnDrawGizmos() method if u dont wanna preview it in the editor | |
private bool[, ] visited; | |
[ContextMenu("Generate Maze")] | |
public Direction[, ] GenerateMaze() { | |
maze = new Direction[mazeSize.x, mazeSize.y]; | |
visited = new bool[mazeSize.x, mazeSize.y]; | |
// random starting pos on an odd index position | |
Vector2Int startPos = new Vector2Int(Random.Range(0, (int)(mazeSize.x / 2f)), Random.Range(0, (int)(mazeSize.y / 2f))); | |
startPos *= 2; | |
startPos += Vector2Int.one; | |
visited[startPos.x, startPos.y] = true; | |
RecurseMaze(startPos.x, startPos.y); | |
return maze; | |
} | |
/// <summary> | |
/// Returns an array of 4 booleans in the order up, down, left, right. | |
/// </summary> | |
/// <param name="pos">The position in the maze.</param> | |
public bool[] GetExitsAt(Vector2Int pos) => GetExitsAt(pos.x, pos.y); | |
/// <summary> | |
/// Returns an array of 4 booleans in the order up, down, left, right. | |
/// </summary> | |
/// <param name="x">The x position in the maze.</param> | |
/// <param name="y">The y position in the maze.</param> | |
public bool[] GetExitsAt(int x, int y) { | |
Direction exits = maze[x, y]; | |
return new bool[] { | |
exits.HasFlag(Direction.Up), | |
exits.HasFlag(Direction.Down), | |
exits.HasFlag(Direction.Left), | |
exits.HasFlag(Direction.Right) | |
}; | |
} | |
private void OnValidate() { | |
if (!drawGizmos) | |
return; | |
Vector2Int change = mazeSize - prevSize; | |
if (mazeSize.x <= 2) | |
mazeSize.x = 2; | |
if (mazeSize.y <= 2) | |
mazeSize.y = 2; | |
GenerateMaze(); | |
prevSize = mazeSize; | |
} | |
private void RecurseMaze(int xPos, int yPos, Direction comingFrom = 0) { | |
visited[xPos, yPos] = true; | |
if ((int)comingFrom != 0) | |
AddDirection(xPos, yPos, comingFrom); | |
// shuffle the order u check the directions in | |
int[] randomDirs = new int[] {-1, -1, -1, -1 }; | |
for (int i = 0; i < randomDirs.Length; i++) { | |
int arrayPos; | |
do { | |
arrayPos = Random.Range(0, 4); | |
} while (randomDirs[arrayPos] != -1); | |
randomDirs[arrayPos] = i; | |
} | |
for (int i = 0; i < randomDirs.Length; i++) { | |
// only run in this direction if its a valid one | |
if (IsValidDirection(randomDirs[i], xPos, yPos)) { | |
if (randomDirs[i] == 0) { // go up | |
AddDirection(xPos, yPos, Direction.Up); | |
RecurseMaze(xPos, yPos + 1, Direction.Down); | |
} else if (randomDirs[i] == 1) { // go down | |
AddDirection(xPos, yPos, Direction.Down); | |
RecurseMaze(xPos, yPos - 1, Direction.Up); | |
} else if (randomDirs[i] == 2) { // go left | |
AddDirection(xPos, yPos, Direction.Left); | |
RecurseMaze(xPos - 1, yPos, Direction.Right); | |
} else if (randomDirs[i] == 3) { // go right | |
AddDirection(xPos, yPos, Direction.Right); | |
RecurseMaze(xPos + 1, yPos, Direction.Left); | |
} | |
} | |
} | |
} | |
private void AddDirection(int xPos, int yPos, Direction direction) => maze[xPos, yPos] |= direction; | |
private bool IsValidDirection(int dir, int x, int y) { | |
if (dir == 0) | |
return IsValidPosition(x, y + 1); // up | |
if (dir == 1) | |
return IsValidPosition(x, y - 1); // down | |
if (dir == 2) | |
return IsValidPosition(x - 1, y); // left | |
if (dir == 3) | |
return IsValidPosition(x + 1, y); // right | |
return false; | |
bool IsValidPosition(int xPos, int yPos) { | |
return xPos >= 0 && xPos < mazeSize.x && yPos >= 0 && yPos < mazeSize.y && !visited[xPos, yPos]; | |
} | |
} | |
private void OnDrawGizmos() { | |
if (!drawGizmos) | |
return; | |
if (maze == null) | |
GenerateMaze(); | |
Vector2 offset = (Vector2)mazeSize / 2f; | |
for (int x = 0; x < mazeSize.x; x++) { | |
for (int y = 0; y < mazeSize.y; y++) { | |
Gizmos.color = Color.black; | |
Vector2 pos = new Vector2(x, y) - offset; | |
Gizmos.DrawWireCube(pos, Vector2.one); | |
Gizmos.color = Color.green; | |
if (maze[x, y].HasFlag(Direction.Up)) | |
Gizmos.DrawRay(pos, Vector2.up); | |
if (maze[x, y].HasFlag(Direction.Down)) | |
Gizmos.DrawRay(pos, Vector2.down); | |
if (maze[x, y].HasFlag(Direction.Left)) | |
Gizmos.DrawRay(pos, Vector2.left); | |
if (maze[x, y].HasFlag(Direction.Right)) | |
Gizmos.DrawRay(pos, Vector2.right); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment