Every developer has a story about an IDE or engine glitch that made them momentarily question their career choices. For me, that moment arrived late one evening, tracing a bug in our FSM-driven agents. Unity's Inspector decided to go on strike, showing empty fields without labels—the digital ghosts of components past.
The simple fix? Close Unity. Reopen. Wait 10 minutes.
It was late. I was done waiting.
Instead, in an exhausted fit of annoyance and clarity, I opened a fresh C# console, installed The Singularity Workshop's FSM API, and let my fingers dance. The next morning, groggy and foggy, I realized I had accidentally conceived an entire, engine-agnostic application core.
Laugh at the simplicity, then realize this genuinely works! This is the entire executable heart of a Windows Desktop application:
public class Program
{
public static void Main(string[] args)
{
// 1. Instantiate the Context: Our Platform-Specific "Drone as I like to think of it"
var appContext = new AppWindowsDesktopContextFSM(args);
// 2. Create the live Execution FSM bound to that Context
FSM_API.Create.CreateInstance("ExecutionFSM", appContext, "Update");
// 3. The Self-Terminating Loop
do
{
// Tick the FSM: Advance one logical step
FSM_API.Interaction.Update("Update");
} while (appContext.IsValid); // Control flow determined by the Context's vital sign
}
}
That's it. This four-line do-while block is less boilerplate than setting up a complex, multi-threaded worker class, yet it provides unparalleled decoupling.
The Conceptual Leap: Context-Driven Execution
The conceptual breakthrough is that the traditional while (IsRunning) loop, where control is external to the core logic, is entirely replaced by a check against the IStateContext.
The Context as the Application's Heartbeat
The loop's survival depends entirely on appContext.IsValid. This property is required by the IStateContext interface.
- If
IsValid is true, the loop runs, calling FSM_API.Interaction.Update() to execute the current state and check for transitions.
- If
IsValid returns false, the loop breaks, and the application cleanly exits. The FSM API even automatically cleans up the associated FSMHandle instance.
The application's "ExecutionFSM" is defined to contain states like Initializing, Running, and ShuttingDown. When a transition leads to the ShuttingDown state, the OnEnter action simply calls a method on the AppContext (our "Drone") that sets an internal flag, making IsValid flip to false.
The FSM dictates when to die; the Context executes how.
Unparalleled Platform Decoupling
This pattern achieves the holy grail of platform-agnostic logic:
- The FSM Definition (
"ExecutionFSM") is Pure Logic: It knows nothing about Windows, Unity, or Android. It only knows about states (e.g., ProcessingInput, SavingData) and transitions (e.g., OnInputProcessed → ToState). This definition can be used anywhere.
- The Context (
AppWindowsDesktopContextFSM) is Pure Platform Abstraction: This class is where all the OS-specific heavy lifting lives. A state's OnEnter action might call ((AppWindowsDesktopContextFSM)ctx).InitializeWindow() or ((AppConsoleContext)ctx).ParseArgs().
The FSM definition remains constant, knowing only that the action is ctx.DoThing(). The behavior behind DoThing() is entirely specific to the AppWindowsDesktopContextFSM running on the client machine. This means the same "ExecutionFSM" definition can be shared across our Console, Windows Desktop, and (ironically) future Unity integrations, providing the necessary FSM behaviors without ever compromising the core logic to platform constraints.
In the end, closing Unity would have taken 10 minutes. Building this foundational piece of software architecture took most of the night. But now, we have an application core that is robust, modular, and immune to inspector glitches. WTF indeed!
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.
