How did I deal with…?
Adding a New Input Action from C++ into Unreal Engine
The goal of this project is to program the whole gameplay of a 3rd person video game using C++. Here you can see the main action in my prototype block out level:
In this case, instead of reusing the default Blueprint for the 3rd person character, I am using the C++ implementation. My goal here is to learn:
- Adding input actions from C++
- Understanding the API better, and
- Being able to re‑program it by myself in the future.
This are the steps to create the necessary UProperties and mapping the action:
Input Action
I'm using this new Input Action to interact with pickups. That Action is enabling me to trigger a series of events, including:
- Updating my counter
- Unlocking the exit gates
- Destroying collected items
- Sending delegates to my User Interface (UI), and
- Communicating with my pickup system using an Interface.
UProperties
All this by just pressing the “E” key. Nothing of this is in my C++ Actor Source. I am using the C++ template, so this is what I I'm getting in the header of my player character. First declaring the UProperties:
/** MappingContext */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputMappingContext* DefaultMappingContext;
/** Jump Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* JumpAction;
/** Move Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* MoveAction;
/** Look Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* LookAction;
And declaring my new Input Action as a UProperty just by copying the syntax:
/** Interact Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* InteractAction;
This is what the new action's slot looks like in the Input Category of my Player Character Blueprint, before and after creating the respective Input Action, and mapping it in the Input Mapping Context:
Declaring and implementing functions
In the protected section, the API is declaring functions for the actions:
protected:
/** Called for movement input */
void Move(const FInputActionValue& Value);
/** Called for looking input */
void Look(const FInputActionValue& Value);
Again, declaring here my own function:
/** Called for interacting input */
void Interact(const FInputActionValue& Value);
Moving on to the source file, this is what the Input Bindings implementation looks like:
void ASciFiProjCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked(PlayerInputComponent)) {
//Jumping
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
//Moving
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ASciFiProjCharacter::Move);
//Looking
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ASciFiProjCharacter::Look);
}
}
Including own binding
I'm including my own binding with the rest, into the SetupPlayerInputComponent:
//Interacting
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Triggered, this, &ASciFiProjCharacter::Interact);
And this is the implementation of my Interact Action, including the Interface and some Delegates:
void ASciFiProjCharacter::Interact(const FInputActionValue& Value)
{
if (OverlappedActor && CanPickup)
{
IInteractInterface* Interface = Cast(OverlappedActor);
if (Interface && (MissionAccomplished == false))
{
Interface->Execute_OnInteract(OverlappedActor, this);
CollectedItems++;
//GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Yellow, FString::Printf(TEXT("%d"), CollectedItems));
Add_Item.Broadcast();
}
if (CollectedItems == (TotalItems - 1))
{
Interact_OneToGo.Broadcast();
}
if (CollectedItems == TotalItems)
{
CanPickup = false;
MissionAccomplished = true;
//GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Yellow, TEXT("Mission Accomplished! Proceed to Exit Gates"));
Mission_Accomplished.Broadcast();
All_Pickups_Collected.Broadcast();
Interact_Finished.Broadcast();
}
}
else
{
if (OverlappedActor == nullptr && CanPickup == false && MissionAccomplished == false)
{
Interact_Empty.Broadcast();
}
if (OverlappedActor == nullptr && CanPickup == false && MissionAccomplished == true)
{
Interact_Finished.Broadcast();
}
}
}
And that's it. That's all it takes to create an own input action in C++.
If you want to know more about Technical Art, Programming in C++ and Real Time, click on the following case studies: