public RandomDungeonTileData(RandomDungeonTileData copy) { tileType = copy.tileType; scope = copy.scope; room = copy.room; trap = copy.trap; chest = copy.chest; distanceFromPrimaryPath = copy.distanceFromPrimaryPath; }
public RandomDungeon(int dungeonWidth, int dungeonHeight) { width = dungeonWidth; height = dungeonHeight; mTiles = new RandomDungeonTileData[width, height]; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { mTiles[x, y] = new RandomDungeonTileData(); mTiles[x, y].tileType = RandomDungeonTileData.EMPTY_TILE; mTiles[x, y].scope = 0; } } }
private int NeighborTrap(int x, int y) { for (int adjustedX = -1; adjustedX <= 1; ++adjustedX) { for (int adjustedY = -1; adjustedY <= 1; ++adjustedY) { int mapX = x + adjustedX; int mapY = y + adjustedY; Vector2Int v = new Vector2Int(mapX, mapY); RandomDungeonTileData td = null; if (mRoomScratch.TryGetValue(v, out td)) { if (td.trap != -1) { return(td.trap); } } } } return(-1); }
public void EvaluateDungeon(RandomDungeon dungeon) { int[] orthogonalOffsets = new int[] { 0, 1, 1, 0, 0, -1, -1, 0 }; for (int x = 0; x < dungeon.width; ++x) { for (int y = 0; y < dungeon.height; ++y) { // Only evaluate walkable tiles if (dungeon.TileType(x, y) != RandomDungeonTileData.WALKABLE_TILE && dungeon.TileType(x, y) != RandomDungeonTileData.EXIT_TILE) { continue; } RandomDungeonTileData data = dungeon.Data(x, y); // If the room isn't already part of the set, add it RandomDungeonNetworkNode node = null; if (!mNodeMap.TryGetValue(data.room, out node)) { node = new RandomDungeonNetworkNode(); node.roomId = data.room; node.distanceFromPrimaryPath = data.distanceFromPrimaryPath; mNodeMap.Add(data.room, node); } // Distance from primary path should be the closest tile that we can get into for this room. node.distanceFromPrimaryPath = Mathf.Min(data.distanceFromPrimaryPath, node.distanceFromPrimaryPath); // Evaluate connections (orthogonally, only considering walkable / exit tiles) for (int i = 0; i < orthogonalOffsets.Length; i += 2) { int neighborX = x + orthogonalOffsets[i]; int neighborY = y + orthogonalOffsets[i + 1]; if (dungeon.IsPositionInBounds(neighborX, neighborY)) { RandomDungeonTileData neighborData = dungeon.Data(neighborX, neighborY); bool isWalkable = (neighborData.tileType == RandomDungeonTileData.WALKABLE_TILE || neighborData.tileType == RandomDungeonTileData.EXIT_TILE); if (isWalkable && neighborData.room != node.roomId && !node.ConnectionExists(neighborData.room)) { node.AddConnection(neighborData.room); } } } // Keep track of all walkable tiles in this room so we know where we can spawn stuff. // todo bdsowers - change the name of this // By design it only keeps track of tiles that aren't next to a wall, but that // isn't conveyed in the name. // todo bdsowers - move a 'num surrounding walls' into map generation, as that can // be useful for more than just this. bool hasUnwalkableNeighbor = false; for (int offsetX = -1; offsetX <= 1; ++offsetX) { for (int offsetY = -1; offsetY <= 1; ++offsetY) { int testX = x + offsetX; int testY = y + offsetY; if (!dungeon.IsPositionInBounds(testX, testY)) { hasUnwalkableNeighbor = true; continue; } char tileType = dungeon.TileType(testX, testY); if (tileType != RandomDungeonTileData.WALKABLE_TILE && tileType != RandomDungeonTileData.EXIT_TILE) { hasUnwalkableNeighbor = true; continue; } } } if (!hasUnwalkableNeighbor) { node.RegisterEmptyPosition(x, y); } } } }
public void SetData(int x, int y, RandomDungeonTileData data) { mTiles[x, y] = data; }
/// <summary> /// Actually performs room placement in the scratchpad. /// </summary> /// <param name="roomData"></param> /// <param name="mapExit"></param> /// <param name="roomExit"></param> /// <param name="scope"></param> /// <param name="primaryPath"></param> private void PlaceRoom(RoomData roomData, Vector2Int mapExit, Vector2Int roomExit, int scope, bool primaryPath) { int maxDistance = 0; roomData.placeCount++; for (int x = 0; x < roomData.width; ++x) { for (int y = 0; y < roomData.height; ++y) { int mapX = mapExit.x - roomExit.x + x; int mapY = mapExit.y - roomExit.y + y; Vector2Int mapPos = new Vector2Int(mapX, mapY); char roomTile = roomData.Tile(x, y); // Empty tiles shouldn't be represented in the dictionary if (roomTile == RandomDungeonTileData.EMPTY_TILE) { continue; } // Create a new tile or edit a tile that already exists. // This ensures we don't generate unnecessary garbage. RandomDungeonTileData td = null; if (!mRoomScratch.ContainsKey(mapPos)) { td = new RandomDungeonTileData(); mRoomScratch.Add(mapPos, td); float distance = Vector2Int.Distance(roomExit, new Vector2Int(x, y)); int distanceInt = Mathf.CeilToInt(distance); maxDistance = Mathf.Max(maxDistance, distanceInt); td.tileId = mCurrentTileId + distanceInt; td.position = mapPos; } else { td = mRoomScratch[mapPos]; td.Clear(); } td.tileType = roomTile; td.scope = scope; td.room = mCurrentRoomId; if (primaryPath) { td.distanceFromPrimaryPath = 0; } else { // todo bdsowers - this is not perfect // maybe it doesn't need to be perfect, we'll see int mapExitDistance = mRoomScratch[mapExit].distanceFromPrimaryPath; td.distanceFromPrimaryPath = mapExitDistance + 1; maxDistanceFromPrimaryPath = Mathf.Max(maxDistanceFromPrimaryPath, td.distanceFromPrimaryPath); } // Trap // Register it in the map proper as a walkable tile // give a block of trap tiles the same identifier - they form one large trap if (roomTile == RandomDungeonTileData.TRAP_TILE) { int neighborTrap = NeighborTrap(mapX, mapY); int trapId = neighborTrap; if (trapId == -1) { trapId = mCurrentTrapId; mCurrentTrapId++; } td.tileType = RandomDungeonTileData.WALKABLE_TILE; td.trap = trapId; } else if (roomTile == RandomDungeonTileData.POSSIBLE_CHEST_TILE) { td.tileType = RandomDungeonTileData.WALKABLE_TILE; td.chest = 1; } else if (roomTile == RandomDungeonTileData.GUARANTEED_CHEST_TILE) { td.tileType = RandomDungeonTileData.WALKABLE_TILE; td.chest = 2; } // Add the new exit to the list of available exits if (roomTile == RandomDungeonTileData.EXIT_TILE) { mAvailableExits.Add(mapPos); } } } ++mCurrentRoomId; mCurrentTileId += maxDistance + 1; }