/// <summary> /// Informs neighbors of this room to unload themselves. Does NOT unload /// this room itself! Also, you may specify one neighbor not to despawn. /// </summary> /// <param name="dontDespawn">Room you would like to not unload</param> public virtual void UnloadNeighbors(RogueRoom dontDespawn) { if (LeftNeighbor != null && LeftNeighbor != dontDespawn) LeftNeighbor.UnloadRoom(); if (RightNeighbor != null && RightNeighbor != dontDespawn) RightNeighbor.UnloadRoom(); if (UpNeighbor != null && UpNeighbor != dontDespawn) UpNeighbor.UnloadRoom(); if (DownNeighbor != null && DownNeighbor != dontDespawn) DownNeighbor.UnloadRoom(); }
/// <summary> /// Generates a new RogueDungeon of the specified width and height. /// In this case, "width" and "height" mean the number of potential /// rooms horizontally or vertically, respectively. /// </summary> /// <param name="width">Maximum number of rooms tall the map can be</param> /// <param name="height">Maximum number of rooms wide the map can be</param> public RogueDungeon(int width, int height) { // Build a maze, which gives us door values bool[,] boolMap = Maze.GenerateMaze(width, height); // Use the maze to fill in our map int newWidth = boolMap.GetLength(0) - 2; int newHeight = boolMap.GetLength(1) - 2; Map = new RogueRoom[newWidth, newHeight]; // Assign initial placements: int bossX = 0, bossY = 0; int keyX = 0, keyY = 0; startRoomX = 0; startRoomY = 0; for (int x = 1; x < boolMap.GetLength(0); x += 2) { for (int y = 1; y < boolMap.GetLength(1); y += 2) { int dirCode = 0; dirCode |= (boolMap[x-1,y] ? 0x1 : 0x0); dirCode |= (boolMap[x+1,y] ? 0x2 : 0x0); dirCode |= (boolMap[x,y-1] ? 0x4 : 0x0); dirCode |= (boolMap[x,y+1] ? 0x8 : 0x0); if (dirCode == 0x1) { bossX = x; bossY = y; startRoomX = x-2; startRoomY = y; } else if (dirCode == 0x2) { bossX = x; bossY = y; startRoomX = x+2; startRoomY = y; } else if (dirCode == 0x4) { bossX = x; bossY = y; startRoomX = x; startRoomY = y-2; } else if (dirCode == 0x8) { bossX = x; bossY = y; startRoomX = x; startRoomY = y+2; } } } // Find key room: Maze.FindFarthest(boolMap, bossX, bossY, out keyX, out keyY); // Account for coordinate offset: bossX -= 1; bossY -= 1; startRoomX -= 1; startRoomY -= 1; keyX -= 1; keyY -= 1; // Instantiate between rooms: for (int x = 0; x < newWidth; x += 2) { for (int y = 0; y < newHeight; y += 2) { // CorridorFork room by default int roomWidth = CORRIDOR_WIDTH; int roomDepth = CORRIDOR_WIDTH; RogueRoom.RoomType type = RogueRoom.RoomType.corridorFork; // If the x,y coordinate was one of our set aside vectors, use that type: if (x == startRoomX && y == startRoomY) { roomWidth = ROOM_WIDTH;//r.Next(MIN_SHOP_ROOM_WIDTH, MAX_SHOP_ROOM_WIDTH-1); roomDepth = ROOM_DEPTH;//r.Next (MIN_SHOP_ROOM_DEPTH, MAX_SHOP_ROOM_DEPTH-1); type = RogueRoom.RoomType.start; } else if (x == bossX && y == bossY) { roomWidth = BOSS_ROOM_WIDTH;//r.Next(MIN_BOSS_ROOM_WIDTH, MAX_BOSS_ROOM_WIDTH-1); roomDepth = BOSS_ROOM_DEPTH;//r.Next (MIN_BOSS_ROOM_DEPTH, MAX_BOSS_ROOM_DEPTH-1); type = RogueRoom.RoomType.boss; } else if (x == keyX && y == keyY) { roomWidth = ROOM_WIDTH; roomDepth = ROOM_DEPTH; type = RogueRoom.RoomType.keyRoom; } // TODO: others? // If we decide to place a room here, adjust the width // and height accordingly else if (Maze.rnd.NextDouble() < ENEMY_ROOM_DENSITY) { roomWidth = ROOM_WIDTH;//r.Next(MIN_ENEMY_ROOM_WIDTH, MAX_ENEMY_ROOM_WIDTH-1); roomDepth = ROOM_DEPTH;//r.Next(MIN_ENEMY_ROOM_DEPTH, MAX_ENEMY_ROOM_DEPTH-1); type = RogueRoom.RoomType.enemy; // TODO: handle enemy score distribution } // We need rooms to be nice values to accomodate corridor widths & cubes. // Short version: we need an equal number of blocks on the left and right // of every door in the maze, so width-corridor_width as well as // height-corridor_width must be even. // Adjust accordingly: /* if ((roomWidth - CORRIDOR_WIDTH) % 2 == 1) roomWidth++; if ((roomDepth - CORRIDOR_WIDTH) % 2 == 1) roomDepth++; */ // Determine what the door code should be, by checking the map: int mapCoordX = x + 1; int mapCoordY = y + 1; int doorCode = 0x0; // NOTE: the below operations are safe, because the Maze class guarantees // that the map will have a buffer of false values around where the rooms are. // Left: if (boolMap[mapCoordX - 1, mapCoordY]) doorCode |= RogueRoom.LEFT_DOOR_MASK; // Right: if (boolMap[mapCoordX + 1, mapCoordY]) doorCode |= RogueRoom.RIGHT_DOOR_MASK; // Up: if (boolMap[mapCoordX, mapCoordY - 1]) doorCode |= RogueRoom.UP_DOOR_MASK; // Down: if (boolMap[mapCoordX, mapCoordY + 1]) doorCode |= RogueRoom.DOWN_DOOR_MASK; // Create the room, and insert it into the map: RogueRoom newRoom; switch (type) { case RogueRoom.RoomType.start: case RogueRoom.RoomType.shop: case RogueRoom.RoomType.empty: case RogueRoom.RoomType.enemy: newRoom = new GeneralRoom(roomWidth, roomDepth, MAX_ROOM_HEIGHT, x, y, doorCode); break; case RogueRoom.RoomType.boss: case RogueRoom.RoomType.keyRoom: newRoom = new GeneralRoom(roomWidth, roomDepth, MAX_ROOM_HEIGHT, x, y, doorCode); SkeletonKingAI.bossRoom = (GeneralRoom)newRoom; ZombiePrinceAI.bossRoom = (GeneralRoom)newRoom; SpiderQueenAI.bossRoom = (GeneralRoom)newRoom; break; case RogueRoom.RoomType.corridorFork: default: newRoom = new CorridorBranchRoom(roomWidth, MAX_ROOM_HEIGHT, x, y, doorCode); break; // This case can't happen: //case RogueRoom.RoomType.corridor: } newRoom.Type = type; // Initialize enemy list to a GeneralRoom. The GeneralRoom handles when it isn't an // enemy room, so we won't worry about that. // TODO: smarter distribution of enemy points. For now, just give same value to each room. if (newRoom is GeneralRoom) ((GeneralRoom)newRoom).AssignEnemies(LevelHolder.Level * 10); Map[x, y] = newRoom; } } // Instantiate corridors: // Left-Right: for (int x = 1; x < newWidth; x += 2) { for (int y = 0; y < newHeight; y += 2) { // Determine door codes, and attach relationships: int mapCoordX = x + 1; int mapCoordY = y + 1; int doorCode = 0x0; RogueRoom lftNbr = null, rgtNbr = null; int corridorWidth = CORRIDOR_WIDTH; int corridorDepth = CORRIDOR_WIDTH; CorridorRoom corridor; // Confirm this corridor is actually in the maze: if (boolMap[mapCoordX, mapCoordY]) { doorCode |= RogueRoom.LEFT_DOOR_MASK; lftNbr = Map[x-1, y]; doorCode |= RogueRoom.RIGHT_DOOR_MASK; rgtNbr = Map[x+1,y]; // Determine correct width for this corridor: corridorWidth = MAX_ROOM_WIDTH + ((MAX_ROOM_WIDTH - lftNbr.Width) / 2) + ((MAX_ROOM_WIDTH - rgtNbr.Width) / 2); // Instantiate & hookup neighbors: corridor = new CorridorRoom(corridorWidth, corridorDepth, MAX_ROOM_HEIGHT, x, y, doorCode); lftNbr.RightNeighbor = corridor; rgtNbr.LeftNeighbor = corridor; corridor.LeftNeighbor = lftNbr; corridor.RightNeighbor = rgtNbr; // Initialize cubes: corridor.InitializeCubes(); // Put it in the map: Map[x,y] = corridor; } else { Map[x,y] = null; } } } // Up-Down: for (int x = 0; x < newWidth; x += 2) { for (int y = 1; y < newHeight; y += 2) { // Determine door codes, and attach relationships: int mapCoordX = x + 1; int mapCoordY = y + 1; int doorCode = 0x0; RogueRoom upNbr = null, dwnNbr = null; int corridorWidth = CORRIDOR_WIDTH; int corridorDepth = CORRIDOR_WIDTH; CorridorRoom corridor; // Confirm this corridor is actually in the maze: if (boolMap[mapCoordX, mapCoordY]) { doorCode |= RogueRoom.UP_DOOR_MASK; upNbr = Map[x, y-1]; doorCode |= RogueRoom.DOWN_DOOR_MASK; dwnNbr = Map[x,y+1]; // Determine correct width for this corridor: corridorDepth = MAX_ROOM_DEPTH + ((MAX_ROOM_DEPTH - upNbr.Depth) / 2) + ((MAX_ROOM_DEPTH - dwnNbr.Depth) / 2); // Instantiate & hookup neighbors: corridor = new CorridorRoom(corridorWidth, corridorDepth, MAX_ROOM_HEIGHT, x, y, doorCode); upNbr.DownNeighbor = corridor; dwnNbr.UpNeighbor = corridor; corridor.UpNeighbor = upNbr; corridor.DownNeighbor = dwnNbr; // Initialize cubes: corridor.InitializeCubes(); // Put it in the map: Map[x,y] = corridor; } else { Map[x,y] = null; } } } // Initialize main rooms' cubes: for (int x = 0; x < newWidth; x += 2) { for (int y = 0; y < newHeight; y += 2) { Map[x,y].InitializeCubes(); } } }
/// <summary> /// Informs this room's neighbors that they need to get themselves loaded into the /// scene. Does NOT load this room itself! Also, will not load a room if that room /// is already loaded. /// /// You may pass in a room you would like not to load, as well, in case your room /// is adjacent to a room already loaded (for example). /// </summary> /// <param name="maxWidth">Maximum width a room can be in the maze, in cube units.</param> /// <param name="maxDepth">Maximum depth a room can be in the maze, in cube units.</param> /// <param name="doorWidth">How large the openings to the room need to be. Must be no more than Width or Depth.</param> /// <param name="scalar">1 cube -> scalar units in Unity.</param> public virtual void LoadNeighbors(RogueRoom dontLoad) { if (LeftNeighbor != null && LeftNeighbor != dontLoad) LeftNeighbor.DynamicLoad(); if (RightNeighbor != null && RightNeighbor != dontLoad) RightNeighbor.DynamicLoad(); if (UpNeighbor != null && UpNeighbor != dontLoad) UpNeighbor.DynamicLoad(); if (DownNeighbor != null && DownNeighbor != dontLoad) DownNeighbor.DynamicLoad(); }