// Update is called once per frame void Update() { /**on each update, pick a random room from list, try to generate a new room relative to that room * if no room in list (means we have exhausted all rooms to create around, or we have not created first room), give up on creating room * after creating rooms, populate them with a player, a set of stairs, and any relevant entities **/ if (roomCount < numberOfRooms) ///create numberOfRooms rooms { if (roomCount == 0) //creating very first room { int newSize = Random.Range(minRoomSize, maxRoomSize + 1); //size of new room dungeon_room newRoom = TryCreateRoom(new Vector3(transform.position.x, transform.position.y, TileMonoBehavior.tileZLayer), newSize, 0, Entity.MoveDirection.up); if (newRoom != null) //if room successfully created { createdRoomsQueue.Enqueue(newRoom); roomCount++; } else { roomCount = numberOfRooms; //forces Generator to stop generating GracefullyExit(); return; } } else if (createdRoomsQueue.Peek() != null) //not first element, and there is a next element to grab { dungeon_room oldRoom = GetRandomRoomFromQueue(); //picks an old room to generate new room relative to if (oldRoom == null) { roomCount = numberOfRooms; return; } dungeon_room newRoom = null; //the room we hope to create int roomSize = Random.Range(minRoomSize, maxRoomSize + 1); //the size we want the new room to be float distance = Random.Range(minDisplacement, maxDisplacement + 1); Vector3 newRoomLocation = new Vector3(); Vector3 oldRoomLocation = oldRoom.getCoords(); Entity.MoveDirection direction = (Entity.MoveDirection)Random.Range(0, 4); ///direction can be 0 up, 2 left, 1 down, 3 right Entity.MoveDirection originalDirection = direction; do ///try to create room at given direction, if it fails, keep trying with new direction until there are no more directions to pick { switch (direction) { case Entity.MoveDirection.up: //up { float relativePosition = Mathf.Ceil(oldRoom.getSize() / 2f) + distance + Mathf.Floor(roomSize / 2f); newRoomLocation = new Vector3(oldRoomLocation.x, oldRoomLocation.y + relativePosition, 0); break; } case Entity.MoveDirection.left: //left { float relativePosition = Mathf.Floor(oldRoom.getSize() / 2f) + distance + Mathf.Ceil(roomSize / 2f); newRoomLocation = new Vector3(oldRoomLocation.x - relativePosition, oldRoomLocation.y, 0); break; } case Entity.MoveDirection.down: //down { float relativePosition = Mathf.Floor(oldRoom.getSize() / 2f) + distance + Mathf.Ceil(roomSize / 2f); newRoomLocation = new Vector3(oldRoomLocation.x, oldRoomLocation.y - relativePosition, 0); break; } case Entity.MoveDirection.right: //right { float relativePosition = Mathf.Ceil(oldRoom.getSize() / 2f) + distance + Mathf.Floor(roomSize / 2f); //if size % 2 = 0, even, then nudge 1 back newRoomLocation = new Vector3(oldRoomLocation.x + relativePosition, oldRoomLocation.y); break; } } ///default case, it tries to initialize room at 0,0,0 newRoom = TryCreateRoom(newRoomLocation, roomSize, distance, direction); //try to create the room at specified location if (newRoom != null) //if room creation succeeded, store the room in list for later use { roomCount++; createdRoomsQueue.Enqueue(newRoom); } else if (direction == Entity.MoveDirection.right) { //else keep trying new directions until all exhausted direction = Entity.MoveDirection.up; } else { direction++; } }while (newRoom == null && direction != originalDirection); ///stop iterating when we successfully create a room, or when we reach original direction if (newRoom != null) //successfully created room, prepare for creating next room { while (tappedRoomsStack.Count != 0) //move all previously invalidated dungeon rooms back into queue again { createdRoomsQueue.Enqueue(tappedRoomsStack.Pop()); } } } //reaching here, this is not first room, so there exists at least one room, but we can't make any more rooms, so stop and cleanup else //createdRooms.Peek() == 0, so no more rooms to pick from. We can't build dungeon, so give up. { roomCount = numberOfRooms; //forces Generator to stop generating } } else //we are finished creating rooms { PopulateDungeon(); Destroy(this.gameObject); } }
/** * @precondition: attached object (this) has default rotation (Vector3: 0,0,0) * @params: roomOrigin -> location in 3d space for room origin (bottom left corner), * roomSize -> number of tiles to extend right and up from origin, * distanceAway -> distance from old tile that new tile is away, must be POSITIVE, used to populate connecting tiles * direction -> direction that new tile is relative to old tile * Checks for space occupation in area defined roomSize x roomSize right and up from specified origin position, * then if un-occupied, creates tiles there, afterwards creates hallway in opposite direction * returns a dungeon room representing the location and dimensions of the room, or null if Queue is empty **/ dungeon_room TryCreateRoom(Vector3 roomOrigin, int roomSize, float distanceAway, Entity.MoveDirection direction) { int halfSizeOffset = roomSize / 2; for (int i = 0; i < roomSize; i++) //(x coord) { for (int j = 0; j < roomSize; j++) //for every position in the room, try to place a tile there, if there is a tile, abort, (y coord) { Vector2 topRightLoc = new Vector2(roomOrigin.x + i + 0.25f - halfSizeOffset, roomOrigin.y + j - halfSizeOffset + 0.25f); Vector2 botLeftLoc = new Vector2(roomOrigin.x + i - 0.25f - halfSizeOffset, roomOrigin.y + j - halfSizeOffset - 0.25f); Collider2D collider = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask); //check if there is a tile there if (collider != null) //if a tile already exists here, this whole room is a bust { return(null); } } } for (int i = 0; i < roomSize; i++) //populate room with Tiles { for (int j = 0; j < roomSize; j++) { GameObject tile = (GameObject)Instantiate(roomFloorTilePrefab, new Vector3(roomOrigin.x + i - halfSizeOffset, roomOrigin.y + j - halfSizeOffset, roomOrigin.z), transform.rotation); if (tileContainer != null) { tile.transform.SetParent(tileContainer.transform); } } } /**now create the pathway leading away from this room, we don't care what is in the way, only that we fill in spaces that are unoccupied * switch(direction), for i = 0; i < distanceAway, i++), try to create tile at position relative to center in direction **/ switch (direction) { case Entity.MoveDirection.up: ///new room is above old room, so work down from new room { for (int i = 0; i <= distanceAway; i++) { Vector2 topRightLoc = new Vector2(roomOrigin.x + 0.25f, roomOrigin.y - halfSizeOffset - i + 0.25f); Vector2 botLeftLoc = new Vector2(roomOrigin.x - 0.25f, roomOrigin.y - halfSizeOffset - i - 0.25f); Collider2D collider = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask); //check if there is a tile there if (collider == null) //if no tile there, place a tile there { GameObject tile = (GameObject)Instantiate(roomFloorTilePrefab, new Vector3(roomOrigin.x, roomOrigin.y - i - halfSizeOffset, roomOrigin.z), transform.rotation); if (tileContainer != null) { tile.transform.SetParent(tileContainer.transform); } } } break; } case Entity.MoveDirection.left: ///new room is left of old room, so work right { int otherHalfSize = roomSize - halfSizeOffset; for (int i = 0; i <= distanceAway; i++) { Vector2 topRightLoc = new Vector2(roomOrigin.x + otherHalfSize + i + 0.25f, roomOrigin.y + 0.25f); Vector2 botLeftLoc = new Vector2(roomOrigin.x + otherHalfSize + i - 0.25f, roomOrigin.y - 0.25f); Collider2D collider = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask); //check if there is a tile there if (collider == null) //if no tile there, place a tile there { GameObject tile = (GameObject)Instantiate(roomFloorTilePrefab, new Vector3(roomOrigin.x + i + otherHalfSize, roomOrigin.y, roomOrigin.z), transform.rotation); if (tileContainer != null) { tile.transform.SetParent(tileContainer.transform); } } } break; } case Entity.MoveDirection.down: ///new room is beneath old room, so work up { int otherHalfSize = roomSize - halfSizeOffset; for (int i = 0; i <= distanceAway; i++) { Vector2 topRightLoc = new Vector2(roomOrigin.x + 0.25f, roomOrigin.y + otherHalfSize + i + 0.25f); Vector2 botLeftLoc = new Vector2(roomOrigin.x - 0.25f, roomOrigin.y + otherHalfSize + i - 0.25f); Collider2D collider = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask); //check if there is a tile there if (collider == null) //if no tile there, place a tile there { GameObject tile = (GameObject)Instantiate(roomFloorTilePrefab, new Vector3(roomOrigin.x, roomOrigin.y + i + otherHalfSize, roomOrigin.z), transform.rotation); if (tileContainer != null) { tile.transform.SetParent(tileContainer.transform); } } } break; } case Entity.MoveDirection.right: ///new room is right of old room, so work left { for (int i = 0; i <= distanceAway; i++) { Vector2 topRightLoc = new Vector2(roomOrigin.x - i - halfSizeOffset + 0.25f, roomOrigin.y + 0.25f); Vector2 botLeftLoc = new Vector2(roomOrigin.x - i - halfSizeOffset - 0.25f, roomOrigin.y - 0.25f); Collider2D collider = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask); //check if there is a tile there if (collider == null) //if no tile there, place a tile there { GameObject tile = (GameObject)Instantiate(roomFloorTilePrefab, new Vector3(roomOrigin.x - i - halfSizeOffset, roomOrigin.y, roomOrigin.z), transform.rotation); if (tileContainer != null) { tile.transform.SetParent(tileContainer.transform); } } } break; } } ///build path from room return(new dungeon_room(roomOrigin.x, roomOrigin.y, roomSize)); }