One of the most common design patterns we utilize—so utilized that we often don't even recognize it as a pattern—is that of breaching a limit.
Think about your daily routine:
- Are we within the index limits of this array?
- Has the player’s health dropped to zero?
- Did the mana pool exceed the "Overcharge" value?
While writing a simple if (current > limit) isn't exactly a high-level engineering challenge, the inherent risk of a "fat-finger" typo is real. We’ve all been there: Should this be greater than, or greater than or equal to? In a complex system, sticking the landing every time is harder than it looks. By moving to the FSM_Threshold Pattern, we accept a tiny bit of overhead in exchange for absolute stability. We stop "recalling" the logic and start relying on a state machine that we know works.
High-Speed Implementation: The Factory
The goal of this architecture is to make implementation so easy it feels like a native attribute. The ThresholdFactory hides the math and FSM registration, giving you a one-line setup for any type.
Use Case 1: The Magic Overcharge
Instead of manually checking mana every frame, define a threshold that monitors for a "Magic Burn" state.
// Define it once
var manaMonitor = ThresholdFactory.Create(
"ManaOvercharge",
limit: 100f,
m: ThresholdMode.Max,
r: ResetMode.Automatic,
cb: (t) => CastExplosionEffect()
);
// Just feed the data
manaMonitor.Accumulate(spellCost);
Use Case 2: The Character Health
Whether it's an int or a float, the factory handles the numeric comparison logic for you.
var health = ThresholdFactory.Create("PlayerHealth", 0, ThresholdMode.Min, ResetMode.Manual, OnDeath);
// No more "if (hp <= 0)" scattered in your movement, combat, and fall-damage scripts.
health.Accumulate(-damage);
Deep Dive: Inside the FSM_Threshold
The power of this system lies in the FSM_Threshold<T> class. It doesn't just store a value; it implements IStateContext, allowing it to serve as the "data bag" for the underlying FSM.
The Core Logic
The class manages three key values: _currentValue, _threshold, and _initialValue. Because it is a generic class, it can handle any type that provides an accumulator (to add values) and a comparator (to check the limit).
When you instantiate a threshold, it registers a unique FSM blueprint based on the type name (e.g., Threshold_Single). This blueprint consists of two primary states:
- Monitoring: The default state where we wait for a breach.
- Breached: Entered via the
CheckLimit() transition. Upon entry, it immediately invokes your callback.
The "Manual Reset" Hammer
One of the most elegant parts of the design is how it handles manual resets. In a standard FSM, you might wait for a transition to evaluate as true. To ensure the engine is responsive and stable, we use a "hammer" approach:
public void ManualReset()
{
_currentValue = _initialValue; // Reset the data
Status.TransitionTo("Monitoring"); // Force the state back immediately
}
By calling Status.TransitionTo("Monitoring"), we bypass the standard transition evaluation and force the state machine back to its starting point, ensuring the code that works is always the code that is running.
The Factory: Simplifying Complexity
The ThresholdFactory is what makes this system consumable. It pre-defines the math for common types so the developer doesn't have to.
For example, look at the byte creation:
public static FSM_Threshold<byte> Create(string n, byte lim, ThresholdMode m, ResetMode r, Action<FSM_Threshold<byte>> cb)
=> new FSM_Threshold<byte>(n, 0, lim, m, r, (c, d) => (byte)(c + d), (c, l) => m == ThresholdMode.Max ? c >= l : c <= l, cb);
The factory injects the specific math for a byte (including the necessary cast) and the logic for Max vs Min modes. This means you never have to worry about if you "stuck the landing" on the comparison logic—the factory already did.
By utilizing this pattern, you move away from fragile, scattered if statements and toward a centralized, event-driven architecture that is as easy to use as it is stable.
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
Simple Demos Repository (Run the Stress Test):
https://github.com/TrentBest/SimpleDemos (Clone this repo and run the StressProfiler project to reproduce these numbers.)
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 or what you've built with the API in the comments.
