【趣味】【ゲーム開発】ダンジョン生成作成(実装途中)
学生時代に作っていた、ダンジョン生成プログラム実装を思い出し、
今日できるところまで進めてみた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
using System.Collections.Generic; using UnityEngine; /// <summary> ダンジョン </summary> public class Dungeon : MonoBehaviour { /// <summary> 方向 </summary> enum Direction { DOWN, LEFT, RIGHT, UP } /// <summary> 反転 </summary> Direction Flip(Direction direction) { switch (direction) { case Direction.DOWN: return Direction.UP; case Direction.LEFT: return Direction.RIGHT; case Direction.RIGHT: return Direction.LEFT; case Direction.UP: return Direction.DOWN; default: return Direction.DOWN; } } /// <summary> 区画クラス </summary> class Block { /// <summary> 区画フラグ </summary> public enum Flag { WALL, ROOM, PASS } /// <summary> コンストラクタ </summary> public Block() { _flag = Flag.WALL; _pass = new Dictionary<Direction, bool>(); } /// <summary> 区画フラグ </summary> public Flag _flag; /// <summary> 方向ごとの通路生成フラグ </summary> public Dictionary<Direction, bool> _pass; } /// <summary> 更新処理 </summary> void Update() { // ダンジョン生成 if (_makeDungeon) { MakeDungeon(); _makeDungeon = false; } } /// <summary> ダンジョン生成関数 </summary> void MakeDungeon() { // 計算用座標 Vector2Int temp = new Vector2Int(); // マス情報全初期化 _gridQty = _bGridQty * _blockQty; _grids = new bool[_gridQty.y, _gridQty.x]; for (int y = 0; y < _gridQty.y; y++) { for (int x = 0; x < _gridQty.x; x++) { _grids[y, x] = false; } } // 区画リスト初期化 Block[,] _blocks = new Block[_blockQty.y, _blockQty.x]; for (int y = 0; y < _blockQty.y; y++) { for (int x = 0; x < _blockQty.x; x++) { _blocks[y, x] = new Block(); } } // 部屋区画セット List<Vector2Int> _searchRooms = new List<Vector2Int>(); while (_searchRooms.Count < _roomQty) { temp.x = Random.Range(0, _blockQty.x); temp.y = Random.Range(0, _blockQty.y); if (_blocks[temp.y, temp.x]._flag == Block.Flag.WALL) { _blocks[temp.y, temp.x]._flag = Block.Flag.ROOM; _searchRooms.Add(temp); } } // 通路の区画をセット temp = _searchRooms[0]; _searchRooms.RemoveAt(0); while (_searchRooms.Count > 0) { // 探索方向を決め、移動可能か確認 Direction direction = (Direction)Random.Range(0, 4); bool canMove = false; switch (direction) { case Direction.DOWN: canMove = temp.y > 0; break; case Direction.LEFT: canMove = temp.x > 0; break; case Direction.RIGHT: canMove = temp.x < _blockQty.x - 1; break; case Direction.UP: canMove = temp.y < _blockQty.y - 1; break; } // 移動できない場合、処理スキップ if (!canMove) { continue; } // 移動前、移動方向に通路フラグをセット _blocks[temp.y, temp.x]._pass[direction] = true; // 移動方向に移動 switch (direction) { case Direction.DOWN: temp.y--; break; case Direction.LEFT: temp.x--; break; case Direction.RIGHT: temp.x++; break; case Direction.UP: temp.y++; break; } // 移動後、反転させた移動方向に通路フラグをセット _blocks[temp.y, temp.x]._pass[Flip(direction)] = true; // 移動先の区画により処理分岐 switch (_blocks[temp.y, temp.x]._flag) { // 移動先が壁の時、通路化 case Block.Flag.WALL: _blocks[temp.y, temp.x]._flag = Block.Flag.PASS; break; // 移動先が部屋の時、見つけた部屋を探索リストから除外 case Block.Flag.ROOM: for (int i = 0; i < _searchRooms.Count; i++) { if (temp == _searchRooms[i]) { _searchRooms.RemoveAt(i); } } break; } } // 仮出力処理 _output = ""; for (int y = 0; y < _blockQty.y; y++) { for (int x = 0; x < _blockQty.x; x++) { switch (_blocks[y, x]._flag) { case Block.Flag.WALL: _output += "■"; break; case Block.Flag.ROOM: _output += "◇"; break; case Block.Flag.PASS: _output += "□"; break; } } _output += "\n"; } } /// <summary> マス </summary> bool[,] _grids; /// <summary> 区画数 </summary> [SerializeField] Vector2Int _blockQty; /// <summary> 区画内マス数 </summary> [SerializeField] Vector2Int _bGridQty; /// <summary> 全体マス数 </summary> [SerializeField] Vector2Int _gridQty; /// <summary> 部屋数 </summary> [SerializeField] int _roomQty; /// <summary> ダンジョン生成フラグ </summary> [SerializeField] bool _makeDungeon; /// <summary> 仮出力先 </summary> [SerializeField, TextArea] string _output; } |
↓実行時のインスペクタ表示
■:壁区画 □:通路区画 ◇:部屋区画
全ての部屋区画を通路区画がつないでいるのがわかると思う。
MakeDungeonにチェックを入れ、何度再生成してもそうなる。
明日は仮完成までは持っていきたい。
…更新が遅いのはスマブラの影響だ。
超楽しいので時間を取られすぎないように注意しないと。