InputInput Buffer
The Input Buffer is an animation-based mechanism, used to store a player input while the buffer is open, and trigger it later when it closes.
It is defined by the
InputBufferInterface
. The Input Manager Component is a valid implementation of this interface.You can control the buffer state using the Input Buffer Animation Notify State.
The Input Manager Component allows you to decide if you want to capture the first or the last player input.
The Input System offers an Input Buffer that allows deferring the execution of Input Handlers to a later moment.
This is particularly useful in combat systems where players might press keys during animations that cannot be interrupted, yet the game should still register these inputs to ensure responsiveness.
Input Buffer Design
The buffer is implemented using the Command design pattern: Inputs that cannot be handled immediately are encapsulated in a Command structure, which can be executed later when the buffer is closed.
tip
Command
In OOP terms, the Input Buffer implements the Command pattern. Incoming Input Actions and their values are converted into a command structure that can be executed later on.
The Input Buffer is Animation-Based, meaning it is opened and closed at specific points during an animation, controlled through an Animation Notify State.
Although the Input Manager Component manages the buffer by default, the Input Buffer functionality is defined by the InputBufferInterface
. Any component that implements this interface can be engaged by the animation, provided it is enabled.
You can also disable the Input Manager's buffer if you wish to replace it with your own custom Buffer Component, making the system highly flexible.
tip
Buffer, not Queue
The default Input Buffer provided by the system is a Buffer, not a Queue. This means only one command will be executed when the buffer closes, rather than processing all commands in the order they were received.
Using the Input Buffer
To buffer actions, follow these steps:
Enable the
Can Be Buffered
property on any Input Handlers you wish to add to the Input Buffer.Add the Notify State to an animation that supports buffering inputs.
Enabling Input Handlers for Buffering
To allow an Input Handler to be buffered, enable its Can Be Buffered
property when registering the Input Handler to a UNinjaInputSetupDataAsset
.
tip
You are buffering Input Actions
Although you mark Input Handlers as " buffered ", conceptually, it is the Input Action that gets buffered by the Input Manager Component. This means the Input Manager Component will collect all buffer-able handlers triggered by an Input Action while the buffer is active and invoke them later when the buffer is closed.
Opening and Closing the Input Buffer in Animations
The most straightforward way to open and close the Input Buffer is by using the Input Buffer Animation Notify State.
tip
Scrubbing Animations
When placing the Input Buffer Animation Notify State, hold the shift key to smooth scroll and preview the animation simultaneously.
Once the state Begins, the Input Buffer will open, and the Input Manager Component will stop routing Input Actions to Handlers. Instead, it will store any handlers that would have been triggered, along with their current Input Action Values, based on the buffering policy in place.
Once the state Ends, the Input Buffer will close, and any stored Input Handlers related to a saved Action will be invoked using the previously saved values.
warning
Avoid the first or last frames
Notifies and Notify States may occasionally fail to be invoked when placed on the very first or last frame of an animation. It's recommended to place them a couple of frames before the end.
Externally Opening and Closing the Buffer
While the method above is the primary way to interact with the Buffer, you can open and close the buffer in other ways using the InputBufferInterface
.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "PluginLabsPlayerController.generated.h"
class UNinjaInputManagerComponent;
UCLASS()
class PLUGINLABS_API APluginLabsPlayerController : public APlayerController
{
GENERATED_BODY()
public:
/** A custom way to open and close the Input Buffer. */
UFUNCTION(BlueprintCallable, Category = "Custom Buffer Setup")
void SetBufferState(bool bOpen);
private:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess))
TObjectPtr<UNinjaInputManagerComponent> InputManager;
}
#include "GameFramework/PluginLabsPlayerController.h"
#include "Components/NinjaInputManagerComponent.h"
#include "Interfaces/InputBufferInterface.h"
APluginLabsPlayerController::SetBufferState(bool bOpen)
{
if (bOpen)
{
// Open the Input Buffer in the controller's Input Manager.
IInputBufferInterface::Execute_OpenInputBuffer(InputManagerComponent);
}
else
{
// Close the Input Buffer in the controller's Input Manager.
IInputBufferInterface::Execute_CloseInputBuffer(InputManagerComponent);
}
}
Default Input Buffer Implementation
The UNinjaInputBufferComponent
is the default implementation of the InputBufferInterface
and provides an additional feature: the Buffering Policy.
There are three possible values for this policy:
Last Command: All Input Actions will be processed until the buffer is closed. When that happens, the last Action processed will be the one executed. This is the default mode.
First Command: Once the first valid Input Action is saved, no other Actions will be kept, and this first Action will be the one executed.
Disabled: Disables the Ninja Input Buffer and allows another custom buffer to take over.
tip
Supporting policies in custom buffers
If you want to support the same policies in your custom Input Buffer implementation, you can use the
EInputBufferMode
enumeration.
Creating New Input Buffers
You can create your own Input Buffer by creating an Actor Component that implements the InputBufferInterface
.
If you choose this route, ensure that the Input Manager Component's Buffer is disabled and that your custom component is enabled using the appropriate interface method.
Another option is to create your component as a subclass of the NinjaInputBufferComponent
, which already implements the necessary interface and provides additional utility methods.
This approach allows you to implement only the functions relevant to your scenario, such as BufferInputCommands
, which decides if a command should be buffered.
The FBufferedInputCommand Struct
Commands stored in the buffer are represented by the FBufferedInputCommand
struct.
The main Input Manager Component creates these instances when input handlers are routed to the buffer instead of being processed immediately. The BufferInputCommands
function receives an array of commands because all the commands in that array were triggered by the same Action and Event, so they represent a single player input.