Implementing Action Binding with parameters С++

В этом туториале мы собираемся создавать различные назначения действий (Action binding) с параметрами. Кроме того, мы научимся изменять их в любое время.
При написании статьи, я расчитывал на то, что вы уже знакомы с UE4 Delegates. Если же нет, вы можете найти на моем сайте туториал на эту тему.

Creating you Inputs

Создадим любой С++ шаблон, и добавим следующие действия:

Image

[свернуть]
Затем откроем .h файл вашего персонажа, и добавим следующие функции:
Code


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;

[свернуть]
Затем, внутри .cpp вашего персонажа, добавим следующую реализацию (Implementation) функций OneParamFunction и TwoParamFunction:
Code


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));
}

[свернуть]
Перед тем как продолжить, давайте сделаем шаг назад, чтобы понять как работают Inputs в С++ внутри UE4.
Ваш персонаж содержит компонент с именем InputComponent. Который отвечает за проверку, если существует необходимое устройство (клавиатура, геймпад, мышь). Кроме того, этот компонент содержит все доступные Input для конкретного персонажа.
В настоящее время существует два типа bind-а в UE4:
Axis binding
Action binding

Основное отличие состоит в том, что axis binding выполняется каждый кадр, в то время как action binding выполняется лишь при определенных условиях (например когда пользователь дважды щелкнул мышкой, или нажал определенную кнопку)
Мы с вами сосредоточимся именно на action binding.

Для того чтобы объявить action binding вам необходимо:
— Указать действие с помощью настроек редактора в разделе Inputs
— Объявить, какая функция срабатывает, если происходит событие Input-а
Внутри темплейта FirstPerson вы можете найти следующую строку кода внутри SetupPlayerInputComponent:

InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);

Это стандартный способ добавить action binding. Но мы рассмотрим другой способ добавления action binding.
На самом деле, в С++ Action binding является структурой, которая содержит полезную информацию, такую как:
Action Delegate
Action Name (Которое является именем вашего Action binding)
A Key Envent (Которое описывает тип input-а, в нашем случае мы будет использовать IE_Pressed действие, которое описывает нажатие кнопки)

Action Delegate по сути является обработчиком, который указывает на функцию, которая будет выполнятся если мы имеем правильное событие от input-а. (грубо говоря нажми кнопку получишь результат).
Теперь когда мы с этим немного разобрались откроем SetupPlayerInputComponent и добавим следующий код:

Code


//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)

[свернуть]

Изменение переменные в Run Time

Функция изменения параметров генерирует два случайных значения, и будет повторно делать Action Binding для TwoParamInput. Реализация этого будет такая:

Code


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");
}
}
}

[свернуть]
Сохраняем и компилируем код, теперь перейдем Эдитору и:
— Присвоим значения наших переменных внутри Blueprint-а персонажа
— Проверим работу нашего кода
Вот скриншот моих значений по умолчанию:
Image

[свернуть]
И вот результат работы моего Input-а:
Image

[свернуть]

Original page


Читайте также: