While our game may be running without any issues in the editor or even in…
Implementing Action Bindings with parameters
In this post we’re going to create various Action Bindings with parameters. Moreover, we’re going to see a way to change the content of our parameters on run time!
This post assumes you’re familiar with UE4 Delegates. In case you don’t quite remember, or know, what or how to use them, I’ve got you covered!
Creating our Inputs
Create any C++ project template and add the following action mappings:
Then, open up the header file of your character and add the following functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
private: /*A simple function which prints its parameter*/ UFUNCTION() void OneParamFunction(int32 Param); /*A simple function which prints its parameters*/ UFUNCTION() void TwoParamsFunction(int32 IntParam, float FloatParam); /*A function that changes the our parameters and replaces a hardcoded action bind*/ void ChangeParameters(); protected: /*The parameter which we will pass into the OneParamFunction*/ UPROPERTY(EditDefaultsOnly, Category=InputsWithParameters) int32 FirstIntParam; /*The int parameter that will get passed into the TwoParamsFunction*/ UPROPERTY(EditDefaultsOnly, Category = InputsWithParameters) int32 SecondIntParam; /*The float parameter that will get passed into the TwoParamsFunction*/ UPROPERTY(EditDefaultsOnly, Category = InputsWithParameters) float FloatParam; |
Then, inside your character’s source file add the following implementation for the OneParamFunction and the TwoParamsFunction:
1 2 3 4 5 6 7 8 9 10 11 |
void AInputsWithParametersCharacter::OneParamFunction(int32 Param) { //printing the given parameter GLog->Log("The parameter you've entered:" + FString::FromInt(Param)); } void AInputsWithParametersCharacter::TwoParamsFunction(int32 IntParam, float FloatParam) { //printing the given parameters GLog->Log("Input with two parameters. First param: " + FString::FromInt(IntParam) + " Second param: " + FString::SanitizeFloat(FloatParam)); } |
Before we go any further let’s take a step back to explain how inputs work in C++ inside UE4.
Your character contains a component named, InputComponent (at least this is happening on the template project !) which is responsible for checking if a valid device for inputs (such as a gamepad / keyboard / mouse etc..) exists. Moreover, that component contains all the available inputs for the specific character.
Currently, there are two types of bindings in UE:
- Axis bindings
- Action bindings
The main difference is that axis bindings execute in each frame, whereas action bindings execute when certain conditions are met (for example the user double clicks, or presses a button).
In this post we’re going to focus solely on action bindings.
In order to declare an action binding you need to:
- Associate the action mapping we’ve specified using the Editor with an input event (ie a button press)
- Declare which function will fire when the input event occurs
Inside the First Person C++ Project template you can locate the following line of code inside the SetupPlayerInputComponent:
1 |
InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump); |
This is the standard way to add an action binding. In this post, we will explore a different way of adding an action binding.
In reality, inside C++ an Action Binding is actually a struct which contains useful information, such as:
- Action Delegate (I will explain in a bit what this is)
- Action Name (which is the actual name of your binding – this must be associated with the action mapping that was specified in your Editor)
- A Key event (which describes the input type. In our case we’re going to use the IE_Pressed key event which describes a button tap)
The Action Delegate is essentially a handler, which points to a function that will execute when we have a valid input based on the key event of our Action Bind. Having said all that, locate the SetupPlayerInputComponent function and add the following code after the default inputs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
//First param action binding... //Declaring an action binding FInputActionBinding ActionBindingOneParam; //Specifying the associated action name and the key event ActionBindingOneParam.ActionName = FName("OneParamInput"); ActionBindingOneParam.KeyEvent = IE_Pressed; //Creating a handler which binds to the given function with a fixed int parameter FInputActionHandlerSignature OneParamActionHandler; //Binding the function named OneParamFunction to our handler //The first parameter (this) means that the handler will search the given function inside the current class OneParamActionHandler.BindUFunction(this, FName("OneParamFunction"), FirstIntParam); //Associating our action binding with our new delegate ActionBindingOneParam.ActionDelegate = OneParamActionHandler; //Performing the actual binding... InputComponent->AddActionBinding(ActionBindingOneParam); //Second Param - identical code to the first param action bind but with a different function and parameters! FInputActionBinding ActionBindingTwoParams; ActionBindingTwoParams.ActionName = FName("TwoParamsInput"); ActionBindingTwoParams.KeyEvent = IE_Pressed; FInputActionHandlerSignature TwoParamsActionHandler; TwoParamsActionHandler.BindUFunction(this, FName("TwoParamsFunction"), SecondIntParam, FloatParam); ActionBindingTwoParams.ActionDelegate = TwoParamsActionHandler; InputComponent->AddActionBinding(ActionBindingTwoParams); //Binding the change parameters function InputComponent->BindAction("ChangeParameters", IE_Pressed, this, &AInputsWithParametersCharacter::ChangeParameters); |
The remaining steps are to implement the function ChangeParameters and specify some initial values for our exposed properties through the Editor.
Changing our variables on run time
The ChangeParameters function will generate two random values and will re-bind the TwoParamsInput Action Binding. Having said that, here is the implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
void AInputsWithParametersCharacter::ChangeParameters() { //Choosing a different random param! SecondIntParam = FMath::Rand(); FloatParam = FMath::RandRange(-1000.f, 1000.f); GLog->Log("Changed params: " + FString::FromInt(SecondIntParam) + " " + FString::SanitizeFloat(FloatParam)); //Search all the action bindings until we find the binding with the two parameters for (int32 i = 0; i < InputComponent->GetNumActionBindings() - 1; i++) { if (InputComponent->GetActionBinding(i).ActionName.IsEqual("TwoParamsInput")) { //Declaring a new binding with the same action name and key event as the TwoParamsInput initial action binding FInputActionBinding NewActionBinding; NewActionBinding.ActionName = FName("TwoParamsInput"); NewActionBinding.KeyEvent = IE_Pressed; //Creating an identical handler with the same bind as before FInputActionHandlerSignature NewDelegate; //However, this bind contains our new values! NewDelegate.BindUFunction(this, FName("TwoParamsFunction"), SecondIntParam, FloatParam); //Associating our handler with our action binding NewActionBinding.ActionDelegate = NewDelegate; //The GetActionBinding function returns the action binding by reference //This means that in the following line we replace the old binding (which contains old values) //with a new binding (which contains the updated values) InputComponent->GetActionBinding(i) = NewActionBinding; GLog->Log("changed the action binding"); } } } |
Save and compile your code. Then, switch to your Editor and:
- Assign values to our variables from within the character Blueprint
- Test your code
Here is a screenshot of my default values:
And here is a screenshot of my end result (after calling the change parameters function a couple of times):
Hello, great tutorial but I found an issue(this might have changed since you posted this). When I bind the uFunction’s with the action handler’s, the third parameter does not show up and it will give me errors that this will not work. I’m using Engine version: 4.15.1
Hello,
It would help a lot if you post your code in a pastebin link so I can see what’s going on.
-Orfeas
Sorry about the late reply, wasn’t able to get to my computer. But I found out what the issue was, instead of delcaring FInputActionHandlerSignature, I declared FInputActionHandlerDynamicSignature by accident and that was why I was having this issue. Apologies for bothering you with my question, but atleast if anybody else has the same issue now they can see to check that as autocomplete might have used FInputActionHandlerDynamicSignature instead of FInputActionHandlerSignature. Fantastic tutorial though! 🙂