本文对随机生成迷宫的实现思路进行记录,其作用在于为游戏过程提供随机性以及节省开发周期,下面是Dungeonize的结构
随机迷宫的生成主要包括几个阶段
1.生成房间体结构,为墙体,自定义房间,自定义物体生成平台
1 for (var i = 0; i < room_count; i++) { 2 Room room = new Room (); 3 if (rooms.Count == 0) { 4 //初始房间生成玩家和任务事件监听 5 room.x = (int)Mathf.Floor (map_size / 2f); 6 room.y = (int)Mathf.Floor (map_size / 2f); //Random.Range(10,20); 7 room.w = Random.Range (min_size, max_size); 8 if (room.w % 2 == 0) room.w += 1; 9 room.h = Random.Range (min_size, max_size); 10 if (room.h % 2 == 0) room.h += 1; 11 room.branch = 0; 12 lastRoom = room; 13 } else { 14 int branch = 0; 15 if (collision_count == 0) { 16 branch = Random.Range (5, 20); //complexity 17 } 18 room.branch = branch; 19 20 lastRoom = rooms [rooms.Count - 1]; 21 int lri = 1; 22 23 while (lastRoom.dead_end) { 24 lastRoom = rooms [rooms.Count - lri++]; 25 } 26 27 28 if (direction == "set") { 29 string newRandomDirection = directions[Random.Range(0, directions.Count)]; 30 direction = newRandomDirection; 31 while (direction == oldDirection) 32 { 33 newRandomDirection = directions[Random.Range(0, directions.Count)]; 34 direction = newRandomDirection; 35 } 36 37 } 38 this.roomMarginTemp = Random.RandomRange(0, this.roomMargin - 1); 39 //邻接方位生成房间 40 if (direction == "y") { 41 room.x = lastRoom.x + lastRoom.w + Random.Range (3, 5) + this.roomMarginTemp; 42 room.y = lastRoom.y; 43 } else if (direction == "-y") { 44 room.x = lastRoom.x - lastRoom.w - Random.Range (3, 5) - this.roomMarginTemp; 45 room.y = lastRoom.y; 46 } else if (direction == "x") { 47 room.y = lastRoom.y + lastRoom.h + Random.Range (3, 5) + this.roomMarginTemp; 48 room.x = lastRoom.x; 49 } else if (direction == "-x") { 50 room.y = lastRoom.y - lastRoom.h - Random.Range (3, 5) - this.roomMarginTemp; 51 room.x = lastRoom.x; 52 } 53 54 room.w = Random.Range (min_size, max_size); 55 if (room.w % 2 == 0) room.w += 1; 56 57 room.h = Random.Range (min_size, max_size); 58 if (room.h % 2 == 0) room.h += 1; 59 60 room.connectedTo = lastRoom; 61 }
在随机产生生成房间体后,生成墙体形成一个完整的房间结构,为之后prefab提供空间
//wall
for (int x = 0; x < map_size_x -1; x++) { for (int y = 0; y < map_size_y -1; y++) { if (map [x, y].type == 0) { if (map [x + 1, y].type == 1 || map [x + 1, y].type == 3) { //west map [x, y].type = 11; map [x, y].room = map [x + 1, y].room; } if (x > 0) { if (map [x - 1, y].type == 1 || map [x - 1, y].type == 3) { //east map [x, y].type = 9; map [x, y].room = map [x - 1, y].room; } } if (map [x, y + 1].type == 1 || map [x, y + 1].type == 3) { //south map [x, y].type = 10; map [x, y].room = map [x, y + 1].room; } if (y > 0) { if (map [x, y - 1].type == 1 || map [x, y - 1].type == 3) { //north map [x, y].type = 8; map [x, y].room = map [x, y - 1].room; } } } } }
通过list存储方位参数
//tile types for ease public static List<int> roomsandfloors = new List<int> { 1, 3 }; public static List<int> corners = new List<int> {4,5,6,7}; public static List<int> walls = new List<int> {8,9,10,11}; //wall direction private static List<string> directions = new List<string> {"x","y","-y","-x"}; //,"-y"};
根据lis存储过道结构
1 //corners 2 for (int x = 0; x < map_size_x -1; x++) { 3 for (int y = 0; y < map_size_y -1; y++) { 4 if (walls.Contains (map [x, y + 1].type) && walls.Contains (map [x + 1, y].type) && roomsandfloors.Contains (map [x + 1, y + 1].type)) { //north 5 map [x, y].type = 4; 6 map [x, y].room = map [x + 1, y + 1].room; 7 } 8 if (y > 0) { 9 if (walls.Contains (map [x + 1, y].type) && walls.Contains (map [x, y - 1].type) && roomsandfloors.Contains (map [x + 1, y - 1].type)) { //north 10 map [x, y].type = 5; 11 map [x, y].room = map [x + 1, y - 1].room; 12 13 } 14 } 15 if (x > 0) { 16 if (walls.Contains (map [x - 1, y].type) && walls.Contains (map [x, y + 1].type) && roomsandfloors.Contains (map [x - 1, y + 1].type)) { //north 17 map [x, y].type = 7; 18 map [x, y].room = map [x - 1, y + 1].room; 19 20 } 21 } 22 if (x > 0 && y > 0) { 23 if (walls.Contains (map [x - 1, y].type) && walls.Contains (map [x, y - 1].type) && roomsandfloors.Contains (map [x - 1, y - 1].type)) { //north 24 map [x, y].type = 6; 25 map [x, y].room = map [x - 1, y - 1].room; 26 27 } 28 } 29 /* door corners --- a bit problematic in this version */ 30 if (map [x, y].type == 3) { 31 if (map [x + 1, y].type == 1) { 32 map [x, y + 1].type = 11; 33 map [x, y - 1].type = 11; 34 } else if (Dungeon.map [x - 1, y].type == 1) { 35 map [x, y + 1].type = 9; 36 map [x, y - 1].type = 9; 37 } 38 } 39 40 } 41 }
这样一个房间体的完整结构已经创建完毕,之后对迷宫结构生成地下城结构
for (var y = 0; y < Dungeon.map_size_y; y++) { for (var x = 0; x < Dungeon.map_size_x; x++) { int tile = Dungeon.map [x, y].type; int orientation = Dungeon.map[x, y].orientation; GameObject created_tile; Vector3 tile_location; if (!makeIt3d) { tile_location = new Vector3 (x * tileScaling, y * tileScaling, 0); } else { tile_location = new Vector3 (x * tileScaling, 0, y * tileScaling); } created_tile = null; if (tile == 1) { GameObject floorPrefabToUse = floorPrefab; Room room = Dungeon.map[x,y].room; if(room != null){ foreach(CustomRoom customroom in customRooms){ if(customroom.roomId == room.room_id){ floorPrefabToUse = customroom.floorPrefab; break; } } } created_tile = GameObject.Instantiate (floorPrefabToUse, tile_location, Quaternion.identity) as GameObject; } if ( Dungeon.walls.Contains(tile)) { GameObject wallPrefabToUse = wallPrefab; Room room = Dungeon.map[x,y].room; if(room != null){ foreach(CustomRoom customroom in customRooms){ if(customroom.roomId == room.room_id){ wallPrefabToUse = customroom.wallPrefab; break; } } } created_tile = GameObject.Instantiate (wallPrefabToUse, tile_location, Quaternion.identity) as GameObject; if(!makeIt3d){ created_tile.transform.Rotate(Vector3.forward * (-90 * (tile -4))); } else{ created_tile.transform.Rotate(Vector3.up * (-90 * (tile -4))); } } if (tile == 3) { if (corridorFloorPrefab) { created_tile = GameObject.Instantiate(corridorFloorPrefab, tile_location, Quaternion.identity) as GameObject; } else { created_tile = GameObject.Instantiate(floorPrefab, tile_location, Quaternion.identity) as GameObject; } if (orientation == 1 && makeIt3d) { created_tile.transform.Rotate(Vector3.up * (-90)); } } if (Dungeon.corners.Contains(tile)) { GameObject cornerPrefabToUse = cornerPrefab; Room room = Dungeon.map[x,y].room; if(room != null){ foreach(CustomRoom customroom in customRooms){ if(customroom.roomId == room.room_id){ cornerPrefabToUse = customroom.cornerPrefab; break; } } } if(cornerPrefabToUse){ //there was a bug in this line. A good man helped for fix. created_tile = GameObject.Instantiate (cornerPrefabToUse, tile_location, Quaternion.identity) as GameObject; if(cornerRotation){ if(!makeIt3d){ created_tile.transform.Rotate(Vector3.forward * (-90 * (tile -4))); } else{ created_tile.transform.Rotate(Vector3.up * (-90 * (tile -4))); } } } else{ created_tile = GameObject.Instantiate (wallPrefab, tile_location, Quaternion.identity) as GameObject; } } if (created_tile) { created_tile.transform.parent = transform; } } }
迷宫生成后,需要对房间内容进行添加,随机的物品以及房间为玩家提供游玩条件,特定的内容包含战斗条件或者任务条件
//Spawn Objects; List<SpawnList> spawnedObjectLocations = new List<SpawnList> (); //OTHERS for (int x = 0; x < Dungeon.map_size_x; x++) { for (int y = 0; y < Dungeon.map_size_y; y++) { if (Dungeon.map [x, y].type == 1 && ((Dungeon.startRoom != Dungeon.map [x, y].room && Dungeon.goalRoom != Dungeon.map [x, y].room) || maximumRoomCount <= 3)) { var location = new SpawnList (); location.x = x; location.y = y; if (Dungeon.walls.Contains(Dungeon.map[x + 1, y].type)) { location.byWall = true; location.wallLocation = "S"; } else if (Dungeon.walls.Contains(Dungeon.map[x - 1, y].type)) { location.byWall = true; location.wallLocation = "N"; } else if (Dungeon.walls.Contains(Dungeon.map[x, y + 1].type)) { location.byWall = true; location.wallLocation = "W"; } else if (Dungeon.walls.Contains(Dungeon.map [x, y - 1].type)) { location.byWall = true; location.wallLocation = "E"; } if (Dungeon.map [x + 1, y].type == 3 || Dungeon.map [x - 1, y].type == 3 || Dungeon.map [x, y + 1].type == 3 || Dungeon.map [x, y - 1].type == 3) { location.byCorridor = true; } if (Dungeon.map [x + 1, y + 1].type == 3 || Dungeon.map [x - 1, y - 1].type == 3 || Dungeon.map [x - 1, y + 1].type == 3 || Dungeon.map [x + 1, y - 1].type == 3) { location.byCorridor = true; } location.room = Dungeon.map[x,y].room; int roomCenterX = (int)Mathf.Floor(location.room.w / 2) + location.room.x; int roomCenterY = (int)Mathf.Floor(location.room.h / 2) + location.room.y; if(x == roomCenterX + 1 && y == roomCenterY + 1 ) { location.inTheMiddle = true; } spawnedObjectLocations.Add (location); } else if (Dungeon.map [x, y].type == 3) { var location = new SpawnList (); location.x = x; location.y = y; if (Dungeon.map [x + 1, y].type == 1 ) { location.byCorridor = true; location.asDoor = 4; location.room = Dungeon.map[x + 1,y].room; spawnedObjectLocations.Add (location); } else if(Dungeon.map [x - 1, y].type == 1){ location.byCorridor = true; location.asDoor = 2; location.room = Dungeon.map[x - 1,y].room; spawnedObjectLocations.Add (location); } else if (Dungeon.map [x, y + 1].type == 1 ){ location.byCorridor = true; location.asDoor = 1; location.room = Dungeon.map[x,y + 1].room; spawnedObjectLocations.Add (location); } else if (Dungeon.map [x, y - 1].type == 1){ location.byCorridor = true; location.asDoor = 3; location.room = Dungeon.map[x,y - 1].room; spawnedObjectLocations.Add (location); } } } }
这样就能生成基本的随机模型
2d ver
3d ver
也可以根据需求进行修改