using System.Collections.Generic; using Godot; /// <summary> /// 地牢生成器 /// </summary> public class GenerateDungeon { public readonly TileMap TileMap; public RoomInfo StartRoom; private Grid<bool> _roomGrid = new Grid<bool>(); private List<RoomInfo> _roomInfos = new List<RoomInfo>(); private int _count = 0; private int _maxCount = 15; public GenerateDungeon(TileMap tileMap) { TileMap = tileMap; } public void Generate() { StartRoom = GenerateRoom(null, 0); while (_count < _maxCount) { var room = Utils.RandChoose(_roomInfos); var nextRoom = GenerateRoom(room, Utils.RandRangeInt(0, 3)); if (nextRoom != null) { room.Next.Add(nextRoom); //找门 FindDoor(room, nextRoom); } } foreach (var info in _roomInfos) { //临时铺上地砖 var id = (int)TileMap.TileSet.GetTilesIds()[0]; for (int i = 0; i < info.Size.x; i++) { for (int j = 0; j < info.Size.y; j++) { TileMap.SetCell(i + (int)info.Position.x, j + (int)info.Position.y, id); } } } } private RoomInfo GenerateRoom(RoomInfo prevRoomInfo, int direction) { if (_count >= _maxCount) { return null; } var room = new RoomInfo(_count); room.Size = new Vector2(Utils.RandRangeInt(25, 60), Utils.RandRangeInt(25, 45)); room.Position = Vector2.Zero; if (prevRoomInfo != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡 { //房间间隔 var space = Utils.RandRangeInt(6, 12); //中心偏移 int offset; if (direction == 0 || direction == 2) { offset = Utils.RandRangeInt(-(int)(prevRoomInfo.Size.y * 0.7f), (int)(prevRoomInfo.Size.y * 0.7f)); } else { offset = Utils.RandRangeInt(-(int)(prevRoomInfo.Size.x * 0.7f), (int)(prevRoomInfo.Size.x * 0.7f)); } //计算房间位置 if (direction == 0) //上 { room.Position = new Vector2(prevRoomInfo.Position.x + offset, prevRoomInfo.Position.y - room.Size.y - space); } else if (direction == 1) //右 { room.Position = new Vector2(prevRoomInfo.Position.x + prevRoomInfo.Size.y + space, prevRoomInfo.Position.y + offset); } else if (direction == 2) //下 { room.Position = new Vector2(prevRoomInfo.Position.x + offset, prevRoomInfo.Position.y + prevRoomInfo.Size.y + space); } else if (direction == 3) //左 { room.Position = new Vector2(prevRoomInfo.Position.x - room.Size.x - space, prevRoomInfo.Position.y + offset); } //是否碰到其他房间 if (_roomGrid.RectCollision(room.Position - new Vector2(2, 2), room.Size + new Vector2(4, 4))) { return null; } } _count++; _roomInfos.Add(room); _roomGrid.AddRect(room.Position, room.Size, true); //下一个房间 //0上, 1右, 2下, 3左 var dirList = new List<int>(new []{ 0, 1, 2, 3 }); if (prevRoomInfo != null) { dirList.Remove(GetReverseDirection(direction)); } if (Utils.RandRangeInt(0, 2) != 0) { while (dirList.Count > 0) { var randDir = Utils.RandChoose(dirList); var nextRoom = GenerateRoom(room, randDir); if (nextRoom == null) { break; } nextRoom.Prev = room; room.Next.Add(nextRoom); dirList.Remove(randDir); //找门 FindDoor(room, nextRoom); } } return room; } /// <summary> /// 找两个房间的门 /// </summary> private void FindDoor(RoomInfo room, RoomInfo nextRoom) { if (Mathf.Min(room.Position.x + room.Size.x, nextRoom.Position.x + nextRoom.Size.x) - Mathf.Max(room.Position.x, nextRoom.Position.x) >= 6) //x轴 { GD.Print("----1: " + room.Id + ", " + nextRoom.Id); //找到重叠区域 var range = CalcRange(room.Position.x, room.Position.x + room.Size.x, nextRoom.Position.x, nextRoom.Position.x + nextRoom.Size.x); var x = Utils.RandRangeInt((int)range.x, (int)range.y - 4); //门描述 var roomDoor = new RoomDoor(); var nextRoomDoor = new RoomDoor(); roomDoor.ConnectRoom = nextRoom; nextRoomDoor.ConnectRoom = room; if (room.Position.y < nextRoom.Position.y) //room在上, nextRoom在下 { roomDoor.Direction = DoorDirection.S; nextRoomDoor.Direction = DoorDirection.N; roomDoor.OriginPosition = new Vector2(x, room.Position.y + room.Size.y); nextRoomDoor.OriginPosition = new Vector2(x, nextRoom.Position.y); } else //room在下, nextRoom在上 { roomDoor.Direction = DoorDirection.N; nextRoomDoor.Direction = DoorDirection.S; roomDoor.OriginPosition = new Vector2(x, room.Position.y); nextRoomDoor.OriginPosition = new Vector2(x, nextRoom.Position.y + nextRoom.Size.y); } room.Doors.Add(roomDoor); nextRoom.Doors.Add(nextRoomDoor); } else if (Mathf.Min(room.Position.y + room.Size.y, nextRoom.Position.y + nextRoom.Size.y) - Mathf.Max(room.Position.y, nextRoom.Position.y) >= 6) //y轴 { GD.Print("----2: " + room.Id + ", " + nextRoom.Id); //找到重叠区域 var range = CalcRange(room.Position.y, room.Position.y + room.Size.y, nextRoom.Position.y, nextRoom.Position.y + nextRoom.Size.y); var y = Utils.RandRangeInt((int)range.x, (int)range.y - 4); //门描述 var roomDoor = new RoomDoor(); var nextRoomDoor = new RoomDoor(); roomDoor.ConnectRoom = nextRoom; nextRoomDoor.ConnectRoom = room; if (room.Position.x < nextRoom.Position.x) //room在左, nextRoom在右 { roomDoor.Direction = DoorDirection.E; nextRoomDoor.Direction = DoorDirection.W; roomDoor.OriginPosition = new Vector2(room.Position.x + room.Size.x, y); nextRoomDoor.OriginPosition = new Vector2(nextRoom.Position.x, y); } else //room在右, nextRoom在左 { roomDoor.Direction = DoorDirection.W; nextRoomDoor.Direction = DoorDirection.E; roomDoor.OriginPosition = new Vector2(room.Position.x, y); nextRoomDoor.OriginPosition = new Vector2(nextRoom.Position.x + nextRoom.Size.x, y); } room.Doors.Add(roomDoor); nextRoom.Doors.Add(nextRoomDoor); } else { GD.Print("----3: " + room.Id + ", " + nextRoom.Id); //门描述 var roomDoor = new RoomDoor(); var nextRoomDoor = new RoomDoor(); roomDoor.ConnectRoom = nextRoom; nextRoomDoor.ConnectRoom = room; if (room.Position.x > nextRoom.Position.x) { if (room.Position.y > nextRoom.Position.y) { if (Utils.RandBoolean()) { roomDoor.Direction = DoorDirection.N; nextRoomDoor.Direction = DoorDirection.E; } else { roomDoor.Direction = DoorDirection.W; nextRoomDoor.Direction = DoorDirection.S; } } else { if (Utils.RandBoolean()) { roomDoor.Direction = DoorDirection.S; nextRoomDoor.Direction = DoorDirection.E; } else { roomDoor.Direction = DoorDirection.W; nextRoomDoor.Direction = DoorDirection.N; } } } else { if (room.Position.y > nextRoom.Position.y) { if (Utils.RandBoolean()) { roomDoor.Direction = DoorDirection.E; nextRoomDoor.Direction = DoorDirection.S; } else { roomDoor.Direction = DoorDirection.N; nextRoomDoor.Direction = DoorDirection.W; } } else { if (Utils.RandBoolean()) { roomDoor.Direction = DoorDirection.E; nextRoomDoor.Direction = DoorDirection.N; } else { roomDoor.Direction = DoorDirection.S; nextRoomDoor.Direction = DoorDirection.W; } } } //var temp = room.Position - nextRoom.Position; } } private Vector2 CalcRange(float start1, float end1, float start2, float end2) { return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2)); } private int GetReverseDirection(int direction) { switch (direction) { case 0: return 2; case 1: return 3; case 2: return 0; case 3: return 1; } return 2; } }