docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Explore the code of the Game State Machine sample

    The sample is split into an editor assembly and a runtime assembly. The editor assembly references the runtime one, because each authoring state creates its runtime counterpart.

    Editor

    File Role
    Editor/Model/GameFlowStateMachine.cs The state machine asset type. Declares the .gameflow extension, offers bool blackboard variables, and adds the Assets > Create menu item.
    Editor/Model/States/GameState.cs The abstract base of every state type. Declares its corresponding CreateRuntimeState.
    Editor/Model/States/SplashGameState.cs The Splash state whose runtime displays the splash screen.
    Editor/Model/States/ReadyGameState.cs The Ready state whose runtime handles the title screen display and interaction.
    Editor/Model/States/CountdownGameState.cs The Countdown state whose runtime displays the countdown screen.
    Editor/Model/States/MainGameState.cs The Main Game state whose runtime handles the endless runner main gameplay loop.
    Editor/Model/States/PauseGameState.cs The Pause state whose runtime freezes the time scale.
    Editor/Model/States/GameOverGameState.cs The Game Over state whose runtime displays the game over screen.
    Editor/Model/Conditions/GameSignalCondition.cs A condition that is true when a given signal was raised this frame.
    Editor/Model/Conditions/TimeInStateCondition.cs A condition comparing the time spent in the current state against a number of seconds.
    Editor/Model/Transitions/EntryTransition.cs A marker self transition that records where the state machine starts.
    Editor/AssetImport/GameFlowStateMachineImporter.cs Converts the authored state machine into the runtime asset.
    Editor/Toolbar/DebugViewToggle.cs Turns the debug view on or off from the state machine editor's toolbar.

    Declaring a state type

    Each state type derives from GameState, is decorated with [State] to give it a title in the graph item library, declares its options in OnDefineOptions, and converts itself into its runtime counterpart in CreateRuntimeState. For example, CountdownGameState:

    [Serializable]
    [State(null, null, "Countdown")]
    class CountdownGameState : GameState
    {
        const string DurationOptionName = "Duration";
    
        protected override void OnDefineOptions(IOptionDefinitionContext context)
        {
            context.AddOption<float>(DurationOptionName)
                .WithDisplayName("Duration")
                .WithTooltip("Seconds to count down from. ...")
                .WithDefaultValue(3f)
                .Build();
        }
    
        public override RuntimeGameState CreateRuntimeState() => new CountdownRuntimeGameState
        {
            Duration = Mathf.Max(0f, GetOptionValue<float>(DurationOptionName))
        };
    }
    

    GameState is abstract and has no [State] attribute, so it is not offered in the state machine editor. GameState.GetOptionValue wraps GetOptionByName and IStateOption.TryGetValue.

    Note that a state option is only shown in the graph inspector when the state is selected. It is never drawn on the state the way a node option is drawn on a node.

    A state machine asset stores the class name, namespace and assembly of each state's type. Renaming a GameState subclass, moving it to another namespace, or moving it to another assembly will break the states of that type in existing state machines unless you add a [MovedFrom] attribute to it. Runtime classes have no such restriction, because the runtime asset is rebuilt on every import.

    Converting states at import

    GameFlowStateMachineImporter.CreateRuntimeState asks each state to create its runtime counterpart:

    if (state is GameState gameState)
        return gameState.CreateRuntimeState();
    
    ctx.LogImportWarning($"'{state.Title}' is not a Game State, so it does nothing while it is active.");
    return null;
    

    StateMachine.GetStates returns the user-defined State instances, so each state can be matched against GameState directly. The returned runtime state is stored in GameFlowRuntimeState.RuntimeState, which is marked [SerializeReference] so that the concrete RuntimeGameState subclass and its values are kept when the runtime asset is serialized.

    If you modify the API surface of the GameFlowRuntimeStateMachine or of a RuntimeGameState subclass, remember to bump the version in the GameFlowStateMachineImporter's [ScriptedImporter] attribute. Otherwise, an old cached import artifact might stay in use instead of an up to date GameFlowRuntimeStateMachine.

    Runtime

    File Role
    Runtime/RuntimeGameState.cs Abstract parent of all runtime states: OnEnter, OnUpdate and OnExit.
    Runtime/States/PauseRuntimeGameState.cs Sets Time.timeScale on enter, restores it on exit.
    Runtime/States/SplashRuntimeGameState.cs Shows the splash screen on enter, hides it on exit.
    Runtime/States/ReadyRuntimeGameState.cs Shows the title screen, and raises a signal on a button press.
    Runtime/States/CountdownRuntimeGameState.cs Counts the countdown screen down from the runner's time in state.
    Runtime/States/MainRuntimeGameState.cs Runs and scores the endless runner, and raises a signal when the player dies.
    Runtime/States/GameOverRuntimeGameState.cs Shows the game over screen, and raises a signal on a button press.
    Runtime/GameFlowRuntimeStateMachine.cs The imported data: states, transitions, rules, variables.
    Runtime/GameFlowRuntimeConditions.cs The runtime form of each condition type.
    Runtime/GameFlowConditionEvaluator.cs Evaluates a condition tree against a context, and records what it did.
    Runtime/GameFlowRunner.cs The component that ticks the machine.
    Runtime/GameFlowDebugVisualizer.cs Draws the running state machine onto the graph editor. Editor only.
    Runtime/UI/ Contains code related to the UI.
    Runtime/EndlessRunner/ Contains code related to the endless runner game.

    The update loop

    GameFlowRunner.Update does the following:

    1. Advances the time in the current state by Time.deltaTime.
    2. Calls OnUpdate on the active state.
    3. Evaluates the current state's transitions, in the order they were added, and their rules within each. The first enabled rule whose conditions are met is selected.
    4. Takes the selected transition.
    5. Discards the game signals raised this frame.

    OnUpdate runs before the transitions are evaluated on purpose; this allows the active state to potentially raise a game signal first (for example because a button was pressed like ReadyRuntimeGameState does) which could affect which transition gets selected.

    Game signals are discarded at the end of every frame, so a signal cannot fire a transition several frames after it was raised.

    A transition with no rules never fires, and neither does one whose every rule is disabled. An empty condition group whose root group is an empty And always fires, whereas one whose root group is an empty Or never does.

    Debug view

    While the game plays, the sample uses the Unity.GraphToolkit.Editor.GraphVisualization API to turn the state machine editor into a debugging view. The active state's accent is animated, its selected outgoing transition is colored green whereas the ignored transitions are colored red, and every condition gets a true, false, or pending icon on its row in the transition inspector.

    This sample demonstrates usage of StateReference, TransitionReference and ConditionReference. For examples on how to use node specific visualization features, check out the Visual Novel Director sample.

    The visualization API can only be used in the editor, so GameFlowDebugVisualizer wraps all usage in #if UNITY_EDITOR.

    Access to authoring IDs at runtime

    The visualization API requires the IDs of the authoring state machine elements, so the importer copies them into their runtime equivalents:

    var runtimeState = new GameFlowRuntimeState
    {
        ID = state.ID,
        Name = state.Title,
        RuntimeState = CreateRuntimeState(ctx, state)
    };
    

    Toolbar toggle

    DebugViewToggle is registered with [GraphToolbarElement(id, typeof(GameFlowStateMachine))], in the Editor/Toolbar folder. It cannot be used outside play mode.

    The toggling relies on the StateCustomizationEnabled, TransitionCustomizationEnabled and ConditionCustomizationEnabled APIs. These hide the overrides without discarding them, so switching the toggle back on restores the debugging visuals rather than redraws them.

    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)