public void Register(FloorChunk Chunk) { if (!Chunks.ContainsKey(Chunk.Id)) { Chunks.Add(Chunk.Id, Chunk); } }
public FloorChunk Create() { var Chunk = new FloorChunk(); Chunk.Id = ++IdCounter; return(Chunk); }
void FloodFill(IntVector StartLocation, int IslandId, HashSet <IntVector> Visited, List <FloorIslandNode> IslandNodes, FloorChunkDB ChunkDB) { FloorChunk PreferedChunk = ChunkDB.GetChunkAt(StartLocation); if (!PreferedChunk.bConnectDoors) { // We don't want doors here return; } if (PreferedChunk == null) { return; } Queue <IntVector> Queue = new Queue <IntVector>(); Queue.Enqueue(StartLocation); while (Queue.Count > 0) { IntVector Location = Queue.Dequeue(); FloorChunk CurrentChunk = ChunkDB.GetChunkAt(Location); if (CurrentChunk != PreferedChunk) { continue; } // Create a node here FloorIslandNode Node = new FloorIslandNode(); Node.IslandId = IslandId; Node.Chunk = CurrentChunk; Node.Location = Location; IslandNodes.Add(Node); // Add the neighbors to the queue List <IntVector> Neighbors = new List <IntVector>(); Neighbors.Add(Location + new IntVector(-1, 0, 0)); Neighbors.Add(Location + new IntVector(1, 0, 0)); Neighbors.Add(Location + new IntVector(0, 0, 1)); Neighbors.Add(Location + new IntVector(0, 0, -1)); foreach (IntVector Neighbor in Neighbors) { if (Visited.Contains(Neighbor)) { continue; } FloorChunk NeighborChunk = ChunkDB.GetChunkAt(Neighbor); if (NeighborChunk != null && NeighborChunk.Id == CurrentChunk.Id) { Queue.Enqueue(Neighbor); Visited.Add(Neighbor); } } } }
FloorChunk GetPriorityChunk(FloorChunk A, FloorChunk B) { if (A == null) { return(B); } if (B == null) { return(A); } return(A.Priority > B.Priority ? A : B); }
public int Compare(int IslandA, int IslandB) { FloorChunk ChunkA = IslandToChunkMap.ContainsKey(IslandA) ? IslandToChunkMap[IslandA] : null; FloorChunk ChunkB = IslandToChunkMap.ContainsKey(IslandB) ? IslandToChunkMap[IslandB] : null; int ScoreA = GetChunkDoorConnectionScore(ChunkA); int ScoreB = GetChunkDoorConnectionScore(ChunkB); if (ScoreA == ScoreB) { return(0); } return(ScoreA < ScoreB ? 1 : -1); }
void SplitChunk(FloorChunk Chunk, FloorChunk OutLeft, FloorChunk OutRight) { int MinRoomLength = floorPlanConfig.MinRoomSize; int Length = Chunk.GetLength(); int LengthLeft = MinRoomLength + random.Next(0, Mathf.Max(0, Length - MinRoomLength * 2)); int LengthRight = Length - LengthLeft; OutLeft.Bounds = Chunk.Bounds; OutLeft.ChunkType = FloorChunkType.Room; OutLeft.SetLength(LengthLeft); OutRight.Bounds = Chunk.Bounds; OutRight.OffsetAlongLength(LengthLeft); OutRight.ChunkType = FloorChunkType.Room; OutRight.SetLength(LengthRight); }
void SplitChunk(FloorChunk Chunk, FloorChunk OutLeft, FloorChunk OutRight, FloorChunk OutHallway) { int HallWidth = floorPlanConfig.HallWidth; int Length = Chunk.GetLength(); int RemainingLength = Length - HallWidth; int MinChunkLength = floorPlanConfig.MinRoomSize; int LengthLeft = MinChunkLength + random.Next(0, Mathf.Max(0, RemainingLength - MinChunkLength * 2 + 1)); int LengthRight = RemainingLength - LengthLeft; OutLeft.Bounds = Chunk.Bounds; OutLeft.ChunkType = FloorChunkType.Room; OutLeft.SetLength(LengthLeft); OutHallway.Bounds = Chunk.Bounds; OutHallway.ChunkType = FloorChunkType.Hall; OutHallway.OffsetAlongLength(LengthLeft); OutHallway.SetLength(HallWidth); OutRight.Bounds = Chunk.Bounds; OutRight.ChunkType = FloorChunkType.Room; OutRight.OffsetAlongLength(LengthLeft + HallWidth); OutRight.SetLength(LengthRight); }
string GetDoorMarkerName(FloorChunk ChunkA, FloorChunk ChunkB) { if (ChunkA == null && ChunkB == null) { return(FloorPlanMarkers.MARKER_DOOR); } FloorChunk PreferedChunk; if (ChunkA == null) { PreferedChunk = ChunkB; } else if (ChunkB == null) { PreferedChunk = ChunkA; } else { PreferedChunk = (ChunkA.Priority > ChunkB.Priority) ? ChunkA : ChunkB; } return(PreferedChunk.DoorMarker.Length > 0 ? PreferedChunk.DoorMarker : FloorPlanMarkers.MARKER_DOOR); }
//////////////////////////// Door connection ////////////////////////// static int GetChunkDoorConnectionScore(FloorChunk Chunk) { if (Chunk == null) { return(-1000); } if (Chunk.bReachable) { return(-500); } if (!Chunk.bConnectDoors) { return(-1000); } if (Chunk.ChunkType == FloorChunkType.Hall) { return(1000); } if (Chunk.ChunkType == FloorChunkType.Room) { return(500); } return(0); }
/// <summary> /// Generate a layout and save it in the model /// </summary> void EmitBuildingMarkers() { floorPlanConfig = config as FloorPlanConfig; floorPlanModel = model as FloorPlanModel; ClearSockets(); //TArray<AFloorPlanDoorVolume*> DoorVolumes = UDungeonModelHelper::GetVolumes<AFloorPlanDoorVolume>(Dungeon) ClearSockets(); int NumFloors = Mathf.RoundToInt(floorPlanConfig.BuildingSize.y); Vector3 GridSize = floorPlanConfig.GridSize; bool bBuildingWallLeft, bBuildingWallBottom; for (int y = 0; y < NumFloors; y++) { for (int x = -1; x < floorPlanConfig.BuildingSize.x; x++) { bBuildingWallLeft = (x == -1 || x == floorPlanConfig.BuildingSize.x - 1); for (int z = -1; z < floorPlanConfig.BuildingSize.z; z++) { bBuildingWallBottom = (z == -1 || z == floorPlanConfig.BuildingSize.z - 1); FloorChunk Chunk00 = ChunkDB.GetChunkAt(x, y, z); FloorChunk Chunk10 = ChunkDB.GetChunkAt(x + 1, y, z); FloorChunk Chunk01 = ChunkDB.GetChunkAt(x, y, z + 1); string GroundMarkerName = FloorPlanMarkers.MARKER_GROUND; string CeilingMarkerName = FloorPlanMarkers.MARKER_CEILING; FloorChunk ChunkAbove = ChunkDB.GetChunkAt(x, y + 1, z); FloorChunk ChunkBelow = ChunkDB.GetChunkAt(x, y - 1, z); bool bEmitGroundMarker = (Chunk00 != ChunkBelow); bool bEmitCeilingMarker = (Chunk00 != ChunkAbove); // Emit the ground marker if (Chunk00 != null && Chunk00.ChunkType != FloorChunkType.Outside) { if (bEmitGroundMarker) { Vector3 GridLocation = new Vector3(x + 0.5f, y, z + 0.5f); Vector3 WorldLocation = Vector3.Scale(GridLocation, GridSize); if (Chunk00.GroundMarker.Length > 0) { GroundMarkerName = Chunk00.GroundMarker; } EmitMarkerAt(WorldLocation, GroundMarkerName, 0); } if (bEmitCeilingMarker) { Vector3 GridLocation = new Vector3(x + 0.5f, y + 1, z + 0.5f); Vector3 WorldLocation = Vector3.Scale(GridLocation, GridSize); if (Chunk00.CeilingMarker.Length > 0) { CeilingMarkerName = Chunk00.CeilingMarker; } EmitMarkerAt(WorldLocation, CeilingMarkerName, Quaternion.Euler(180, 0, 0)); } } int Chunk00Id = (Chunk00 != null ? Chunk00.Id : -1); int Chunk10Id = (Chunk10 != null ? Chunk10.Id : -1); int Chunk01Id = (Chunk01 != null ? Chunk01.Id : -1); bool bEmitLeftWall = (Chunk00Id != Chunk10Id); bool bEmitBottomWall = (Chunk00Id != Chunk01Id); bool bLeftDoor = DoorManager.ContainsDoor(new IntVector(x, y, z), new IntVector(x + 1, y, z)); // || DoorManager.ContainsDoorVolume(Vector3.Scale(new Vector(x + 1, y, z + 0.5f) * GridSize), DoorVolumes); bool bBottomDoor = DoorManager.ContainsDoor(new IntVector(x, y, z), new IntVector(x, y, z + 1)); // || DoorManager.ContainsDoorVolume(Vector3.Scale(new Vector(x + 0.5f, y, z + 1) * GridSize), DoorVolumes); if (Chunk00 != null && Chunk10 != null && Chunk00.ChunkType == FloorChunkType.Hall && Chunk10.ChunkType == FloorChunkType.Hall) { // Do not block the halls with a wall bEmitLeftWall = false; } if (Chunk00 != null && Chunk01 != null && Chunk00.ChunkType == FloorChunkType.Hall && Chunk01.ChunkType == FloorChunkType.Hall) { // Do not block the halls with a wall bEmitBottomWall = false; } if (Chunk00 != null && Chunk10 != null && (!Chunk00.bEmitGroundMarker || !Chunk10.bEmitGroundMarker)) { // We don't have ground in one of the adjacent chunks. Can't have doors bLeftDoor = false; } if (Chunk00 != null && Chunk01 != null && (!Chunk00.bEmitGroundMarker || !Chunk01.bEmitGroundMarker)) { // We don't have ground in one of the adjacent chunks. Can't have doors bBottomDoor = false; } if (bEmitLeftWall) { FloorChunk PriorityChunk = GetPriorityChunk(Chunk00, Chunk10); bEmitLeftWall = PriorityChunk != null ? PriorityChunk.bCreateWalls : true; } if (bEmitBottomWall) { FloorChunk PriorityChunk = GetPriorityChunk(Chunk00, Chunk01); bEmitBottomWall = PriorityChunk != null ? PriorityChunk.bCreateWalls : true; } if (bEmitLeftWall) { Vector3 GridLocation = new Vector3(x + 1, y, z + 0.5f); Vector3 WorldLocation = Vector3.Scale(GridLocation, GridSize); string MarkerName; if (bLeftDoor) { MarkerName = GetDoorMarkerName(Chunk00, Chunk10); } else { MarkerName = FloorPlanMarkers.MARKER_WALL; if (bBuildingWallLeft) { MarkerName = FloorPlanMarkers.MARKER_BUILDING_WALL; } else { if (Chunk00 != null && Chunk10 != null) { FloorChunk PriorityChunk = (Chunk00.Priority > Chunk10.Priority) ? Chunk00 : Chunk10; if (PriorityChunk.WallMarker.Length > 0) { MarkerName = PriorityChunk.WallMarker; } } } } EmitMarkerAt(WorldLocation, MarkerName, 90); } if (bEmitBottomWall) { Vector3 GridLocation = new Vector3(x + 0.5f, y, z + 1); Vector3 WorldLocation = Vector3.Scale(GridLocation, GridSize); string MarkerName; if (bBottomDoor) { MarkerName = GetDoorMarkerName(Chunk00, Chunk01); } else { MarkerName = FloorPlanMarkers.MARKER_WALL; if (bBuildingWallBottom) { MarkerName = FloorPlanMarkers.MARKER_BUILDING_WALL; } else { if (Chunk00 != null && Chunk01 != null) { FloorChunk PriorityChunk = (Chunk00.Priority > Chunk01.Priority) ? Chunk00 : Chunk01; if (PriorityChunk.WallMarker.Length > 0) { MarkerName = PriorityChunk.WallMarker; } } } } EmitMarkerAt(WorldLocation, MarkerName, 0); } } } } // Emit center marker if specified List <FloorChunk> Chunks = new List <FloorChunk>(); ChunkDB.GetChunks(Chunks); foreach (FloorChunk Chunk in Chunks) { if (Chunk.bEmitGroundMarker && Chunk.CenterMarker.Length > 0) { Vector3 ChunkSize = MathUtils.ToVector3(Chunk.Bounds.Size) / 2.0f; ChunkSize.y = 0; Vector3 GridLocation = MathUtils.ToVector3(Chunk.Bounds.Location) + ChunkSize; Vector3 WorldLocation = Vector3.Scale(GridLocation, GridSize); EmitMarkerAt(WorldLocation, Chunk.CenterMarker, 0); } } }
void BuildLayout() { ChunkDB = new FloorChunkDB(); DoorManager = new FloorDoorManager(); Visited.Clear(); random = new System.Random((int)floorPlanConfig.Seed); int NumFloors = Mathf.RoundToInt(floorPlanConfig.BuildingSize.y); for (int y = 0; y < NumFloors; y++) { // Build the hallways and the intermediate floor chunks (which will hold the rooms) List <FloorChunk> FloorChunks = new List <FloorChunk>(); { FloorChunk InitialFloor = ChunkDB.Create(); InitialFloor.Bounds.Location = new IntVector(0, y, 0); InitialFloor.Bounds.Size = MathUtils.ToIntVector(floorPlanConfig.BuildingSize); Stack <FloorChunk> Stack = new Stack <FloorChunk>(); Stack.Push(InitialFloor); while (Stack.Count > 0) { FloorChunk Top = Stack.Pop(); float Area = Top.Area(); if (Area <= 0) { continue; } if (Top.Area() <= floorPlanConfig.MinRoomChunkArea) { FloorChunks.Add(Top); } else { // Needs to be split further FloorChunk Left = ChunkDB.Create(); FloorChunk Right = ChunkDB.Create(); FloorChunk Hallway = ChunkDB.Create(); SplitChunk(Top, Left, Right, Hallway); ChunkDB.Register(Hallway); Stack.Push(Left); Stack.Push(Right); } } } // Split the floor chunks (space between the hallways) to create rooms foreach (FloorChunk Chunk in FloorChunks) { Stack <FloorChunk> Stack = new Stack <FloorChunk>(); Stack.Push(Chunk); int MinArea = floorPlanConfig.MinRoomSize * floorPlanConfig.MinRoomSize; int MaxArea = floorPlanConfig.MaxRoomSize * floorPlanConfig.MaxRoomSize; while (Stack.Count > 0) { FloorChunk Top = Stack.Pop(); bool bRequiresSplit = true; int Area = Top.Area(); int Length = Top.GetLength(); if (Length > floorPlanConfig.MaxRoomSize) { // Length is too big. force a split bRequiresSplit = true; } else if (Area <= MinArea) { // This room is too small and should not be split bRequiresSplit = false; } else if (Area <= MaxArea) { float SplitProbability = (Area - MinArea) / (MaxArea - MinArea); SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset; if (Chunk.GetLength() >= Chunk.GetWidth() * 2) { SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset; } bRequiresSplit = (random.Next() < SplitProbability); } if (bRequiresSplit) { FloorChunk Left = ChunkDB.Create(); FloorChunk Right = ChunkDB.Create(); SplitChunk(Top, Left, Right); Stack.Push(Left); Stack.Push(Right); } else { ChunkDB.Register(Top); } } } /* * // Get the chunks defined by the room volumes * List<FloorChunk> RoomVolumeChunks = new List<FloorChunk>(); * if (World) { * FRectangle BuildingBounds; * BuildingBounds.Location = FIntVector::ZeroValue; * BuildingBounds.Size = FMathUtils::ToIntVector(floorPlanConfig.BuildingSize); * for (TActorIterator<AFloorPlanRoomVolume> It(World); It; ++It) { * AFloorPlanRoomVolume* Volume = *It; * if (Volume.Dungeon != Dungeon) { * // This volume is not supposed to affect this dungeon * continue; * } * FVector GridSize = floorPlanConfig.GridSize; * FRectangle VolumeBounds; * Volume.GetDungeonVolumeBounds(GridSize, VolumeBounds); * int VolumeStartZ = VolumeBounds.Location.Z; * int VolumeEndZ = VolumeStartZ + VolumeBounds.Size.Z; * * if (z < VolumeStartZ || z >= VolumeEndZ) { * // Out of the volume bounds * continue; * } * * FRectangle ChunkBounds = VolumeBounds; * ChunkBounds.Location.Z = z; * ChunkBounds.Size.Z = 1; * ChunkBounds.Clip(BuildingBounds); * if (ChunkBounds.Size.Z == 0) continue; * int ChunkZ = ChunkBounds.Location.Z; * * FloorChunk RoomVolumeChunk = ChunkDB.Create(); * RoomVolumeChunk.Bounds = ChunkBounds; * RoomVolumeChunk.ChunkType = FloorChunkType.Room; * RoomVolumeChunk.bEmitGroundMarker = (ChunkZ == VolumeStartZ); * RoomVolumeChunk.bEmitCeilingMarker = (ChunkZ == VolumeEndZ - 1); * RoomVolumeChunk.bConnectDoors = Volume.bConnectDoors; * RoomVolumeChunk.WallMarker = Volume.WallMarker; * RoomVolumeChunk.GroundMarker = Volume.GroundMarker; * RoomVolumeChunk.CeilingMarker = Volume.CeilingMarker; * RoomVolumeChunk.DoorMarker = Volume.DoorMarker; * RoomVolumeChunk.CenterMarker = Volume.CenterMarker; * RoomVolumeChunk.bCreateWalls = Volume.bCreateWalls; * * // Since this chunk is defined by a volume, we can have a more detailed rasterised cell shape * GetVolumeCells(Volume, z, RoomVolumeChunk.BoundCells); * * // Give a higher priority to the volume chunk so it overrides everything in its path * RoomVolumeChunk.Priority = Volume.Priority; * * RoomVolumeChunks.Add(RoomVolumeChunk); * ChunkDB.Register(RoomVolumeChunk); * } * } */ } ChunkDB.CacheChunkPositions(); for (int y = 0; y < floorPlanConfig.BuildingSize.y; y++) { CreateDoors(y); } }
void BuildLayout() { ChunkDB = new FloorChunkDB(); DoorManager = new FloorDoorManager(); Visited.Clear(); random = new System.Random((int)floorPlanConfig.Seed); int NumFloors = Mathf.RoundToInt(floorPlanConfig.BuildingSize.y); for (int y = 0; y < NumFloors; y++) { // Build the hallways and the intermediate floor chunks (which will hold the rooms) List <FloorChunk> FloorChunks = new List <FloorChunk>(); { FloorChunk InitialFloor = ChunkDB.Create(); InitialFloor.Bounds.Location = new IntVector(0, y, 0); InitialFloor.Bounds.Size = MathUtils.ToIntVector(floorPlanConfig.BuildingSize); Stack <FloorChunk> Stack = new Stack <FloorChunk>(); Stack.Push(InitialFloor); while (Stack.Count > 0) { FloorChunk Top = Stack.Pop(); float Area = Top.Area(); if (Area <= 0) { continue; } if (Top.Area() <= floorPlanConfig.MinRoomChunkArea) { FloorChunks.Add(Top); } else { // Needs to be split further FloorChunk Left = ChunkDB.Create(); FloorChunk Right = ChunkDB.Create(); FloorChunk Hallway = ChunkDB.Create(); SplitChunk(Top, Left, Right, Hallway); ChunkDB.Register(Hallway); Stack.Push(Left); Stack.Push(Right); } } } // Split the floor chunks (space between the hallways) to create rooms foreach (FloorChunk Chunk in FloorChunks) { Stack <FloorChunk> Stack = new Stack <FloorChunk>(); Stack.Push(Chunk); int MinRoomSize = floorPlanConfig.MinRoomSize; int MaxRoomSize = floorPlanConfig.MaxRoomSize; MaxRoomSize = Mathf.Max(MinRoomSize, MaxRoomSize); int MinArea = MinRoomSize * MinRoomSize; int MaxArea = MaxRoomSize * MaxRoomSize; while (Stack.Count > 0) { FloorChunk Top = Stack.Pop(); bool bRequiresSplit = true; int Area = Top.Area(); int Length = Top.GetLength(); if (Length > MaxRoomSize) { // Length is too big. force a split bRequiresSplit = true; } else if (Area <= MinArea) { // This room is too small and should not be split bRequiresSplit = false; } else if (Area <= MaxArea) { float SplitProbability = (Area - MinArea) / (MaxArea - MinArea); SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset; if (Chunk.GetLength() >= Chunk.GetWidth() * 2) { SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset; } bRequiresSplit = (random.Next() < SplitProbability); } if (bRequiresSplit) { FloorChunk Left = ChunkDB.Create(); FloorChunk Right = ChunkDB.Create(); SplitChunk(Top, Left, Right); Stack.Push(Left); Stack.Push(Right); } else { ChunkDB.Register(Top); } } } // TODO: Add support for floor plan specific volumes // ... } ChunkDB.CacheChunkPositions(); for (int y = 0; y < floorPlanConfig.BuildingSize.y; y++) { CreateDoors(y); } }