top of page

Room Spawning

Code Sample

Below is an example of work from one of my independent student projects: an automated, random dungeon generator. The system works in stages to generate a dungeon layout with pre-generated rooms and objects, and has a UI that users can interact with to use it. The code sample will cover a small section of the system, written in C# for Unity. Upon pressing a green “Begin” button, the system will start to generate rooms. The system runs through these steps, start to finish:

  1. Pick a random room to be our first room, and fill it with random objects at locations in the room.

  2. Pick and create up to 4 rooms off of the first room, as well as the objects to fill them.

  3. Pick and create up to 3 rooms off of the new rooms, as well as the objects to fill them.

  4. Repeat Step 3 until the system detects that we have the correct number of rooms.

  5. When the system detects that we have enough rooms, tell the rooms to stop creating new rooms and move to the next phase, which is to wall off unused hallways.

This is all a part of the first phase of the system. The following is the code which actually creates a room.

/******************************************************************************/
/*
Author: Jeff Grow
Brief:  This code snippet is a component that is placed on each pre-made room.
        It helps in the creation of new rooms, and keeps track of vital statistics
        for room generation. When a room creates a new room, that room will also
        have this script, allowing it to spawn more rooms in turn. This continues
        until the system detects that we have enough rooms for the floor.
 
All content © 2016 DigiPen (USA) Corporation, all rights reserved.
*/
/******************************************************************************/


//Including Unity system files for the code to function.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class RoomSpawner : MonoBehaviour
{
    //Allows us to get the Room Directory so we can see and use the list of pre-made rooms.
    public List<RoomSpawner> Rooms
    {
        get
        {
            return LevelParameters.GetComponent<RoomDirectory>().Rooms;
        }
    }

    //Array of Door Blockers for this room, which allow us to close off doors we don't need later.
    public GameObject[] DoorBlockers;

    //Array of Door Checkers, which check to see if two doorways are connected.
    public GameObject[] DoorCheckers;

    //An array of booleans which mark which doors are currently being used in a room.
    public bool[] IsDoorInUse;

    //The mininmum and maximum random range for the number of rooms this room can create.
    public float MinimumNumberOfRooms;
    public float MaximumNumberOfRooms;

    //Stores the number of rooms this room will connect to.
    [HideInInspector]
    public int TargetNumberOfRooms;

    //The Level properties object, so we can know perameters of the level.
    public GameObject LevelParameters;

    //A shortcut variable for easy access to the LevelProperties Component.
    public LevelProperties LevelProperties;
    //A shortcut variable for easy access to the RoomProperties Component.
    public RoomProperties RoomProperties;
    //A shortcut variable for easy access to the SystemOverseer Component.
    public SystemOverseer SystemOverseer;

    /*This is the artificial timer that is for presentation purposes. It spaces out the room placements so users can
    see the system in action. */
    [HideInInspector]
    public int ArtificalTimer = 0;

    //The current step that the spawner system is in. It is specifically for closing the doors that aren't in use.
    [HideInInspector]
    public int DoorStep = 0;

    //The number of rooms that this room has created.
    [HideInInspector]
    public int RoomCounter = 0;

    //This is a special data type that is used for saving and loading level layouts.
    public RoomData MyData = new RoomData();

    //Checks if this room was loaded using the save/load functionality.
    [HideInInspector]
    public bool WasLoaded = false;
    
    void Start()
    {
        //Finding the level properties for the scene.
        LevelParameters = GameObject.Find("LevelProperties");

        //Finding the components so we can use the variables instead.
        LevelProperties = LevelParameters.GetComponent<LevelProperties>();
        SystemOverseer = LevelParameters.GetComponent<SystemOverseer>();
        RoomProperties = GetComponent<RoomProperties>();

        //Selecting the random number of rooms this room will spawn.
        TargetNumberOfRooms = ((int)Random.Range(MinimumNumberOfRooms, MaximumNumberOfRooms));
    }

    void Update()
    {
        
        //Check if the system wants to generate more rooms.
        if (SystemOverseer.CurrentState == SystemOverseer.SystemState.Generate)
        {
            //Check if we have has less rooms than what this room wants to create.
            if(RoomCounter <= TargetNumberOfRooms)
            {
                //Check if we are past the artifical waiting period.
                if (ArtificalTimer >= 30)
                {
                    /* Reset the timer for this room and mark it in the system so that
                    it won't be destroyed if another room spawns on top of it. */
                    ArtificalTimer = 0;
                    if ((RoomProperties.CanBeDestroyed) == true)
                    {
                        RoomProperties.CanBeDestroyed = false;
                        //Registers this room with the system so it can be saved later if we want.
                        SystemOverseer.RegisterRoom(this);
                    }
                    //If the system has space for more rooms, then we continue by picking a random door.
                    if (LevelProperties.RoomCount <= LevelProperties.NumberOfRooms)
                    {
                        int TempRand = (Random.Range(0, (IsDoorInUse.Length)));
                        /*If that doorway isn't being used, spawn a random room using it. Then tell the system
                        that we have created another room so it can keep track.*/
                        if (IsDoorInUse[TempRand] == false)
                        {
                            SpawnRandomRoom(TempRand);
                            LevelProperties.RoomCount++;
                            RoomCounter++;
                        }
                    }
                }
                //Increment the timer so we can create some spacing between rooms being created.
                ArtificalTimer++;
            }
        }
    }

    //This function is given the randomly selected door so it can create a room from it.
    void SpawnRandomRoom(int RandomDoor)
    {
        //Creates a variable we can use to manipulate our newly spawned room.
        GameObject temp;
        /*Marks the random door as in use, selects a random room from the room directory,
        and then creates a copy of the selected room.*/
        IsDoorInUse[RandomDoor] = true;
        int RandomRoom = Random.Range(0, (Rooms.Count));
        temp = Instantiate(Rooms[RandomRoom]).gameObject;

        //Calculate half the height and width of the new and old rooms
        float OldRoomHalfHeight = RoomProperties.RoomMeasurements.x / 2;
        float NewRoomHalfHeight = Rooms[RandomRoom].GetComponent<RoomProperties>().RoomMeasurements.x / 2;
        float OldRoomHalfWidth = RoomProperties.RoomMeasurements.z / 2;
        float NewRoomHalfWidth = Rooms[RandomRoom].GetComponent<RoomProperties>().RoomMeasurements.z / 2;

        //Shortcut variable for the old room's current position.
        Vector3 RoomPos = transform.position;

        //Checks if our current random door is the North door (in the system as door "0")
        if (RandomDoor == 0)
        {
            //Place the new room north of the old room
            temp.GetComponent<Transform>().position = new Vector3(((RoomPos.x + OldRoomHalfHeight) + (NewRoomHalfHeight)), (RoomPos.y), (RoomPos.z));
        }

        //Checks if our current random door is the East door (in the system as door "1")
        if (RandomDoor == 1)
        {
            //Place the new room east of the old room
            temp.GetComponent<Transform>().position = new Vector3((RoomPos.x), (RoomPos.y), (RoomPos.z + -(OldRoomHalfWidth) + -(NewRoomHalfWidth)));
        }

        //Checks if our current random door is the South door (in the system as door "2")
        if (RandomDoor == 2)
        {
            //Place the new room south of the old room
            temp.GetComponent<Transform>().position = new Vector3( (RoomPos.x + -(OldRoomHalfWidth) + -(NewRoomHalfWidth)), (RoomPos.y), (RoomPos.z));
        }

        //Checks if our current random door is the West door (in the system as door "3")
        if (RandomDoor == 3)
        {
            //Place the new room west of the old room
            temp.GetComponent<Transform>().position = new Vector3((RoomPos.x), (RoomPos.y), (RoomPos.z + OldRoomHalfWidth + NewRoomHalfWidth));
        }

        //Lets the new room know which door spawned it so it doesn't try to use it.
        temp.GetComponent<RoomSpawner>().MarkConnectingDoor(RandomDoor);

        //Fills out data for the new room for saving and loading.
        temp.GetComponent<RoomSpawner>().MyData.ArchetypeName = Rooms[RandomRoom].name;
        temp.GetComponent<RoomSpawner>().MyData.Position = temp.GetComponent<Transform>().position;

        /* Tells the new room what room created it so it can send back data in case it needs
        to be destroyed for any reason. */
        temp.GetComponent<RoomProperties>().SetPreviousRoom(RandomDoor, gameObject);
    }
}
]]

 

bottom of page