Summary
This article introduces the input processing mechanism in Mover 2.0, what the input command context is, how to pass data to the Mover system through the context, and how to customize the InputProducer to manipulate the context.
Introduction
UnlikeCharacterMovementComponent (inherited from PawnMovementComponent), you only need to callAddInputVector to drive the character's movement.
In Mover, the handling of movement input becomes more flexible, but at the cost of user code becoming more low-level and complex.
Input Command Context
In Mover, the main way to pass user input to the Mover system is through InputCmdContext (input command context), hereinafter referred to as Context.
You can simply understand Context as aMoverData container, which can be manipulated through Blueprint/C++ APIs to add, delete, modify, and query the data it contains.
Here, theMoverData refers to: a structure that inherits fromFMoverDataStructBase, therefore, you must add a new MoverData type through C++.
Context can accommodatemultiple types of input parameter structures.
What is InputProducer?
Any UObject that implementsMoverInputProducerInterface can be regarded as anInputProducer.
MoverComponent has a built-in ProduceInput function that is called every frame.
1// Get latest local input prior to simulation step. Called by backend system on owner's instance (autonomous or authority).2 void ProduceInput(const int32 DeltaTimeMS, FMoverInputCmdContext* Cmd);
It also holds a reference to an object that implementsMoverInputProducerInterface. The default implementation of ProduceInput above is completed through the InputProducer object below, allowing users to decouple input logic from the Mover system.
1 /** Optional object for producing input cmds. Typically set at BeginPlay time. If not specified, defaulted input will be used. */2 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Mover, meta = (MustImplement = "/Script/Mover.MoverInputProducerInterface"))3 TObjectPtr<UObject> InputProducer;
By default, MoverComponent will try to query objects that implement this interface from the owning Actor or its component tree at BeginPlay.
Since this object is public and can be read and written in Blueprints, you can assign any object that implementsMoverInputProducerInterfaceto this member at any time.
Note
Although the code comments claim that this object is optional, much of the engine code in the current Mover plugin does not treat it as '
optional'. So make sure you always provide an InputProducer.
Users only need to care about how to pass input command control parameters to InputCmdContext through the ProduceInput function.
Implementing the MoverInputProducerInterface
Both Blueprints and C++ can implementMoverInputProducerInterface,
1class IMoverInputProducerInterface : public IInterface2{3 GENERATED_BODY()45public:6 /** Contributes additions to the input cmd for this simulation frame. Typically this is translating accumulated user input (or AI state) into parameters that affect movement. */7 UFUNCTION(BlueprintNativeEvent)8 void ProduceInput(int32 SimTimeMs, FMoverInputCmdContext& InputCmdResult);9};
Note
ProduceInput will execute every frame, but you do not necessarily need to add data to the Context every frame.
Official Example
In the MoverExample plugin,MoverExamplesCharacter this Class implementsMoverInputProducerInterface, and demonstrates how to bind InputAction, cache the value of the Action, and in OnProduceInput, based on configuration, the character's current state, and the value of InputAction, constructs inputs forCharacterDefaultInputs. You can refer to it for basic usage, but please refer to later sections for how to design your InputProducer.
Designing Your InputProducer
I recommend implementing this interface through a Component rather than through an Actor. Component-based development can enhance the portability of the code.
Using separate components, implement the control logic of the business through inheritance of components, thus achieving different control strategies.
1UCLASS(ClassGroup=GMS, BlueprintType, Blueprintable, meta=(BlueprintSpawnableComponent), DisplayName="GMS Movement System Component(Mover)")2class GAME_API UMoverControlSystem : public UActorComponent, public IMoverInputProducerInterface3{4 GENERATED_BODY()5public:6 virtual void ProduceInput_Implementation(int32 SimTimeMs, FMoverInputCmdContext& InputCmdResult) override;7protected:8 // Override this function in native class to author input for the next simulation frame. Consider also calling Super method.9 UFUNCTION(BlueprintNativeEvent, Category="GMS|MovementSystem")10 FMoverInputCmdContext OnProduceInput(float DeltaMs, FMoverInputCmdContext InputCmd);11}
1void UMoverControlSystem::ProduceInput_Implementation(int32 SimTimeMs, FMoverInputCmdContext& InputCmdResult)2{3 InputCmdResult = OnProduceInput(static_cast<float>(SimTimeMs), InputCmdResult);4}56FMoverInputCmdContext UMoverControlSystem::OnProduceInput_Implementation(float DeltaMs, FMoverInputCmdContext InputCmdResult)7{8 // Your game control logic, this is where you implements your control system, feeding inputs to context.9 // Your game control logic, implement your control system here, passing inputs to context.10 FCharacterDefaultInputs& CharacterInputs = InputCmdResult.InputCollection.FindOrAddMutableDataByType<FCharacterDefaultInputs>();1112 // Constructs inputs depends on your game design.13 // Construct appropriate default input parameters based on your game design.14 CharacterInputs.SetMoveInput(EMoveInputType::DirectionalIntent,RawMoveInputValueFromInputAction);1516 // Other kinds of inputs (abilities input, dash,double jump etc...)17 // Other inputs, ability inputs, such as dash, double jump, etc.18 FYourCustomOtherInputs& OtherInputs = InputCmdResult.InputCollection.FindOrAddMutableDataByType<FYourCustomOtherInputs>();19 OtherInputs.IsDashPressed = RawDashInputValueFromInputAction;20}21
You can perform logical control through your component derived classes.
Loading Blueprint
Initializing BlueprintUE renderer...
Handle Dash..
In the engine's lower level, theProduceInput on the MoverComponent is called by theNetworkPrediction plugin.
It is a world subsystem that updates with the lifecycle of the world. We will delve deeper into this part in future articles.
