前回紹介した迷路の自動生成アルコリズムを可視化してみました。
smartgames.hatenablog.com
今回は前回使用した穴掘り法の他に棒倒し法も可視化してみます。
■実装(穴掘り法)
コードの中身は前回のものとあまりかわりません
using System; using System.Linq; using System.Collections; using System.Collections.Generic; using UnityEngine; public class MazeBuilder : MonoBehaviour { [SerializeField] private GameObject ground; [SerializeField] private GameObject wallPrefab; [SerializeField] private Camera mainCamera; private int mazeHeight; private int mazeWidth; private bool[,] maze; private GameObject[,] mazeObject; private List<Vector2> searchDirections = new List<Vector2> { Vector2.up, Vector2.down, Vector2.right, Vector2.left }; private void Start() { CreateMaze(21, 21); } private void CreateMaze(int height, int width) { mazeWidth = width; mazeHeight = height; InitializeMaze(); StartCoroutine(DigMaze()); } private void InitializeMaze() { maze = new bool[mazeWidth, mazeHeight]; mazeObject = new GameObject[mazeWidth, mazeHeight]; for (int i = 0; i < mazeWidth; i++) { for (int j = 0; j < mazeHeight; j++) { maze[i, j] = true; mazeObject[i, j] = Instantiate(wallPrefab, new Vector3(i, 0, j), Quaternion.identity) as GameObject; } } var centered = new Vector3(mazeWidth / 2f - 0.5f, 0, mazeHeight / 2f - 0.5f); ground.transform.localScale = new Vector3(mazeWidth, 1, mazeHeight); ground.transform.position = centered + Vector3.down * 0.5f; mainCamera.transform.position = centered + Vector3.up * ((mazeWidth + mazeHeight) / 2f); } private IEnumerator DigMaze() { int startPosW = Enumerable.Range(0, mazeWidth).Where(i => i % 2 != 0).OrderBy(i => Guid.NewGuid()).First(); int startPosH = Enumerable.Range(0, mazeHeight).Where(i => i % 2 != 0).OrderBy(i => Guid.NewGuid()).First(); yield return Dig(new Vector2(startPosW, startPosH)); } private IEnumerator Dig(Vector2 point) { yield return RemoveWall(point); foreach (var dir in searchDirections.OrderBy(i => Guid.NewGuid())){ var checkPos = point + dir * 2; if (IsInBoard(checkPos) && maze[(int)checkPos.x, (int)checkPos.y]) { yield return RemoveWall(point + dir); yield return Dig(checkPos); } } } private IEnumerator RemoveWall(Vector2 point) { var w = (int)point.x; var h = (int)point.y; maze[w, h] = false; Destroy(mazeObject[w, h]); yield return new WaitForSeconds(0.05f); } private bool IsInBoard(Vector2 pos) { return pos.x >= 0 && pos.y >= 0 && pos.x < mazeWidth && pos.y < mazeHeight; } }
■実装(棒倒し法)
using System; using System.Linq; using System.Collections; using System.Collections.Generic; using UnityEngine; public class MazeBuilder2 : MonoBehaviour { [SerializeField] private GameObject ground; [SerializeField] private GameObject wallPrefab; [SerializeField] private Camera mainCamera; private int mazeHeight; private int mazeWidth; private bool[,] maze; private List<Vector2> searchDirectionsFirst = new List<Vector2> { Vector2.up, Vector2.down, Vector2.right, Vector2.left }; private List<Vector2> searchDirections = new List<Vector2> { Vector2.up, Vector2.right, Vector2.left }; private void Start() { CreateMaze(21, 21); } private void CreateMaze(int height, int width) { mazeWidth = width; mazeHeight = height; InitializeMaze(); StartCoroutine(CreateMaze()); } private void InitializeMaze() { maze = new bool[mazeWidth, mazeHeight]; var centered = new Vector3(mazeWidth / 2f - 0.5f, 0, mazeHeight / 2f - 0.5f); ground.transform.localScale = new Vector3(mazeWidth, 1, mazeHeight); ground.transform.position = centered + Vector3.down * 0.5f; mainCamera.transform.position = centered + Vector3.up * ((mazeWidth + mazeHeight) / 2f); } private IEnumerator CreateMaze() { var startPositions = new List<Vector2>(); for (int i = 0; i < mazeWidth; i++) { for (int j = 0; j < mazeWidth; j++) { if (i == 0 || j == 0 || i == mazeWidth - 1 || j == mazeWidth - 1 ) { Instantiate(wallPrefab, new Vector3(i, 0.5f, j), Quaternion.identity); } else if (i % 2 == 0 && j % 2 == 0) { Instantiate(wallPrefab, new Vector3(i, 0.5f, j), Quaternion.identity); startPositions.Add(new Vector2(i, j)); } } } foreach (var pos in startPositions) { if (pos.x == 2) { foreach (var dir in searchDirectionsFirst.OrderBy(i => Guid.NewGuid())) { var checkPos = pos + dir; if (maze[(int)checkPos.x, (int)checkPos.y]) { continue; } else { yield return CreateWall(checkPos); break; } } } else { foreach (var dir in searchDirections.OrderBy(i => Guid.NewGuid())) { var checkPos = pos + dir; if (maze[(int)checkPos.x, (int)checkPos.y]) { continue; } else { yield return CreateWall(checkPos); break; } } } } yield break; } private IEnumerator CreateWall(Vector2 position) { maze[(int)position.x, (int)position.y] = true; Instantiate(wallPrefab, new Vector3(position.x, 0.5f, position.y), Quaternion.identity); yield return new WaitForSeconds(0.05f); } }
■実行(穴掘り法)
■実行(棒倒し法)
■まとめ
迷路が作られていく様子は見ていて楽しい
■参考
自動生成迷路