The Grand Finale: Orchestrating Complex Motion with Multi-Context FSMs

The Grand Finale: Orchestrating Complex Motion with Multi-Context FSMs

Leader posted 4 min read

We've successfully established a reusable architectural pattern by isolating the data (Context) from the logic flow (Finite State Machine) for the three primitive motions: Rotation, Scaling, and Translation. We created three distinct, independent blueprints—"RotationFSM," "ScalarFSM," and "TranslationFSM"—each driving separate objects on various axes.

Now, for the grand finale: we will demonstrate the true power of this decoupled architecture by applying all three FSM blueprints simultaneously to the same three objects, achieving a perfectly synchronized, multi-dimensional motion effect.

This isn't about creating a new FSM; it's about proving the flexibility and reusability of the existing ones. We will show that one object can be driven by multiple, independently managed FSM contexts, eliminating the need for a monolithic, complex state machine.


The Power of Decoupled Contexts

The core principle remains the same: the FSM definition is the reusable logic (the how), and the Context is the unique data (the what).

In our previous demos, we created one Context per object. In the Combined Motion Demo, we create three Contexts per object.

Object Rotation Demo Scalar Demo Translation Demo Combined Demo
X-axis Cube RotationContext ScaleContext TranslationContext RotationFSM, ScalarFSM, TranslationFSM
Y-axis Cube RotationContext ScaleContext TranslationContext RotationFSM, ScalarFSM, TranslationFSM
Z-axis Cube RotationContext ScaleContext TranslationContext RotationFSM, ScalarFSM, TranslationFSM

The FSM framework handles each Context instance completely independently. When the Unity Update() loop runs, it executes the update for all nine individual FSM instances (three contexts * three objects), resulting in the compound motion.


The Entry Point: SimpleRotationScalarTranslationDemo.cs

The SimpleRotationScalarTranslationDemo.cs file is the orchestrator, instantiating the nine required Contexts in its main FSM's OnEnterExecuting method.

Instantiation Logic: Three-in-One

The code combines the instantiation logic from all three previous demos. For the XaxisCube, we instantiate a ScaleContext, a TranslationContext, and a RotationContext, all referencing the same demo.XaxisCube Transform.

private void OnEnterExecuting(IStateContext context)
{
    if (context is SimpleRotationScalarTranslationDemo demo)
    {
        // === X-AXIS CUBE ===
        // 1. Scale FSM (Uses ScaleContext/ScalarFSM)
        ScaleContext scX = new ScaleContext(demo.XaxisCube, new Vector3(1, 0, 0), 0.5f, 3f, 0.5f);
        // 2. Translation FSM (Uses TranslationContext/TranslationFSM)
        TranslationContext tcX = new TranslationContext(demo.XaxisCube, new Vector3(1, 0, 0), 1f, 2f, -2f);
        // 3. Rotation FSM (Uses RotationContext/RotationFSM)
        RotationContext rcX = new RotationContext(demo.XaxisCube, new Vector3(1, 0, 0), 90f, 45f, -45f);
       
        // === Y-AXIS CUBE ===
        // ... (Similar instantiation for Y-axis cube, using (0, 1, 0) for the axis)
        ScaleContext scY = new ScaleContext(demo.YaxisCube, new Vector3(0, 1, 0), 0.5f, 3f, 0.5f);
        TranslationContext tcY = new TranslationContext(demo.YaxisCube, new Vector3(0, 1, 0), 1f, 2f, -2f);
        RotationContext rcY = new RotationContext(demo.YaxisCube, new Vector3(0, 1, 0), 90f, 45f, -45f);
       
        // === Z-AXIS CUBE (Note: Scale is multi-axis for visual flair) ===
        // ... (Similar instantiation for Z-axis cube, using various axes)
        ScaleContext scZ = new ScaleContext(demo.ZaxisCube, new Vector3(1, 1, 0), 0.5f, 3f, 0.5f);
        TranslationContext tcZ = new TranslationContext(demo.ZaxisCube, new Vector3(0, 0, 1), 1f, 2f, -2f);
        RotationContext rcZ = new RotationContext(demo.ZaxisCube, new Vector3(0, 0, 1), 90f, 45f, -45f);
    }
}

The Decoupled FSMs in Action

Because each Context is an independent data container, the FSM framework executes them separately, resulting in simultaneous, non-interfering motion:

  • The RotationContext drives the TransformHandle.localRotation.
  • The ScaleContext drives the TransformHandle.localScale.
  • The TranslationContext drives the TransformHandle.localPosition.

Each FSM instance has its own independent state and transitions, yet they all operate on the same object's Transform. The result is a fascinating display: the Z-axis Cube, for instance, oscillates along the Z-axis (Translation), pulses in size along the X and Y axes (Scaling), and swings around the Z-axis (Rotation).


Conclusion: True Architectural Victory

This Combined Motion Demo is the ultimate proof of the FSM Context Pattern's power:

  1. Separation of Concerns: We fully separated the primitive operations. Modifying the boundary check for rotation, for instance, has zero impact on the translation or scaling logic.
  2. High Reusability: We did not write a single new state machine definition for this complex demo. We simply reused the "RotationFSM," "ScalarFSM," and "TranslationFSM" blueprints.
  3. Scalable Complexity: An object's behavior is now a composition of independent FSM-driven movements. If we need to add a "Color Modulation FSM," we simply instantiate a fourth context for each object.

This decoupled architecture provides the foundation for robust, maintainable, and highly extensible game systems. You've escaped Update() spaghetti and unlocked the ability to compose complex behaviors from simple, reusable, and independent parts.


See it in action on YouTube (Don't forget to like and subscribe!):

https://youtu.be/1lKBINkTtYM

Support the Vision and See the Code!

If this pattern has helped clean up your Update() loop, please consider supporting our development! Your support ensures we can continue to provide advanced, architectural solutions for cleaner game development.

Resources & Code:

The FSM Package (Unity Asset Store):
https://assetstore.unity.com/packages/slug/332450

NuGet Package (Non-Unity Core):
https://www.nuget.org/packages/TheSingularityWorkshop.FSM_API

GitHub Repository:
https://github.com/TrentBest/FSM_API

Support Our Work:

Patreon Page:
https://www.patreon.com/c/TheSingularityWorkshop

Support Us (PayPal Donation):
https://www.paypal.com/donate/?hosted_button_id=3Z7263LCQMV9J

We'd love to hear your thoughts! Please Like this post, Love the code, and Share your feedback in the comments.

The Singularity Workshop Logo, a digital Eye of energy within a circuit digital universe

If you read this far, tweet to the author to show them you care. Tweet a Thanks

1 Comment

1 vote
0

More Posts

Completing the Motion Trilogy: The Reusable TranslationFSM

The Singularity Workshop - Oct 14

Applying the FSM Context Pattern to Scaling: The Reusable ScalarFSM

The Singularity Workshop - Oct 14

Building a Reusable State Machine for Oscillating Rotation in Unity

The Singularity Workshop - Oct 14

The FSM Agent Architecture: Scaling NavMesh Agents with Decoupled Logic

The Singularity Workshop - Oct 15

When Unity Glitches, You Build Your Own Loop: The Four-Line App Core

The Singularity Workshop - Oct 17
chevron_left