You taught me how to use behavior trees, so I’m glad I can repay the favor. High level overview: UInputComponents hold the action or axis bindings that can be called on a specific actor. APlayerController is the main organizer of player input, it builds the input stack every frame. The input stack is just an array of UInputComponent* that defines the order in which each input component will be processed, based on their priority. The input components that will appear on this stack are (in order of ascending priority): The controlled pawn, Level script actors with input enabled, the controllers input component, and then an array of input components that can be manually added to with APlayerController::PushInputComponent(UInputComponent InputComponent)*. The stack of input components is given to a UPlayerInput subobject of the player controller, and this subobject will organize input and execute the bound delegates. Note that if a binding has not been manually set to not consume input, any input components below it on the stack that also have a binding for that input action/axis will not receive the event (you can set the binding to not consume input by doing InputComponent->BindAction(…).bConsumeInput = false; when you set up the binds. This might be useful if say, you want your pawn to know about shooting input as well as your weapon actor).
The way you will probably want to set it up is with the weapon right at the bottom of the stack, after the pawn. To do this you’ll need a custom player controller to override void APlayerController::BuildInputStack(TArray<UInputComponent>& InputStack)* and push your weapons input component onto the stack first, and only then call the Super::BuildInputStack. By default, your weapon will not have an input component, so you’ll have to create one when your weapon is equipped and wants to start accepting input. You shouldn’t use AActor::EnableInput(APlayerController PlayerController)* to create your input component because that will also push the component on the controllers manual stack, so you should use your own enable input function that only copies how AActor creates the component and then does the blueprint bindings.
Normally you would use SetupPlayerInputComponent() on your pawn to actually bind to functions, but your weapon obviously doesn’t have that function. However, it should be as simple as calling InputComponent->BindAction(…) in the Equipped() function of your weapon.
//this function is called every frame and determines what input components will receive input events
void AMyController::BuildInputStack(TArray<UInputComponent*>& InputStack){
AMyPawn* ControlledPawn = Cast<AMyPawn>(GetPawnOrSpectator());
if (ControlledPawn){
//get the current weapon that we want to send input to
AMyWeapon *EquippedWeapon = ControlledPawn->GetCurrentWeapon();
if (EquippedWeapon->InputComponent)
//if it has an input component then push it to the bottom of the stack, before everything else
InputStack.Push(EquippedWeapon->InputComponent);
}
//now put all the other input components on top
Super::BuildInputStack(InputStack);
}
void AMyWeapon::OnEquipped(){
//copied from AActor::EnableInput, creates input component and binds blueprint actions, but without pushing it onto the controllers manual stack
if (!InputComponent)
{
InputComponent = ConstructObject<UInputComponent>(UInputComponent::StaticClass(), this);
InputComponent->RegisterComponent();
InputComponent->bBlockInput = bBlockInput;
InputComponent->Priority = InputPriority;
UBlueprintGeneratedClass* BGClass = Cast<UBlueprintGeneratedClass>(GetClass());
if (BGClass != NULL)
{
UInputDelegateBinding::BindInputDelegates(BGClass, InputComponent);
}
}
//notice missing PlayerController->PushInputComponent(InputComponent);
//you can do input bindings
InputComponent->BindAction("Fire", IE_Pressed, this, &AMyWeapon::Fire);
//when the weapon is unequipped you can set InputComponent = nullptr; and it will stop receiving input immediately
//I forgot to add that you will have to sort out a mechanism to either re-use the existing component or destroy it otherwise you'll end
//up creating more and more unused input components every time you switch weapons. This is just a general object management thing
//that I didn't think about until later.
}
I haven’t tested this code but it should work.
This code is very simple and inflexible, you might want to make a custom controller that uses a more general approach, like another manual input component array that you apply before everything else in the stack, instead of limiting yourself to subclasses of weapon actors.