State Pattern - Managing Character States

Managing Character States

The State Pattern 🎭

CSCI 3213 - Game Programming

Spring '26 - Week 3, Class 1

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.

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

Implementation Step 1: Interface

namespace Chapter.State { /// The state interface that all concrete states implement public interface IBikeState { // Handle the state behavior // Takes BikeController to access properties void Handle(BikeController controller); } }
Design Note: We pass BikeController to Handle() so state classes can access bike properties (speed, direction, etc.). This is a Unity-adapted approach.

Implementation Step 2: Context

namespace Chapter.State { public class BikeStateContext { // Current state - publicly accessible public IBikeState CurrentState { get; set; } // Reference to the bike controller private readonly BikeController _bikeController; public BikeStateContext(BikeController bikeController) { _bikeController = bikeController; } // Transition to current state public void Transition() { CurrentState.Handle(_bikeController); } // Transition to a new state public void Transition(IBikeState state) { CurrentState = state; CurrentState.Handle(_bikeController); } } }

Two Transition Methods: One cycles current state, one sets and transitions to new state.

Implementation Step 3: Controller

using UnityEngine; namespace Chapter.State { public class BikeController : MonoBehaviour { // Public properties for 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() { // Initialize context _bikeStateContext = new BikeStateContext(this); // Initialize states as components _startState = gameObject.AddComponent<BikeStartState>(); _stopState = gameObject.AddComponent<BikeStopState>(); _turnState = gameObject.AddComponent<BikeTurnState>(); // Set initial state _bikeStateContext.Transition(_stopState); } // Public methods to change states public void StartBike() => _bikeStateContext.Transition(_startState); public void StopBike() => _bikeStateContext.Transition(_stopState); public void Turn(Direction direction) { CurrentTurnDirection = direction; _bikeStateContext.Transition(_turnState); } } }

Implementation Step 4: Stop State

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

Stop State Behavior

Simply sets the bike's speed to zero. In a full implementation, this would also trigger idle animations and reset gears.

Implementation Step 5: Start State

using UnityEngine; namespace Chapter.State { public class BikeStartState : MonoBehaviour, IBikeState { private BikeController _bikeController; public void Handle(BikeController bikeController) { if (!_bikeController) _bikeController = bikeController; // START behavior: set to max speed _bikeController.CurrentSpeed = _bikeController.maxSpeed; } void Update() { // While in START state, move forward each frame if (_bikeController) { if (_bikeController.CurrentSpeed > 0) { _bikeController.transform.Translate( Vector3.forward * (_bikeController.CurrentSpeed * Time.deltaTime)); } } } } }
Note: Update() runs continuously while this component is active, moving the bike forward!

Implementation Step 6: Turn State

using UnityEngine; namespace Chapter.State { public class BikeTurnState : MonoBehaviour, IBikeState { private Vector3 _turnDirection; private BikeController _bikeController; public void Handle(BikeController bikeController) { if (!_bikeController) _bikeController = bikeController; // Set turn direction (Left = -1, Right = 1) _turnDirection.x = (float)_bikeController.CurrentTurnDirection; // Only turn if moving if (_bikeController.CurrentSpeed > 0) { transform.Translate(_turnDirection * _bikeController.turnDistance); } } } }
// Direction enum referenced by BikeController public enum Direction { Left = -1, Right = 1 }

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 test client script (next slide)
  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!

Test Client Script

using UnityEngine; namespace Chapter.State { public class ClientState : MonoBehaviour { private BikeController _bikeController; void Start() { // Find the BikeController in the scene _bikeController = (BikeController) FindObjectOfType(typeof(BikeController)); } void OnGUI() { // Create GUI buttons to control the bike 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(); } } }

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

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

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

20 pts: State Pattern correctly implemented (interface, context, states)
15 pts: BikeController properly manages state transitions
15 pts: CrashState implemented with all requirements
10 pts: Keyboard controls work correctly
25 pts: Unity Animator Controller created with transitions
15 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! 🎯