Rather than simply attempting a state change and giving up if it isn't allowed, it is often desirable to keep trying for a short time. For example, if the player is attacking and they press the attack button again, you probably want the current animation to finish first and then start the next attack in a combo as long as the input didn't occur too long ago. Note that "input" in this case does not only mean "button presses from the player", it can be used for any sort of events that might try to control a state machine (such as AI).
StateMachine<TState>.InputBuffer class allows you to easily implement this sort of buffering:
- Construct a
new StateMachine<TState>.InputBufferby passing in the target state machine.
- Whenever you would normally call
TrySetState(state)on the state machine, call
Buffer(state, timeOut)on the input buffer instead. It will call
TrySetStateand if it fails, then it will store the
stateto try again later.
Updateon the buffer every frame to have it try to enter the buffered state again (if there is one).
The Weapons example demonstrates how to use this system.
This system only buffers a single state at a time. If the player presses the attack button while they are already attacking then presses the block button before the first attack ends, it will only execute the block rather than performing the entire second attack before blocking. This assumes the latest command is the only one that matters, which is often good for things like player input, but might not be best for all situations. If you want to ensure that all commands are executed in order, you could make a similar class (perhaps called
InputSequenceBuffer) which manages a list of states instead of only a single
StateMachine<TState>.StateSelector class provides an easy way to manage a prioritised list of potential states:
- Construct a
new StateMachine<TState>.StateSelectorby passing in the target state machine.
- Add states to the selector by calling its
Addmethod, which requires you to give them each a priority value. If multiple states have the same priority, the most recently added will be treated as a higher priority.
- After you have added all the potential states you want it to choose from, call
ForceSetStateto have it try to enter each of the states using the corresponding
- It attempts to enter each state you have added in order of priority (highest first).
- If it successfully enters a state, the selector is cleared.
If you want to define the priority of a state as part of the state class itself (rather than as a second parameter every time you call the
Add method), you can implement the
IPrioritizable interface. The
IPrioritizable.Priority is usually implemented as an
virtual property in your base state class so that each state can
override it with their own priority.