Creating a Step-By-Step Event-Based Tutorial

It is common in games of any complexity to point things out for the player to do, in sequence, to get the hang of it when it’s his or her first time playing.

For example in an RTS, you might start the first mission with one unit, and you display an arrow pointing to it with a message telling them to click on it. Then when they do, tell them to move it to a certain area, then to attack a given enemy, then move somewhere else, then make another unit appear and have them click a button to show its abilities, then to click on a certain one, etc.

I’m trying to conceptualize what would be the most elegant, and flexible, way of implementing such an event-based system once you already have the engine built. Having a tutorial that waits for desired actions at given times, while still running the whole engine, is sort-of like having dozens of “winning conditions”, only one of which is valid at a time.

The only practical way I can think of is to have a global int for the current tutorial step, and then to fill each possible event involved in the tutorial with conditions, such as:

if(GUI.Button(myRect,"Move Unit")){
	if(tutorialStep==3 || tutorialStep==16 || tutorialStep==27)
		Next_Tutorial_step();
	//Do the button's actual logic here
}

As you can imagine, it’d become a bit bloated to fill the code for every button, action or keystroke that’s involved in the tutorial with conditions like this, especially if it’s comprehensive and involves at some point each of the dozens of actions you can perform in the game. This would for example require running code inside a unit movement function to check whether we’re in a tutorial and, if so, whether we’re selecting the object we’re supposed to for the current step, and if so, whether it’s going to the desired location etc.

It would be preferable to have everything in a separate Tutorial class which when activated could somehow be watching all events such as button clicks, locations of given objects, keystrokes or any other action that you want to register to it at some point or another.

Has anyone implemented such a system in Unity, which also has the flexibility to add new steps for future buttons or actions in one place?

Well I’d do it like this:

Create the description of your tutorial step as a ScriptableObject derived class so that it can a) be persistent b) be edited independently in the Inspector and c) refer to project items that might need to be created.

Have this class use a linked list style to the next step of the tutorial - so in other words have it hold a pointer to the next class. This gives you maximum flexibility in the future. Also give it an unique id - probably based on a GUID (Guid.NewGuid().ToString()) so you can find them easily.

You need to actually add these steps to the AssetDatabase so that they become a part of the project.

I would suggest you define the predicates for each step to be either an elapsed time or one of a list of “steps” (though I expect you will only use 1).

You use PlayerPrefs to store the ID of the last used step and write a static function on the tutorial step class that takes an “Action” - you would call from everywhere that might trigger a tutorial step.

So

   TutorialStep.Did("Move Unit");

The static would examine the predicates of the current step and compare them against the string passed in - if it matches the tutorial is shown and the next step made current.

You also call a time function on a regular interval, say every 20 seconds:

    IEnumerator Start() {
          var t = Time.time;
          while(true) {
              yield return new WaitForSeconds(20);
              TutorialStep.After(Time.time - t);
          }
    }

This way is very flexible and require you only to specify events to the system, not provide predicate logic inside your UI etc.