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); }
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); } }