void UpdateHeights(GridDungeonModel model) { if (terrain == null || terrain.terrainData == null) { return; } var rasterizer = new LandscapeDataRasterizer(terrain, groundLevelHeight); rasterizer.LoadData(); var gridSize = model.Config.GridCellSize; // Raise the terrain foreach (var cell in model.Cells) { var locationGrid = cell.Bounds.Location; var location = locationGrid * gridSize; var size = cell.Bounds.Size * gridSize; var cellY = location.y + layoutLevelOffset; rasterizer.DrawCell(location.x, location.z, size.x, size.z, cellY); } // Smooth the terrain ApplySmoothing(model, rasterizer); rasterizer.SaveData(); }
public static bool AreAdjacentCellsReachable(GridDungeonModel gridModel, int cellIdA, int cellIdB) { var cellA = gridModel.GetCell(cellIdA); var cellB = gridModel.GetCell(cellIdB); if (cellA == null || cellB == null) { return(false); } // If any one is a room, make sure we have a door between them if (cellA.CellType == CellType.Room || cellB.CellType == CellType.Room) { if (!gridModel.DoorManager.ContainsDoorBetweenCells(cellIdA, cellIdB)) { // We don't have a door between them and is blocked by a room wall return(false); } } // if their height is different, make sure we have a stair between them if (cellA.Bounds.Location.y != cellB.Bounds.Location.y) { if (!gridModel.ContainsStair(cellIdA, cellIdB)) { // Height difference with no stairs. not reachable return(false); } } // reachable return(true); }
/// <summary> /// Finds all the nearby tiles that belong to the same cluster /// </summary> /// <param name="gridModel"></param> /// <param name="corridorTileCellId"></param> /// <returns></returns> public static int[] GetCellCluster(GridDungeonModel gridModel, int sampleCellId) { var clusters = new List <int>(); // Check if we are in a room. Rooms don't need to be clustered as they form a single group var startCell = gridModel.GetCell(sampleCellId); if (startCell == null || startCell.CellType == CellType.Room) { clusters.Add(sampleCellId); return(clusters.ToArray()); } var visited = new HashSet <int>(); var stack = new Stack <int>(); stack.Push(sampleCellId); while (stack.Count > 0) { var topId = stack.Pop(); if (visited.Contains(topId)) { continue; } visited.Add(topId); var top = gridModel.GetCell(topId); if (top == null) { continue; } if (top.CellType == CellType.Unknown || top.CellType == CellType.Room) { continue; } if (IsCorridor(top.CellType)) { clusters.Add(topId); } // search adjacent cells foreach (var adjacentId in top.AdjacentCells) { // make sure the adjacent cell is reachable if (AreAdjacentCellsReachable(gridModel, topId, adjacentId)) { stack.Push(adjacentId); } } } return(clusters.ToArray()); }
void EmitCornerMarker(DungeonBuilder builder, GridDungeonModel model, IntVector point, string markerName) { // Add an empty marker here var gridSize = model.Config.GridCellSize; var position = point * gridSize; position += Vector3.Scale(new Vector3(0.5f, 0, 0.5f), gridSize); var transform = Matrix4x4.TRS(position, Quaternion.identity, Vector3.one); builder.EmitMarker(markerName, transform, point, -1); }
void EmitForPoint(DungeonBuilder builder, GridDungeonModel model, IntVector point) { foreach (var config in CornerConfigs) { if (ConfigMatches(model, point, config)) { EmitCornerMarker(builder, model, point, config.markerName); break; } } }
public GridDungeonModel GetDungeonModelGrid() { var model = base.GetDungeonModel(); gridModel = model as GridDungeonModel; if (gridModel == null) { Debug.LogWarning("Invalid dungeon model type for this type of paint tool. Expected DungeonModelGrid. Received:" + (model != null ? model.GetType().ToString() : "null")); } return(gridModel); }
public static void GetAdjacentCorridors(GridDungeonModel gridModel, int startCellId, ref List <int> OutConnectedCorridors, ref List <int> OutConnectedRooms) { OutConnectedCorridors.Clear(); OutConnectedRooms.Clear(); // search all nearby cells till we reach a dead end (or a room) var visited = new HashSet <int>(); var stack = new Stack <int>(); stack.Push(startCellId); while (stack.Count > 0) { var topId = stack.Pop(); if (visited.Contains(topId)) { continue; } visited.Add(topId); var top = gridModel.GetCell(topId); if (top == null) { continue; } if (top.CellType == CellType.Unknown) { continue; } if (top.CellType == CellType.Room && top.Id != startCellId) { OutConnectedRooms.Add(topId); continue; } if (IsCorridor(top.CellType)) { OutConnectedCorridors.Add(topId); } // search adjacent cells foreach (var adjacentId in top.AdjacentCells) { // make sure the adjacent cell is reachable if (AreAdjacentCellsReachable(gridModel, topId, adjacentId)) { stack.Push(adjacentId); } } } }
protected virtual void ApplySmoothing(GridDungeonModel model, LandscapeDataRasterizer rasterizer) { var gridSize = model.Config.GridCellSize; foreach (var cell in model.Cells) { var locationGrid = cell.Bounds.Location; var location = locationGrid * gridSize; var size = cell.Bounds.Size * gridSize; var cellY = location.y + layoutLevelOffset; var curve = (cell.CellType == CellType.Room) ? roomElevationCurve : corridorElevationCurve; rasterizer.SmoothCell(location.x, location.z, size.x, size.z, cellY, smoothingDistance, curve); } }
public static Cell[] FindFurthestRooms(GridDungeonModel model) { var bestLength = 0; var result = new Cell[2]; foreach (var startCell in model.Cells) { var queue = new Queue <LongestPathBFSData>(); var visited = new HashSet <int>(); var startData = new LongestPathBFSData { cell = startCell, length = 0 }; LongestPathBFSData endData = startData; queue.Enqueue(startData); while (queue.Count > 0) { var front = queue.Dequeue(); visited.Add(front.cell.Id); foreach (var childId in front.cell.FixedRoomConnections) { if (visited.Contains(childId)) { continue; } var child = model.GetCell(childId); var childData = new LongestPathBFSData { cell = child, length = front.length + 1 }; queue.Enqueue(childData); } if (queue.Count == 0) { endData = front; } } if (endData.length > bestLength) { bestLength = endData.length; result[0] = startData.cell; result[1] = endData.cell; } } return(result); }
void UpdateTerrainTextures(GridDungeonModel model) { if (terrain == null || terrain.terrainData == null) { return; } var numTextures = textures.Length; var data = terrain.terrainData; var map = new float[data.alphamapWidth, data.alphamapHeight, numTextures]; UpdateBaseTexture(model, map); UpdateCliffTexture(map); data.SetAlphamaps(0, 0, map); }
CellType GetCellTypeFromId(int cellId, GridDungeonModel model) { if (!model.CellLookup.ContainsKey(cellId)) { return(CellType.Unknown); } var cell = model.CellLookup[cellId]; if (cell == null) { return(CellType.Unknown); } if (cell.CellType == CellType.CorridorPadding) { return(CellType.Corridor); } return(cell.CellType); }
public static void DrawAdjacentCells(Cell cell, GridDungeonModel model, Color color, bool mode2D) { if (model == null) { return; } var gridConfig = model.Config as GridDungeonConfig; if (gridConfig == null) { return; } foreach (var adjacentId in cell.AdjacentCells) { var adjacentCell = model.GetCell(adjacentId); if (adjacentCell == null) { return; } var centerA = Vector3.Scale(cell.Bounds.CenterF(), gridConfig.GridCellSize); var centerB = Vector3.Scale(adjacentCell.Bounds.CenterF(), gridConfig.GridCellSize); DebugDrawUtils.DrawLine(centerA, centerB, color, 0, false, mode2D); } foreach (var adjacentId in cell.FixedRoomConnections) { var adjacentCell = model.GetCell(adjacentId); if (adjacentCell == null) { return; } var centerA = Vector3.Scale(cell.Bounds.CenterF(), gridConfig.GridCellSize) + new Vector3(0, 0.2f, 0); var centerB = Vector3.Scale(adjacentCell.Bounds.CenterF(), gridConfig.GridCellSize) + new Vector3(0, 0.2f, 0); DebugDrawUtils.DrawLine(centerA, centerB, Color.red, 0, false, mode2D); } }
bool ConfigMatches(GridDungeonModel model, IntVector point, CellSpatialConfig config) { var neighbors = config.neighborConfig; for (int i = 0; i < neighbors.Length; i++) { var code = neighbors[i]; if (code == 0) { // Don't care about this cell continue; } var dx = i % 3; var dz = i / 3; dx--; dz--; // bring to -1..1 range (from previous 0..2) dz *= -1; var x = point.x + dx; var z = point.z + dz; var cellInfo = model.GetGridCellLookup(x, z); bool empty = cellInfo.CellType == CellType.Unknown; if (code == 1 && empty) { // We were expecting a non-empty space here, but it is empty return(false); } else if (code == 2 && !empty) { // We were expecting a empty space here, but it is not empty return(false); } } // Matches, all tests have passed return(true); }
void BuildTerrain(GridDungeonModel model) { SetupTextures(); UpdateHeights(model); UpdateTerrainTextures(model); }
void UpdateBaseTexture(GridDungeonModel model, float[,,] map) { if (terrain == null) { return; } int fillIndex = GetTextureIndex(LandscapeTextureType.Fill); if (fillIndex < 0) { return; } var data = terrain.terrainData; // Fill up the entire space with the fill texture for (var y = 0; y < data.alphamapHeight; y++) { for (var x = 0; x < data.alphamapWidth; x++) { for (int t = 0; t < textures.Length; t++) { var ratio = (t == fillIndex) ? 1 : 0; map[y, x, t] = ratio; } } } int corridorIndex = GetTextureIndex(LandscapeTextureType.Corridor); int roomIndex = GetTextureIndex(LandscapeTextureType.Room); if (roomIndex < 0 && corridorIndex < 0) { // Both corridor and room textures were not provided. Fill them up with the fill index roomIndex = fillIndex; corridorIndex = fillIndex; } else if (roomIndex < 0) { // Use the same texture for the room used by the corridor roomIndex = corridorIndex; } else if (corridorIndex < 0) { // Use the same texture for the corridor used by the room corridorIndex = roomIndex; } // Apply the room/corridor texture { var gridSize = model.Config.GridCellSize; var roomMap = new float[map.GetLength(0), map.GetLength(1)]; var corridorMap = new float[map.GetLength(0), map.GetLength(1)]; foreach (var cell in model.Cells) { var bounds = cell.Bounds; var locationGrid = bounds.Location; var location = locationGrid * gridSize; var size = bounds.Size * gridSize; int gx1, gy1, gx2, gy2; LandscapeDataRasterizer.WorldToTerrainTextureCoord(terrain, location.x, location.z, out gx1, out gy1); LandscapeDataRasterizer.WorldToTerrainTextureCoord(terrain, location.x + size.x, location.z + size.z, out gx2, out gy2); for (var gx = gx1; gx <= gx2; gx++) { for (var gy = gy1; gy <= gy2; gy++) { if (cell.CellType == CellType.Unknown) { continue; } if (cell.CellType == CellType.Room) { roomMap[gy, gx] = 1; } else { corridorMap[gy, gx] = 1; } } } } // Blur the layout data var filter = new BlurFilter(roadBlurDistance); roomMap = filter.ApplyFilter(roomMap); corridorMap = filter.ApplyFilter(corridorMap); // Fill up the inner region with corridor index for (var y = 0; y < data.alphamapHeight; y++) { for (var x = 0; x < data.alphamapWidth; x++) { bool corridor = (corridorMap[y, x] > corridorBlurThreshold); if (corridor) { map[y, x, fillIndex] = 0; map[y, x, roomIndex] = 0; map[y, x, corridorIndex] = 1; } bool room = (roomMap[y, x] > roomBlurThreshold); if (room) { map[y, x, fillIndex] = 0; map[y, x, corridorIndex] = 0; map[y, x, roomIndex] = 1; } } } } }