Home / Legacy / Lesson 9: The Stage Manager

Lesson 9: The Stage Manager

This entry is part 12 of 15 in the series Unity 3d Fundamentals Course

In the previous lesson we finished the environment by placing all assets in the scene.

In this lesson we are going to start working on the game logic.

Lesson 9: The Stage Manager

Our project has three different stages. At the beginning only the first one will be active. When all targets on the first stage are destroyed the second one will be activated and so forth. After completing all stages the game is finished and we will show some statistics to the player about his performance.

In this lesson we will start by creating a Stage Manager to deal with the state of each shooting stage.

Lesson Outline

Create the Stage Beacon

Lesson 9: The Stage Manager

The Stage Beacon is responsible for activating each stage. We will use a Trigger to detect when the Player is inside the beacon and enable the corresponding stage.

But first we will start with the beacon visuals. Download and import the necessary textures: [wpdm_file id=3]

As you see the textures are completely white. Whenever you need to use the same texture with different colors, the best way is to create a single white texture and change its colour using the shader properties. This way you can have as many colored textures you want using a single texture file in your project.

Create a new material for each texture and change the shader to Transparent/Diffuse. This shader deals with the texture transparency and allows us to change the tint color of the material.

Lesson 9: The Stage Manager

Lesson 9: The Stage Manager

Lesson 9: The Stage Manager


Place the quads on the position of the first beacon and point to the arrow to the first stage area. Also don’t forget to remove the Mesh Colliders.

Lesson 9: The Stage Manager

These textures are separated because we want the circle to be constantly rotating while the arrow should remain static. So lets create a new script to make the circle rotate around its own center.

Create a new script called StageBeacon and add the following code.

We used the Rotate method of the Transform class.

void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self);

  • no return value;
  • Vector3 eulerAngles – how many degrees to rotate on each call;
  • Space relativeTo – the coordinate system to use (lets use the default);

In this case we are rotating the object on the Y axis – Vector3.up equals Vector3(0, 1, 0) – a specific number of degrees- defined by the speed variable – per second – defined by the Time.deltaTime.

Create a root object for the circle and add the StageBeacon. Assign a rotation speed – e.g. 100.

Don’t forget to center the circle object on the root.

Lesson 9: The Stage Manager

Now lets add a Point Ligth to illuminate the ground and the surrounding area of the beacon.

Lesson 9: The Stage Manager

Also add a particle system with the following configuration.

Lesson 9: The Stage Manager

Create a root object for the beacon and place all elements inside. The only object that should remain static is the arrow. All the rest should be inside the root-circle object.

Lesson 9: The Stage Manager

The beacon visuals are ready. Now we need to deal with the Triggering part.

Lets add a Box Collider to our stage beacon root and make it a Trigger.

Lesson 9: The Stage Manager

To detect the collision we will need a script with the Trigger methods. Create a new script called StageBeaconCollider and add the following code.

To know more about Triggers check our Lesson 2: Create the First Person Weapon

The Stage Beacon is now created and able to detect collisions. Now we need to create the Stage Manager to respond to this events.

Create the Stage Manager

Each shooting stage will have a Stage Manager to deal with its own state. Create a StageManager script and apply it to the StageOne object, created on the last lesson – the parent object of all stage targets.

Lesson 9: The Stage Manager

The first responsibility of the Stage Manager is to activate the stage when the Player is inside the beacon. Lets add a public method to activate the stage.

This script needs to know which targets are under his control. Since its the root object of all targets we can easily access them. Create a public reference to store all targets. To prevent from manipulating directly the target GameObjects we will use the Target Controller. Declare a public static array of type Target Controller.

We are declaring it public so we can see the array on the inspector otherwise it should be private.

To get all TargetControllers we will use the Component.GetComponentInChildren method.

Component[] GetComponentsInChildren(Type t, bool includeInactive = false);

  • returns a static array of the type t;
  • Type t – the type of the component we want to get;
  • bool includeInactive – should we get the components on the inactive gameobject as well.

Now on the Awake method we are going to fill in the array with the objects using the GetComponentInChildren. This method returns a static array of all components found in the GameObject active children.

Lesson 9: The Stage Manager

When a stage is enabled, the idea is to activate the several targets, one after the other with a time interval in between. To create a more interesting behaviour we are going to randomize the targets order so each time we play the targets will be randomly enabled. I’ve found a shuffle algorithm for arrays that does exactly what we need – Knuth shuffle algorithm. Create a new private method called ShuffleTargets and add the following code.

Lets call this method right after populating the targets array.

Now the targets order will be randomized at the beginning of the game.

Lesson 9: The Stage Manager

Now that the targets are randomized we will iterate over the array activating each one of them with a time interval in between. If we are using a time interval it means we will be using a Coroutine.

Declare a public variable to hold how much time to wait between targets activation.

Lets create a Coroutine to activate a target, wait for the specified time interval and then proceed activating the next one. Create a new Coroutine called CoActivateTarget.

To iterate over the array use  a for loop.  The for loop runs through each array elements until reaching the array length. Add a for loop to your Coroutine.

Now each time we enter the loop we will wait for a random time interval based on the one specified. Similarly to Lesson 7: Introducing Coroutines we are going to randomize the time interval by a specified percentage.

When the wait is over the loop will continue and we will activate the target. Since we are using a TargetController we will call the Activate Target method.

After activating the target, the loop begins again and everything repeats until reaching the total number of targets.

The Stage is activated when the Player enters the beacon. Now we need to call the ActivateStage method when it happens.

In the StageBeaconCollider add a public reference to the Stage Manager and call the ActivateStage when the Player enters the trigger. Also don’t forget to disable the beacon.

Right now the StageManager is simply activating all targets. We want it to also manage the targets configuration. All targets on the same stage should have a similar behaviour. So Instead of configuring each target values individually we will use the StageManager to define those values.

We want to define the speed, waiting time and random factor for each the movement and rotation components. Lets create a new class to hold these values so its cleaner to move them around the scripts.

The Target Config class does not extend MonoBehaviour since its a “regular” class. No need to assign them to a GameObject.

Now lets create two public variables of type TargetConfig on the StageManager component.

We want these variables to be available on the Inspector so we need to make the class Serializable.

Now we need to change the ActivateTarget method of the TargetController. Lets add two arguments to hold the TargetConfig for the movement and the rotation.

On the StageManager we need to change the method call by adding these two arguments. On the CoActivateTarget add the variables as arguments.
Now we are able to define the config values for each component on the StageManager and we are sending them to the TargetController. Lets apply these values to the corresponding behaviours. First we need to get a reference to each behaviour on the Target object. Lets create two private references and assign them on the Awake method.
On the ActivateTarget method we need to pass the arguments to each controller.
To finish each controller must have the SetConfig method declared and do something with the configuration. Lets create a new public method called SetConfig on each behaviour – TargetMovement and TargetRotation.
We will use the TargetConfig to set the values of the corresponding variables.
Now all targets of the same stage are being configured in a single place – the StageManager. All targets will have a similar behaviour with subtle differences resulting from the randomness applied.

Full Codes





Names to keep

What’s next…

On the following lesson we will create the Game Manager to control the multiple stages.


Series Navigation<< Lesson 8: Finishing the EnvironmentLesson 10: The Game Manager >>

Leave a Comment

Your email address will not be published. Required fields are marked *