Skip to main content

Tutorial System

Build in-game tutorials as ScriptableObject-based steps. Designers can change the flow without hardcoding, and the runtime supports skipping, replaying, saving, and loading completion state.

Structure

TutorialSystem - Pure C# instance. Saves and restores completed tutorials.
└── TutorialRunner - MonoBehaviour that runs tutorial steps as coroutines.

TutorialSequence - ScriptableObject. Step list and skip settings.
└── TutorialStep[] - ScriptableObject base class for concrete tutorial steps.

Built-In Steps

StepDescription
HighlightButtonStepHighlights a UI object and optionally waits for an action key
WaitForActionStepWaits until a named player action is triggered
DialogueStepShows a message panel, then auto-advances or waits for click input
DelayStepWaits for a fixed number of seconds

Quick Start

1. Add TutorialRunner to the Scene

// Only TutorialRunner needs to live on a GameObject because it runs coroutines.
// TutorialSystem is created from code.

2. Create a TutorialSequence Asset

Project window -> Create -> AchUtils/Tutorial/Tutorial Sequence

Configure the steps in the inspector:

SequenceId : "FirstGacha"
CanSkip : true
Steps:
[0] HighlightButtonStep - Highlight GachaButton, wait for "GachaClick"
[1] DialogueStep - "You obtained a character!"
[2] HighlightButtonStep - Highlight EquipButton

3. Start the Tutorial

[SerializeField] TutorialRunner tutorialRunner;
[SerializeField] TutorialSequence gachaSequence;

private TutorialSystem tutorialSystem;

void Awake()
{
tutorialSystem = new TutorialSystem(tutorialRunner);
}

void OnDestroy()
{
tutorialSystem.Dispose();
}

// Completed tutorials are skipped automatically.
tutorialSystem.StartTutorial(gachaSequence);

// Force replay, ignoring completion state.
tutorialSystem.StartTutorialForce(gachaSequence);

4. Trigger Player Actions

Call TriggerAction from button handlers or gameplay events.

public void OnGachaButtonClicked()
{
tutorialSystem.TriggerAction("GachaClick");
// Continue normal game logic...
}

API

TutorialSystem

TutorialSystem(TutorialRunner runner, bool loadOnCreate = true)

void StartTutorial(TutorialSequence sequence)
void StartTutorialForce(TutorialSequence sequence)
void Skip()
void TriggerAction(string key)
bool IsCompleted(string sequenceId)
void Save()
void Load()
void ResetAll()
void Dispose()

TutorialRunner

bool IsRunning
int CurrentStepIndex

event Action OnCompleted
event Action OnSkipped
event Action<int> OnStepChanged

Custom Steps

Inherit from TutorialStep and implement Execute.

[CreateAssetMenu(menuName = "AchUtils/Tutorial/Steps/My Step")]
public class MyCustomStep : TutorialStep
{
public GameObject TargetPanel;

public override IEnumerator Execute(TutorialRunner runner)
{
TargetPanel.SetActive(true);

while (!runner.HasTriggeredAction("PanelClosed"))
yield return null;

runner.ConsumeAction("PanelClosed");
TargetPanel.SetActive(false);
}
}

Save Format

Completed SequenceId values are saved to PlayerPrefs as a comma-separated string.

AchUtils_Tutorial_Completed = "FirstGacha,FirstEquip,FirstDungeon"

::: tip If SequenceId is empty, completion is not saved. You can also disable saving with SaveProgress = false. :::

Flow Example

Start

HighlightButtonStep "Click the gacha button"

WaitForActionStep "GachaClick"

DialogueStep "You obtained a character!"

HighlightButtonStep "Open the equipment screen"

End -> MarkCompleted("FirstGacha")