State Pattern - Managing Character States

Managing Character States

The State Pattern 🎭

CSCI 3213 - Game Programming

From idle to action - managing entity behaviors!

Today's Content

πŸ“š Based on Chapter 5

Managing Character States with the State Pattern

From: Game Development Patterns with Unity 2021 (2nd Edition)
By David Baron

Available: Dulaney Browne Library or major book retailers. This chapter introduces state management and Unity's animation system!

Today's Learning Objectives

What We'll Master

  • 🎯 Understand the State Pattern structure
  • 🎯 Define character finite states
  • 🎯 Implement State Pattern in C#
  • 🎯 Recognize pattern limitations
  • 🎯 Leverage Unity's Animation System FSM

Goal: Build a motorcycle controller with multiple states (Stop, Start, Turn, Crash) using the State pattern.

Developer's Note: "Never Panic Early"

⚠️ What to Expect During Implementation

As we implement this pattern, we'll be creating multiple files in a specific order. You will see errors in Unity and your IDE until all files are complete.

How to Handle Development Errors

  • Don't Ignore: Note the errors - they're telling you something
  • Don't Panic: These are expected until all files are created
  • Stay Calm: Follow the implementation order and errors will resolve

As Apollo 13's Fred Haise said: "Never Panic Early"

This is a critical skill for software development. Note problems, but stay focused on the implementation path.

The Problem: State Transitions

In Games, Entities Constantly Change States

  • Enemy: Idle β†’ Patrol β†’ Chase β†’ Attack β†’ Death
  • Player: Idle β†’ Walk β†’ Run β†’ Jump β†’ Fall β†’ Land
  • Vehicle: Stop β†’ Start β†’ Turn β†’ Accelerate β†’ Crash
  • Door: Closed β†’ Opening β†’ Open β†’ Closing

❌ Without State Pattern

Massive switch statements, bloated controller classes, behaviors scattered everywhere, difficult to add new states, impossible to maintain!

What is the State Pattern?

State Pattern

A behavioral pattern that allows an object to alter its behavior when its internal state changes.

βœ… Key Concept

Encapsulate state-specific behaviors into separate classes. The object appears to change its class when it changes state.

In Simple Terms: Each state is its own class with its own behavior. Changing state = switching which class handles the behavior.

State Pattern Structure

Core Participants

1. Context Class

β€’ Defines interface for clients to request state changes

β€’ Holds pointer to current state

β€’ Example: BikeStateContext

2. IState Interface

β€’ Establishes contract for concrete states

β€’ Defines Handle() method

β€’ Example: IBikeState

3. ConcreteState Classes

β€’ Implement IState interface

β€’ Contain state-specific behavior

β€’ Example: BikeStartState, BikeStopState, BikeTurnState

State Pattern UML Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   BikeController    β”‚  ← Client
│─────────────────────│
β”‚ + StartBike()       β”‚
β”‚ + StopBike()        β”‚
β”‚ + Turn()            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ uses
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ BikeStateContext    │────────▢│  IBikeState  β”‚  ← Interface
│─────────────────────│         │──────────────│
β”‚ - currentState      β”‚         β”‚ + Handle()   β”‚
β”‚ + Transition()      β”‚         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
                                       β”‚ implements
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό                        β–Ό                    β–Ό
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚ BikeStopState  β”‚      β”‚ BikeStartState β”‚  β”‚ BikeTurnState  β”‚
     │────────────────│      │────────────────│  │────────────────│
     β”‚ + Handle()     β”‚      β”‚ + Handle()     β”‚  β”‚ + Handle()     β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                

Defining Character States

Our Racing Motorcycle

STOP
β†’
START
β†’
TURN
β†’
CRASH

Finite States for Blade Racer Bike

These are the discrete states our motorcycle can be in at any given moment. Each state has specific behaviors and animations.

Finite State Machine (FSM): A system can only be in ONE state at a time.

State Behavior Definitions

πŸ›‘ STOP State

  • Speed: Zero
  • Gears: Neutral
  • Animation: Engine idle (chassis vibrating)
  • Input: Can transition to START

▢️ START State

  • Speed: Max speed
  • Movement: Forward motion
  • Animation: Wheels turning
  • Input: Can TURN or STOP

πŸ”„ TURN State

  • Direction: Left or Right
  • Movement: Lateral shift
  • Animation: Bike tilting
  • Input: Return to START

πŸ’₯ CRASH State

  • Speed: Decelerating
  • State: On fire, on side
  • Animation: Crash sequence
  • Input: No longer responds

Knowledge Check: State Pattern

Click each card to reveal the answer!

❓ Question 1

Why use the State Pattern instead of a large if/else or switch statement to handle bike behavior?

❓ Question 2

The bike has four states: STOP, START, TURN, and CRASH. How does the BikeController know which state it's currently in?

❓ Question 3

Looking at our FSM diagram, what should happen if the bike tries to TURN while in the STOP state?

❓ Question 4

In the CRASH state, animations play and the bike no longer responds to input. Why is this behavior encapsulated in the state itself rather than in the BikeController?

Implementation Step 1: Interface

πŸ“ File Structure Note

Create a new file: Assets/Scripts/Patterns/State/IBikeState.cs
This interface defines the contract that all bike states must follow.

/// The state interface public interface IBikeState { // Handle state behavior void Handle(BikeController controller); }

How This Works

IBikeState Interface: All concrete states (Stop, Start, Turn, Crash) will implement this interface.

Handle() Method: Each state implements its own behavior here. We pass in BikeController so states can access bike properties (speed, direction, etc.).

Don't Worry! Your editor will show red squiggly lines under BikeController because we haven't defined it yet. We'll create it in Step 3. The red lines will disappear then!

Design Note: This is a Unity-adapted approach - we pass the controller reference to each Handle() call rather than storing it permanently.

Implementation Step 2: Context

πŸ“ File Structure Note

Create a new file: Assets/Scripts/Patterns/State/BikeStateContext.cs
This class manages state transitions and holds the current state.

public class BikeStateContext { // Current state public IBikeState CurrentState { get; set; } // Reference to controller private readonly BikeController _bikeController; public BikeStateContext( BikeController bikeController) { _bikeController = bikeController; } // Transition current state public void Transition() { CurrentState.Handle(_bikeController); } // Transition to new state public void Transition(IBikeState state) { CurrentState = state; CurrentState.Handle(_bikeController); } }

How This Works

BikeStateContext: The "context" class that manages state transitions. It knows the current state and can switch between states.

Why readonly? The _bikeController is marked readonly because once we set it in the constructor, it should never change. The bike controller reference stays the same for the entire lifetime of this context.

Note: readonly means the field can only be assigned in the constructor or at declaration. This prevents bugs where we accidentally reassign it later.

Two Transition Methods: We have two methods both named Transition - this is called method overloading in C#. One takes no parameters and re-triggers the current state. The other takes an IBikeState parameter, switches to that new state, AND triggers it.

C# Feature: Overloading allows multiple methods with the same name but different parameters. The compiler picks the right one based on what arguments you pass!

Implementation Step 3: Controller

πŸ“ File Structure Note

Create a new file: Assets/Scripts/Controllers/BikeController.cs
This is the main controller that uses the State pattern to manage bike behavior.

using UnityEngine; public class BikeController : MonoBehaviour { // Configuration public float maxSpeed = 2.0f; public float turnDistance = 2.0f; // Current state data public float CurrentSpeed { get; set; } public Direction CurrentTurnDirection { get; private set; } // State references private IBikeState _startState, _stopState, _turnState; private BikeStateContext _bikeStateContext; void Start() { _bikeStateContext = new BikeStateContext(this); _startState = gameObject.AddComponent <BikeStartState>(); _stopState = gameObject.AddComponent <BikeStopState>(); _turnState = gameObject.AddComponent <BikeTurnState>(); _bikeStateContext.Transition(_stopState); } public void StartBike() => _bikeStateContext.Transition(_startState); public void StopBike() => _bikeStateContext.Transition(_stopState); public void Turn(Direction direction) { CurrentTurnDirection = direction; _bikeStateContext.Transition(_turnState); } }

How This Works

BikeController: This is the MonoBehaviour that gets attached to the bike GameObject. It's the main entry point for controlling the bike.

Start() Method: Creates the context and all state objects, then sets the initial state to STOP.

The 'this' Keyword: When we call new BikeStateContext(this), the this keyword refers to the current BikeController instance. We're passing a reference to "myself" so the context knows which bike it's managing!

C# Tip: this is a reference to the current object. Inside BikeController, this means "this BikeController object."

AddComponent<T>(): Unity's way of adding scripts as components. Each state becomes a MonoBehaviour on the same GameObject!

Public Methods: Other scripts call StartBike(), StopBike(), or Turn() to change the bike's state. These methods delegate to the context.

Game Flow: When player presses W, some input script calls BikeController.StartBike(), which transitions to the START state!

Implementation Step 4: Stop State

πŸ“ File Structure Note

Create a new file: Assets/Scripts/Patterns/State/BikeStopState.cs
This is a concrete state that implements the STOP behavior.

using UnityEngine; public class BikeStopState : MonoBehaviour, IBikeState { private BikeController _bikeController; public void Handle( BikeController bikeController) { // Cache reference if (!_bikeController) _bikeController = bikeController; // STOP: set speed to zero _bikeController.CurrentSpeed = 0; Debug.Log("[BikeStopState] Stopped"); } }

How This Works

BikeStopState: The STOP state behavior encapsulated in a class. This is a MonoBehaviour that implements IBikeState.

Handle() Method: Called when bike transitions to STOP state. Sets speed to zero - that's all STOP does!

Caching Reference: We cache _bikeController on first call so we don't have to pass it every frame. Unity pattern optimization.

In a full game: This would also trigger idle animations, play engine idle sound, reset gears to neutral, etc. All STOP-specific behavior lives here!

Implementation Step 5: Start State

πŸ“ File Structure Note

Create a new file: Assets/Scripts/Patterns/State/BikeStartState.cs
This is a concrete state that implements the START/MOVE behavior.

using UnityEngine; public class BikeStartState : MonoBehaviour, IBikeState { private BikeController _bikeController; public void Handle( BikeController bikeController) { if (!_bikeController) _bikeController = bikeController; // START: set to max speed _bikeController.CurrentSpeed = _bikeController.maxSpeed; } void Update() { // Move forward each frame if (_bikeController) { if (_bikeController.CurrentSpeed > 0) { _bikeController.transform.Translate( Vector3.forward * (_bikeController.CurrentSpeed * Time.deltaTime)); } } } }

How This Works

BikeStartState: The START state makes the bike move forward at max speed. Two key methods here!

Handle(): Sets the bike's speed to maximum when entering START state. This is the state transition behavior.

Update(): Runs every frame while in START state! Moves the bike forward continuously. This is why the bike keeps moving - Update() is always running for this MonoBehaviour.

State Power: Each state controls its own Update() loop! STOP state doesn't move, START state moves forward, TURN state handles lateral movement.

Implementation Step 6: Turn State

πŸ“ File Structure Note

Create a new file: Assets/Scripts/Patterns/State/BikeTurnState.cs
This is a concrete state that implements the TURN behavior.

using UnityEngine; public class BikeTurnState : MonoBehaviour, IBikeState { private Vector3 _turnDirection; private BikeController _bikeController; public void Handle( BikeController bikeController) { if (!_bikeController) _bikeController = bikeController; // Set direction (Left=-1, Right=1) _turnDirection.x = (float) _bikeController.CurrentTurnDirection; // Only turn if moving if (_bikeController.CurrentSpeed > 0) { transform.Translate(_turnDirection * _bikeController.turnDistance); } } }
πŸ“ Also Create: Direction.cs (enum file)
// Direction enum public enum Direction { Left = -1, Right = 1 }

How This Works

BikeTurnState: Handles lateral movement (left/right). More complex than STOP or START!

Direction Enum: Left = -1, Right = 1. Cast to float for Vector3.x. Negative moves left, positive moves right.

Safety Check: Only turn if CurrentSpeed > 0. Can't turn while stopped - just like real bikes!

Translate(): Moves the transform laterally by turnDistance. Instant lane change!

Design Pattern: TURN state knows turning rules. If we wanted gradual turning, we'd update the logic here only - nowhere else!

Test Client Script

πŸ“ File Structure Note - TESTING CODE

Create a new file: Assets/Scripts/Testing/ClientState.cs
This is a temporary test script that creates GUI buttons to manually trigger state transitions.
⚠️ This is for testing only - you can delete it once you've verified the State pattern works!

using UnityEngine; public class ClientState : MonoBehaviour { private BikeController _bikeController; void Start() { // Find BikeController in scene _bikeController = FindFirstObjectByType<BikeController>(); } void OnGUI() { // GUI buttons if (GUILayout.Button("Start Bike")) _bikeController.StartBike(); if (GUILayout.Button("Turn Left")) _bikeController.Turn(Direction.Left); if (GUILayout.Button("Turn Right")) _bikeController.Turn(Direction.Right); if (GUILayout.Button("Stop Bike")) _bikeController.StopBike(); } }

How This Works

ClientState: A simple test script that creates GUI buttons to manually trigger state transitions.

FindFirstObjectByType<T>(): Unity 6 method that searches the entire scene for an object of type T. Returns the first one it finds.

Unity 6 Update: This replaces the old FindObjectOfType(typeof(BikeController)) pattern.

The new generic version is cleaner - no casting needed! The type is specified in angle brackets <BikeController>.

C# Generics: The <BikeController> tells the method exactly what type to find and return. Type-safe and no casting required!

OnGUI(): Unity's old GUI system. Runs every frame to draw buttons. Clicking buttons calls BikeController methods.

⚠️ Common Mistake: Must be OnGUI() with all caps "GUI" - not OnGui() or onGUI(). Unity won't call your method if the spelling/capitalization is wrong, and you won't get an error message - it just silently doesn't work! No buttons will appear.
πŸ’‘ Alternative: When you have multiple test scripts with overlapping GUI buttons, consider using TestPanel.cs to combine all test controls into one draggable window. See the Event Bus lecture for the unified TestPanel implementation.

Testing the State Pattern

Test Setup Steps

  1. Create new Unity scene
  2. Add 3D Cube GameObject (visible to camera)
  3. Attach BikeController script to cube
  4. Attach ClientState test script to cube (or any GameObject)
  5. Play and use GUI buttons to test states
Visual Feedback: Watch the cube move forward (START), shift sideways (TURN), and stop (STOP) based on button clicks!

Hands-On Practice πŸ’»

40-Minute Implementation Challenge

Implement the State Pattern for the bike:

  1. Create IBikeState interface
  2. Create BikeStateContext class
  3. Create BikeController MonoBehaviour
  4. Implement BikeStopState, BikeStartState, BikeTurnState
  5. Create Direction enum
  6. Create ClientState test script
  7. Test in Unity with GUI buttons

Gaming History Moment πŸ•ΉοΈ

Sega vs Nintendo: The Console Wars (1989-1995)

In 1991, Sega needed a mascot to rival Mario. They created Sonic the Hedgehog, designed around one core concept: speed. Sonic wasn't just fast - he had distinct states that emphasized velocity and attitude. Unlike Mario's simple run and jump, Sonic had idle tapping his foot impatiently, revving up in a spin dash, blazing through loops at top speed, and tumbling when hit.

Each state had unique animations, physics, and behaviors. The transition from standing still to spin dash to full-speed running created a sense of momentum and power. Sega's "Genesis does what Nintendon't" campaign emphasized Sonic's speed states - this wasn't your father's platformer!

Connection to State Pattern

Sonic's character controller is a perfect example of the State Pattern in action! Idle, Spin Dash, Running, Jump, Roll, Hit - each state has specific physics, animations, and allowed transitions. Just like our bike states (STOP, START, TURN), Sonic's states encapsulate behaviors: you can't spin dash while running, you can't run while in the air. The State Pattern enables complex character behavior with clean, manageable code!

Learn More: Console Wars Documentary (2020) | Watch on Paramount+ | IMDB Page

Benefits of the State Pattern

βœ… Encapsulation

State-specific behaviors are isolated in their own classes. No giant switch statements!

βœ… Maintainability

Easy to add new states without modifying existing code. Open/Closed Principle!

βœ… Clarity

Each state class has a single responsibility. Clear, focused code!

βœ… Flexibility

States can be assigned dynamically at runtime. Powerful composition!

Drawbacks & Limitations

⚠️ Limitation 1: Animation Blending

The State pattern doesn't provide built-in animation blending. Transitioning from idle β†’ walk β†’ run requires smooth visual blending, which needs extra code.

⚠️ Limitation 2: Complex Transitions

Defining relationships and conditions between states (state diagrams) requires significant boilerplate code. Example: "Can only transition to Run from Walk, not from Idle."

⚠️ Limitation 3: Many Classes

Complex characters with many states = many classes to manage.

Unity's Built-In Solution

Unity Animation System

Unity's animation system IS a Finite State Machine (FSM) with:

  • βœ“ Visual State Editor - Drag and drop states
  • βœ“ Animation Blending - Smooth transitions built-in
  • βœ“ Transition Conditions - Set up rules visually
  • βœ“ State Behaviors - Attach scripts to states
  • βœ“ Parameters & Triggers - Control flow from code

Best of Both Worlds: Use State pattern concepts with Unity's visual tools!

Unity Animator Controller

Visual State Machine Editor

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚   Idle   β”‚ ────────────┐
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚ speed > 0.1
         β–²                   β–Ό
         β”‚              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚ speed < 0.1  β”‚   Walk   β”‚
         β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                   β”‚
         β”‚                   β”‚ speed > 5.0
         β”‚                   β–Ό
         β”‚              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         └──────────────│   Run    β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                

Rectangles = Animation States
Arrows = Transitions with conditions

State Pattern vs Unity Animator

Use State Pattern For:

  • Non-animated state machines
  • Game logic states (menu systems)
  • AI decision states
  • Abstract state systems
  • Learning and understanding FSM

Use Unity Animator For:

  • Character animations
  • Complex animation blending
  • Visual state transitions
  • Mechanical animations (doors, etc.)
  • Production-ready animation

For Blade Racer: We'll use State Pattern for game logic and Unity Animator for bike/character animations!

Alternative & Related Patterns

🌳 Behavior Trees

For complex AI with dynamic decision-making. Tree of actions evaluated each frame.

Use for: NPC AI, enemy behaviors

πŸ“‹ Blackboard Pattern

Shared knowledge repository for AI agents. Works well with Behavior Trees.

Use for: AI data sharing

βš™οΈ FSM (Pure)

More focused on transitions and input triggers than State Pattern. Automaton-like.

Use for: Game state machines

πŸ’Ύ Memento Pattern

Like State Pattern but with undo/rollback capability. Saves state history.

Use for: Undo systems, time rewind

Homework Assignment πŸ“

Assignment: State Pattern Implementation

Due: Next class
Submission: Unity project + video to D2L

Part 1: Code Implementation (60 points)

  1. Implement complete State Pattern (all classes from today)
  2. Add a 4th state: CrashState
    • Logs "Bike crashed!"
    • Sets speed to zero
    • Disables further state transitions
  3. Add keyboard controls in ClientState:
    • Space = Start, S = Stop
    • Left Arrow = Turn Left, Right Arrow = Turn Right
    • C = Crash

Unity Animator Controller 🎬

What is Unity Animator?

Unity's Animator Controller is a visual tool for managing state machines and animations. It provides a node-based interface for creating FSMs without writing all the state transition code manually.

βœ… Advantages

  • Visual state machine editor
  • Built-in animation blending
  • Easy to modify transitions
  • Inspector-friendly parameters

⚠️ Limitations

  • Less flexible than code
  • Designed primarily for animation
  • Can become complex quickly
  • Harder to debug than State Pattern
For Part 2: We'll use Animator alongside our State Pattern implementation to compare both approaches.

Step 1: Create Animator Controller

Creating Your First Animator Controller

  1. In Project window: Right-click in Assets folder
  2. Select Create β†’ Animator Controller
  3. Name it BikeAnimatorController
  4. Double-click to open Animator window
Create Animator Controller menu

Step 2: Add States to Animator

Creating States in the Animator Window

  1. In Animator window: Right-click on grid
  2. Select Create State β†’ Empty
  3. Rename to Idle (this will be your default state)
  4. Repeat to create Moving and Crashed states
Animator window with three states
Note: The Entry state automatically connects to your first state. This is the starting state when the Animator begins.

Step 3: Add Parameters

Creating Animator Parameters

Parameters are variables that control state transitions. We'll use Triggers which are one-time events that fire transitions.

  1. In Animator window: Find Parameters tab (top-left)
  2. Click the + button
  3. Select Trigger type
  4. Create these triggers:
    • StartMoving
    • StopMoving
    • Crash
Parameters panel with triggers

Step 4: Create Transitions

Connecting States with Transitions

Creating a Transition:

  1. Right-click on Idle state
  2. Select Make Transition
  3. Click on Moving state to connect them
  4. Click the transition arrow to select it
  5. In Inspector: Click + under Conditions
  6. Set condition to StartMoving trigger
Repeat for all transitions:
  • Idle β†’ Moving (condition: StartMoving)
  • Moving β†’ Idle (condition: StopMoving)
  • Moving β†’ Crashed (condition: Crash)
  • Idle β†’ Crashed (condition: Crash)
Animator with transitions and conditions

Step 5: Attach to GameObject

Adding Animator to Your Bike

  1. Select your Bike GameObject in Hierarchy
  2. In Inspector: Click Add Component
  3. Search for and add Animator component
  4. Drag BikeAnimatorController into the Controller slot
Animator component in Inspector
⚠️ Common Mistake: Make sure you add the Animator component, NOT the Animation component. They are different!

Step 6: Trigger States from Code

πŸ“ File Structure Note

Update existing file: Assets/Scripts/Controllers/BikeController.cs
Add Animator integration to connect the State Pattern with Unity's Animator Controller.
Highlighted lines show the code to add.

public class BikeController : MonoBehaviour { private IBikeState _startState, _stopState, _turnState; private BikeStateContext _bikeStateContext; private Animator _animator; void Start() { _bikeStateContext = new BikeStateContext(this); _startState = gameObject.AddComponent<BikeStartState>(); _stopState = gameObject.AddComponent<BikeStopState>(); _turnState = gameObject.AddComponent<BikeTurnState>(); _animator = GetComponent<Animator>(); _bikeStateContext.Transition(_stopState); } public void StartBike() { _bikeStateContext.Transition(_startState); _animator.SetTrigger("StartMoving"); } public void StopBike() { _bikeStateContext.Transition(_stopState); _animator.SetTrigger("StopMoving"); } }
Key Method: animator.SetTrigger("TriggerName") fires the trigger and causes the Animator to transition if conditions are met.

Step 7: Add Visual Feedback (Optional)

πŸ“ File Structure Note - OPTIONAL

Create new file: Assets/Scripts/Behaviours/IdleStateBehaviour.cs
This is optional visual feedback code for testing. Since we don't have animations yet,
StateMachineBehaviour lets us change colors when states activate.

using UnityEngine; public class IdleStateBehaviour : StateMachineBehaviour { // Called when entering the Idle state public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // Change bike color to green when Idle var renderer = animator.GetComponent<Renderer>(); renderer.material.color = Color.green; } }
⚠️ SPELLING MATTERS! Unity uses British English spelling: StateMachineBehaviour (with "u"). The American spelling StateMachineBehavior (without "u") will NOT work and cause errors!
What is StateMachineBehaviour? This is a Unity built-in class that lets you run code when entering, exiting, or updating animator states.

To Add to a State:

  1. Click on a state in Animator window
  2. In Inspector: Click Add Behaviour
  3. Create script (e.g., IdleStateBehaviour)
  4. Repeat for Moving (blue) and Crashed (red) states

Homework Assignment (Continued)

Part 2: Unity Animator Exploration (40 points)

  1. Create a simple Animator Controller with 3 states:
    • Idle, Moving, Crashed
  2. Set up transitions between states with parameters
  3. Attach to your bike GameObject
  4. Add color changes or simple animations to visualize states
  5. Trigger animator from BikeController code

Video Requirements:

  • 2-5 minutes showing both implementations
  • Demonstrate all states transitioning
  • Show Unity Animator window with your FSM
  • Brief narration explaining your implementation

Grading Rubric (100 points)

Point Breakdown

25 pts: State Pattern correctly implemented (interface, context, concrete states)
25 pts: BikeController + Unity Animator Controller with proper state transitions
15 pts: CrashState implemented with all requirements
15 pts: Keyboard controls work correctly and trigger state changes
10 pts: All states function properly with correct state management
10 pts: Video demonstrates all functionality clearly

Additional Resources

πŸ“š Further Reading

Office Hours: Need help with Unity Animator? Come see me!

Questions & Discussion πŸ’¬

Open Floor

  • State Pattern structure and implementation?
  • When to use State Pattern vs Unity Animator?
  • How to add the CrashState?
  • Unity Animator setup questions?
  • Homework clarifications?

State Pattern Mastered! 🎭

Today's Achievements:

Homework Due Next Class:

State Pattern + CrashState + Unity Animator

Video submission to D2L

Next: Event Bus Pattern for game-wide communication! 🎯