unity使用深度优先搜索算法自动生成随机迷宫
unity使用深度优先搜索算法自动生成随机迷宫
关键词:unity C# 随机生成迷宫 深度优先搜索算法 迷宫算法
最近有空,研究了一下深度优先搜索算法,并做成一个生成迷宫的例子。
参考的是:
https://en.wikipedia.org/wiki/Maze_generation_algorithm
以下是效果图。
话不多说,代码直接贴在下面。
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using UnityEngine.UI; 5 6 public class WorldBehaviour : MonoBehaviour 7 { 8 public struct MapPointState 9 { 10 public int x; 11 public int y; 12 13 public bool isVisit; 14 public int state; 15 16 public List<int> direction; 17 18 public MapPointState(int x, int y, bool isVisit, int state) 19 { 20 this.x = x; 21 this.y = y; 22 this.isVisit = isVisit; 23 this.state = state; 24 direction = new List<int>(); 25 } 26 } 27 28 public RectTransform mainCanvas; 29 public Image image; 30 31 public int worldWidth; 32 public int worldHeight; 33 34 private Image[,] pathImages; 35 36 private MapPointState[,] mapPointStates; 37 38 private Queue<MapPointState> mapQueue; 39 40 private Stack<MapPointState> pathStack; 41 42 private int currentVisits; 43 44 private bool isReadyStop; 45 private Coroutine coroutine; 46 // Use this for initialization 47 void Start() 48 { 49 pathImages = new Image[worldHeight, worldWidth]; 50 mapQueue = new Queue<MapPointState>(); 51 52 coroutine = StartCoroutine(WaitAndShow()); 53 54 CreateAllPath(); 55 InitDepthFirstSearch(); 56 StartDepthFirstSearch(); 57 } 58 /// <summary> 59 /// 初始化 60 /// </summary> 61 private void InitDepthFirstSearch() 62 { 63 mapPointStates = new MapPointState[worldHeight, worldWidth]; 64 pathStack = new Stack<MapPointState>(); 65 66 int[] a = { 0, 1, 2, 3 };//0Up 1Down 2Left 3Right 67 68 for (int i = 0; i < worldWidth; i++) 69 { 70 for (int j = 0; j < worldHeight; j++) 71 { 72 mapPointStates[i, j] = new MapPointState(i, j, false, 0); 73 mapPointStates[i, j].direction.AddRange(a); 74 } 75 } 76 } 77 /// <summary> 78 /// 开始 79 /// </summary> 80 private void StartDepthFirstSearch() 81 { 82 DepthFirstSearch(Random.Range(0, worldHeight), Random.Range(0, worldWidth), -1); 83 84 print(currentVisits); 85 isReadyStop = true; 86 } 87 /// <summary> 88 /// 搜索 89 /// </summary> 90 /// <param name="x">当前所在x</param> 91 /// <param name="y">当前所在y</param> 92 /// <param name="direction">来时的方向</param> 93 private void DepthFirstSearch(int x, int y, int direction)//抽象坐标轴x↑y→ 94 { 95 //若超过边界 96 if (x < 0 || x >= worldHeight || y < 0 || y >= worldWidth) 97 { 98 if (pathStack.Count > 0) 99 DepthFirstSearch(pathStack.Peek().x, pathStack.Peek().y, -1); 100 return; 101 } 102 //若剩余方向为0 103 if (mapPointStates[x, y].direction.Count == 0) 104 { 105 if (pathStack.Contains(mapPointStates[x, y])) 106 { 107 pathStack.Pop(); 108 mapPointStates[x, y].isVisit = true; 109 mapQueue.Enqueue(mapPointStates[x, y]); 110 } 111 if (pathStack.Count > 0) 112 DepthFirstSearch(pathStack.Peek().x, pathStack.Peek().y, -1); 113 return; 114 } 115 //移除来时方向 116 if (mapPointStates[x, y].direction.Contains(direction)) 117 { 118 mapPointStates[x, y].direction.Remove(direction); 119 } 120 121 currentVisits++; 122 123 //随机下一个方向 124 int nextDirection = mapPointStates[x, y].direction[Random.Range(0, mapPointStates[x, y].direction.Count)]; 125 mapPointStates[x, y].direction.Remove(nextDirection); 126 127 int newX = -1, newY = -1; 128 129 ProcessNextPosition(x, y, nextDirection, ref newX, ref newY); 130 131 //搜索下一个方向 132 if (newX != -1 && newY != -1) 133 { 134 AddNewPointInMap(x, y); 135 136 switch (nextDirection) 137 { 138 case 0: 139 nextDirection = 1; 140 break; 141 case 1: 142 nextDirection = 0; 143 break; 144 case 2: 145 nextDirection = 3; 146 break; 147 case 3: 148 nextDirection = 2; 149 break; 150 } 151 152 DepthFirstSearch(newX, newY, nextDirection); 153 154 return; 155 } 156 //回溯 157 if (mapPointStates[x, y].direction.Count > 0) 158 { 159 DepthFirstSearch(x, y, -1); 160 } 161 else if (pathStack.Count > 0) 162 { 163 DepthFirstSearch(pathStack.Peek().x, pathStack.Peek().y, -1); 164 } 165 } 166 /// <summary> 167 /// 计算下一个坐标 168 /// </summary> 169 /// <param name="x">当前x</param> 170 /// <param name="y">当前y</param> 171 /// <param name="nextDirection">下一个方向</param> 172 /// <param name="newX">新x</param> 173 /// <param name="newY">新y</param> 174 private void ProcessNextPosition(int x, int y, int nextDirection, ref int newX, ref int newY) 175 { 176 switch (nextDirection) 177 { 178 case 0: 179 if (x + 1 < worldHeight && mapPointStates[x + 1, y].state != 1) 180 { 181 if ((y - 1 >= 0 && mapPointStates[x + 1, y - 1].state == 1) || (y + 1 < worldWidth && mapPointStates[x + 1, y + 1].state == 1)) 182 { 183 break; 184 } 185 186 if (x + 2 < worldHeight && mapPointStates[x + 2, y].state == 1) 187 { 188 AddNewPointInMap(x, y); 189 break; 190 } 191 192 newX = x + 1; 193 newY = y; 194 } 195 break; 196 case 1: 197 if (x - 1 >= 0 && mapPointStates[x - 1, y].state != 1) 198 { 199 if ((y - 1 >= 0 && mapPointStates[x - 1, y - 1].state == 1) || (y + 1 < worldWidth && mapPointStates[x - 1, y + 1].state == 1)) 200 { 201 break; 202 } 203 204 if (x - 2 >= 0 && mapPointStates[x - 2, y].state == 1) 205 { 206 AddNewPointInMap(x, y); 207 break; 208 } 209 210 newX = x - 1; 211 newY = y; 212 } 213 break; 214 case 2: 215 if (y - 1 >= 0 && mapPointStates[x, y - 1].state != 1) 216 { 217 if ((x + 1 < worldHeight && mapPointStates[x + 1, y - 1].state == 1) || (x - 1 >= 0 && mapPointStates[x - 1, y - 1].state == 1)) 218 { 219 break; 220 } 221 222 if (y - 2 >= 0 && mapPointStates[x, y - 2].state == 1) 223 { 224 AddNewPointInMap(x, y); 225 break; 226 } 227 228 newX = x; 229 newY = y - 1; 230 } 231 break; 232 case 3: 233 if (y + 1 < worldWidth && mapPointStates[x, y + 1].state != 1) 234 { 235 if ((x + 1 < worldHeight && mapPointStates[x + 1, y + 1].state == 1) || (x - 1 >= 0 && mapPointStates[x - 1, y + 1].state == 1)) 236 { 237 break; 238 } 239 240 if (y + 2 < worldWidth && mapPointStates[x, y + 2].state == 1) 241 { 242 AddNewPointInMap(x, y); 243 break; 244 } 245 246 newX = x; 247 newY = y + 1; 248 } 249 break; 250 } 251 } 252 253 /// <summary> 254 /// 增加新点进地图 255 /// </summary> 256 /// <param name="x"></param> 257 /// <param name="y"></param> 258 private void AddNewPointInMap(int x, int y) 259 { 260 mapPointStates[x, y].state = 1; 261 262 if (!mapQueue.Contains(mapPointStates[x, y])) 263 { 264 mapQueue.Enqueue(mapPointStates[x, y]); 265 } 266 267 if (!pathStack.Contains(mapPointStates[x, y])) 268 { 269 pathStack.Push(mapPointStates[x, y]); 270 } 271 } 272 /// <summary> 273 /// 创建所有路径 274 /// </summary> 275 private void CreateAllPath() 276 { 277 for (int i = 0; i < worldHeight; i++) 278 { 279 for (int j = 0; j < worldWidth; j++) 280 { 281 pathImages[i, j] = Instantiate(image, new Vector3(i * 32, j * 32, 0), Quaternion.identity, mainCanvas); 282 } 283 } 284 } 285 /// <summary> 286 /// 设置路径颜色 287 /// </summary> 288 /// <param name="mapPointState"></param> 289 private void SetPathColor(MapPointState mapPointState) 290 { 291 if (mapPointState.isVisit) 292 pathImages[mapPointState.x, mapPointState.y].color = new Color(0, 1, 0, 1); 293 else 294 pathImages[mapPointState.x, mapPointState.y].color = new Color(1, 1, 1, 1); 295 } 296 /// <summary> 297 /// 等待显示 298 /// </summary> 299 /// <returns></returns> 300 private IEnumerator WaitAndShow() 301 { 302 while (true) 303 { 304 yield return new WaitForSeconds(0.1f); 305 306 if (mapQueue.Count > 0) 307 { 308 SetPathColor(mapQueue.Peek()); 309 mapQueue.Dequeue(); 310 } 311 312 if (isReadyStop && mapQueue.Count == 0) 313 { 314 print("End"); 315 StopCoroutine(coroutine); 316 } 317 } 318 } 319 }
另附上工程文件:
https://files.cnblogs.com/files/JinT-Hwang/NewUnityProject1.7z
欢迎交流指教:)