Adding Components to an Actor

A tutorial for adding Components to Actors.

Choose your operating system:

Windows

macOS

Linux

On this page

Components are a type of Object designed to be used as sub-objects within Actors.

Components are useful for sharing common behaviors across different classes, such as the ability to display a visual effect, play sounds, or handle behavioral logic.

There are three components available when creating your own Components: Actor Components, Scene Components, and Primitive Components.

  • Actor Components (class UActorComponent) are useful for abstract behaviors such as movement, inventory or attribute management, and other non-physical concepts. Actor Components do not have a Transform property, meaning they do not have any physical location or rotation in the world.

  • Scene Components (class USceneComponent, a child of UActorComponent) support location-based behaviors that do not require a geometric representation. This includes spring arms, cameras, physical forces and constraints (not physical objects), and audio.

  • Primitive Components (class UPrimitiveComponent, a child of USceneComponent) are Scene Components with geometric representation, which are generally used to render visual elements, or to collide or overlap with physical objects. This includes Static or Skeletal Meshes, sprites, billboards, and particle systems as well as box, capsule, and sphere collision volumes.

Choose your implementation method:

Blueprints

C++

Project Setup

In this tutorial, you are tasked with creating gameplay logic for an Actor Component named HealthComponent. Once this Component is attached to an Actor, your Actor will contain the functionality to deduct damage from its health.

In this example, we will use the Third Person Character included in the

[Third Person Template](understanding-the-basics/projects-templates/third-person-template)
project.

  1. Begin by creating a New > Games > Third Person > Blueprint Project named Health Component.

image_0.png

  1. Navigate to Edit > Project Settings > Engine > Input > Bindings > Action Mappings, then click Add (+) to create a new Action Mapping named OnDamagePressed, and set the value to 1.

image_1.png

Input contains Action Mappings, which can be used to map a button or keypress to an event-driven behavior such as inflicting damage on the player character.

Creating The Actor Component: Health Component

In this section you'll be creating a Health Component, which is an Actor Component that can be attached to any Actor.

Follow the steps below to begin creating the logic that will keep contain and deduct the player's health value.

  1. From the Content Browser, click Add/New > Blueprint Class. Then, from the Pick a Native Class menu, select Actor Component to create a new Actor Component named Bp_HealthComponent.

    image_2.png

  2. In the Class Defaults, navigate to the MyBlueprint panel. Then, from the Variables category, click Add (+) to create two float variables named Health and MaxHealth.

    image_3.png

  3. Select the Max Health variable and navigate to the Details panel to set the default Max Health value to 100.0.

    image_4.png

  4. Drag a copy of Max Health float into the Event Graph.

    image_5.png

  5. Drag the Health float onto the Event Graph, and select Set Health to create a Set Health node.

    image_6.png

  6. Connect the output pin from Max Health float into the input pin of Health from the Set Health node, then connect the output execution pin from the Event Begin Play node into the input execution pin of the Set Health node.

    image_7.png

  7. Click Compile and Save.

    image_8.png

Creating The Event Dispatcher: Handle Damage

[Event Dispatchers](making-interactive-experiences\interactive-framework\unreal-engine-actors\actor-communication\ed-quickstart)
can call methods in an Actor that bind themselves, or "listen", to the Event Dispatcher. Then, when the Event Dispatcher calls an event, the Actor listening to it will respond to that event.

Follow the steps below to begin creating a Handle Take Damage Event Dispatcher.

  1. From the My Blueprint panel, navigate to the Event Dispatchers category and click Add (+) to create a new Event Dispatcher named HandleTakeDamage.

    image_9.png

  2. Navigate to the Details panel and from the Input category click the Add(+) button to create the following variables:

    Variable Name

    Type

    Description

    DamageActor

    Bp_HealthComponent

    The Actor that will be damaged.

    Health

    Float

    The base health of the Actor.

    Damage

    Float

    The base damage to apply.

    DamageType

    Damage Type

    The class that describes the damage dealt.

    InstigatedBy

    Controller

    The controller that is responsible for causing the damage. For example, a player who throws a grenade.

    DamageCauser

    Actor

    The Actor that represents the cause of the damage. For example, the grenade that has exploded.

    image_10.png

  3. Click Compile and Save.

    image_11.png

Creating The Function: Take Damage

You will need to create a function to handle the logic for deducting health from the Player Character when they receive damage.

To do this, follow the steps below:

  1. From the My Blueprint window, navigate to the Functions category and click Add (+) to create a new function named TakeDamage.

    image_12.png

  2. Navigate to the Details panel. Then, from the Inputs category click Add (+) to create the following inputs.

    Variable Name

    Type

    DamageActor

    Actor

    Damage

    Float

    DamageType

    Damage Type

    InstigatedBy

    Controller

    DamageCauser

    Actor

    image_13.png

  3. From the My Blueprint panel, navigate to the Variables category and drag the Health variable into the Event Graph.

    image_14.png

  4. From the Take Damage node, drag off of the Damage variable. Then from the Actions menu, search for and select float - float.

    image_15.png

  5. Drag off from the Health pin and connect it to the B subtraction float from the float - float node.

    image_16.png

  6. Drag off the result from the float - float node, then from the Actions menu, search for and select Clamp (float).

    image_17.png

  7. From the My Blueprint panel, navigate to the Variables category, then drag the Max Health variable onto the Max float variable pin of the Clamp (float) node.

    image_18.png

  8. Drag off the execution pin from the Take Damage node, then from the actions menu search for and select the Branch (if).

image_19.png

  1. From the Take Damage node, drag off of the Damage variable. Then, from the Actions menu, search for and select the <= (Less Than or Equal To) operator.

    image_20.png

  2. From the Less than equal to operator node, drag off of the boolean return pin, and plug it into the Condition pin of the Branch node.

    image_21.png

  3. From the Branch node, drag off of the False execution pin. Then, from the Actions menu search for and select Set Health.

    image_22.png

  4. Navigate to the Clamp (float) node and drag off of the Return Value. Then connect it to the Health pin of the Set Health node.

    image_23.png

  5. From the Set Health node, drag off the output execution pin, then from the Actions menu search for and select Call Handle Take Damage.

    image_24.png

  6. From the Set Health node, connect the Health output pin to the Health input pin of the Call Handle Take Damage node.

    image_25.png

  7. Navigate to the Take Damage node, then connect the Damage, Damage Type, Instigated By, and Damage Causer pins into their respective pins from the Call Handle Take Damage node.

    image_26.png

  8. Click Compile and Save.

    image_27.png

  9. Navigate to the Event Graph > Begin Play node, then from the Set Max Health Node drag off of the output execution pin. From the Actions menu uncheck the Context Sensitive box, then search for and select Bind Event to On Take Any Damage.

    image_28.png

  10. From the Bind Event to On Take Any Damage node drag off of the Target pin and from the Actions menu, search for and select Get Owner from the Components category.

    image_29.png

  11. From the Bind Event to On Take Any Damage node drag off the Event pin and from the Actions menu, search for and select Create Event.

    image_30.png

  12. From the Create Event node, click the Select Function dropdown menu and select the function TakeDamage.

    image_31.png

  13. Click Compile and Save.

    image_32.png

Finished Blueprint

Take Damage Function

image_33.png

Begin Play

image_34.png

Adding Health Component to the Third Person Character

Now that you have created your Health Component class, you will need to add its Actor Component to your Third Person Character class and bind the OnDamagePressed Action Mapping to inflict damage to the player.

  1. Navigate to the Content > ThirdPersonBp > Blueprints folder and double-click the ThirdPersonCharacter to open its Class Defaults.

    image_35.png

  2. From the Components panel, click the Add Component button then search for and select Bp Health Component.

    image_36.png

  3. Right-click the Event Graph, then from the Actions menu, search for and select OnDamagePressed.

    image_37.png

  4. From the InputAction OnDamagePressed node, drag off of the Pressed execution pin, then from the Actions menu, search for and select Apply Damage.

    image_38.png

  5. From the Apply Damage node, drag off of the Damaged Actor pin and, from the Actions menu, search for and select Get a reference to self. Set the Base Damage float value to 20.0.

    image_39.png

    The Apply Damage function is a part of the Gameplay Statics Library, which includes useful generic functions for gameplay purposes.

  6. Right-click the Event Graph, then from the Actions menu, search for and select Event Begin Play.

    image_40.png

  7. From the Components panel, drag a copy of your BP_HealthComponent into the Event Graph.

    image_41.png

  8. Drag off the Bp Health Component pin, then from the Actions menu, search for and select Bind Event to Handle Take Damage.

    image_42.png

  9. Drag off of the Event pin from the Bind Event to Handle Take Damage, then from the Actions menu search for and select Create Event to create a custom event named OnHealthChanged.

    image_43.png

  10. From the OnHealthChanged node, drag off the Health pin, then from the Actions menu search for and select the <= (Less than equal to) operator.

    image alt text

  11. From the OnHealthChanged node, drag off the Execution pin, then from the Actions menu search for and select Branch.

    image_45.png

  12. From the <= (Less than equal to) operator node, drag off of the boolean return pin, then connect it to the Condition pin of the Branch node.

    image_46.png

  13. Drag off of the True execution pin from the Branch node, then from the Actions menu search for and select DestroyActor.

    image_47.png

    When the player's health value reaches zero, then they will be removed from the world.

  14. From the OnHealthChanged node, drag off of the Execution pin then from the Actions menusearch for and select Print String.

    image_48.png

    We use Print String to print the current value of health onto the screen whenever the player character receives damage.

  15. Click Compile and Save.

    image_49.png

Finished Blueprint

image_50.png

End Result

You are now ready to test the functionality of your Health Component.

You can move your character using the WASD keys. When pressing the numeric 1 key, your character will receive damage until its health reaches zero, at which point it will be destroyed from the world.

  1. Navigate to the Toolbar, and click Play.

image_51.png

image_52.gif

Project Setup

In this tutorial, you are tasked with creating gameplay logic for an Actor Component named HealthComponent. Once this Component is attached to an Actor, your Actor will contain the functionality to deduct damage from its health.

In our example, we will use the Third Person Character included in the

[Third Person Template](understanding-the-basics/projects-templates/third-person-template)
project.

  1. Begin by creating a New > Games > Third Person > CPP Project named Health Comp.

    image_53.png

  2. Navigate to Edit > Project Settings > Engine > Input > Bindings > Action Mappings, then click the Add (+) to create a new Action Mapping named OnDamagePressed, and set the value to 1**.

    image_54.png

    Input contains Action Mappings, which can be used to map a button or keypress to an event-driven behavior such as inflicting damage on the player character.

Creating the Actor Component: Health Component

Delegates can call member functions on C++ objects in a generic, type-safe way. When an Actor binds itself to a delegate, it will respond to that Delegate's member function event.

Follow the steps below to begin creating an On Health Changed Delegate.

  1. Click Add/Import to create a New C++ Class, then from the Choose a Parent Class menu, select Actor Component to create a new Actor Component named HealthComponent.

    image_55.png

  2. In the HealthComponent.h file, declare the following Delegate:

    DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComp, float, Health, float, DamageAmount, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);
  3. Navigate to the Class Defaults and declare the following methods and variables:

    public:
    
    UPROPERTY(BlueprintAssignable, Category = "Events")
    FOnHealthChangedSignature OnHealthChanged;
    
    protected:
    
    UPROPERTY(EditDefaultsOnly,BlueprintReadWrite)
    float Health;
    
    UPROPERTY(EditDefaultsOnly,BlueprintReadWrite)
    float MaxHealth;
    
    UFUNCTION(BlueprintCallable)
    void HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
  4. Navigate to the HealthComponent.cpp file and inside the HealthComponent Constructor, initialize the following class variable:

    UHealthComponent::UHealthComponent()
    
    {
    
    MaxHealth = 100.0f;
    
    }
  5. Implement the following definition for the BeginPlay class method:

    void UHealthComponent::BeginPlay
    
    {
    Super::BeginPlay();
    
    //Get the Owner of this Actor Component.
    AActor* MyOwner = GetOwner();
    if (MyOwner)
    {
        //The Owner Object is now bound to respond to the OnTakeAnyDamage Function.        
        MyOwner->OnTakeDamage.AddDynamic(this,&UHealthComponent::HandleTakeDamage);
    }
    
    //Set Health Equal to Max Health.           
    Health = MaxHealth;
    }
  6. Declare the following code for the HandleTakeAnyDamage method:

    void UHealthComponent::HandleTakeAnyDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser) 
    { 
    
        if (Damage <= 0.0f) 
        { 
            return; 
        }
    
        Health = FMath::Clamp(Health - Damage, 0.0f, MaxHealth); OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser); 
    }
  7. Compile your code.

Finished Code

Health Component.h

    #pragma once

    #include "CoreMinimal.h"
    #include "Components/ActorComponent.h"
    #include "HealthComponent.generated.h"

    DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComponent, float, Health, float, DamageAmount, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);

    UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
    class HEALTHCOMP_API UHealthComponent : public UActorComponent
    {
    GENERATED_BODY()

    public: 

    // Sets default values for this component's properties
    UHealthComponent();

    UPROPERTY(BlueprintAssignable, Category = "Events")
    FOnHealthChangedSignature OnHealthChanged;

    protected:

    // Called when the game starts
    UFUNCTION(BlueprintCallable)

    void HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);

    virtual void BeginPlay() override;

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
    float Health;

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
    float MaxHealth;

    public: 

    // Called every frame
    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
    };

Health Component.cpp

    #include "HealthComponent.h"

    // Sets default values for this component's properties
    UHealthComponent::UHealthComponent()
    {
    // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
    // off to improve performance if you don't need them.
    PrimaryComponentTick.bCanEverTick = true;
    MaxHealth = 100.0f;
    }

    // Called when the game starts
    void UHealthComponent::BeginPlay()
    {
    Super::BeginPlay();

    //Get the Owner of this Actor Component.
    AActor* MyOwner = GetOwner();

    if(MyOwner)
    {
        MyOwner->OnTakeAnyDamage.AddDynamic(this, &UHealthComponent::HandleTakeDamage);

        //The Owner Object is now bound to respond to the OnTakeAnyDamage Function.        
        MyOwner->OnTakeAnyDamage.AddDynamic(this,&UHealthComponent::HandleTakeAnyDamage);
    }

    //Set Health Equal to Max Health.
    Health = MaxHealth;
    }

    void UHealthComponent::HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
    {

    if (Damage <= 0.0f)
    {
        //Damage amount was 0 or less.
        return;
    } 

    Health = FMath::Clamp(Health - Damage, 0.0f, MaxHealth); OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);
    }

    // Called every frame
    void UHealthComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
    {
        Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    }

Adding Health Component to the HealthComp Character

Now that you have created your Health Component class, you will need to add its Actor Component to your Health Comp Character class and bind the OnDamagePressed Action Mapping to inflict damage to the Player.

  1. From the Content Browser, navigate to C++ Classes > HealthComp and double-click the HealthComp Character** to open the `HealthCompCharacter.h` file.

  2. Declare the following code in the Class Defaults:

    protected:
    
    UPROPERTY(EditDefaultsOnly,BlueprintReadWrite)
    class UHealthComponent* HealthComponent; 
    
    UFUNCTION()
    OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
    
    //Function which will call damage to our Player
    UFUNCTION()
    void DamagePlayerCharacter();
  3. Navigate to the HealthCompCharacter.cpp file and include the following class libraries:

    #include "HealthComponent.h"
    #include "Kismet/GameplayStatics.h"

    The Gameplay statics library includes numerous utility helper functions that can serve your gameplay purpose needs. In this instance, we will be using the ApplyDamage method.

  4. In the AHealthCompCharacter Constructor, initialize your Health Component class:

    AHealthCompCharacter::AHealthCompCharacter()
    {
        HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComponent");
    }
  5. Navigate to the AHealthCompChatacter::BeginPlay method and add the following code:

    void AHealthCompCharacter::BeginPlay()
    {
        Super::BeginPlay();
        HealthComponent->OnHealthChanged.AddDynamic(this, &AHealthCompCharacter::OnHealthChanged);
    }
  6. In the AHealthCompCharacter::OnHealthChanged method, implement the following logic to destroy the Player Character when its health reaches zero:

    void AHealthCompCharacter::OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
    {
        if (Health <= 0.0f)
    {
        Destroy();
    }
        UE_LOG(LogTemp, Warning, TEXT("The Player's Current Health is: %f"), Health);
    }

    UE_LOG is a macro that contains varying verbosity types to use along with commands for visualizing your data to the output log.

  7. Implement the AHealthCompCharacter::DamagePlayerCharacter method by adding the following code:

    void AHealthCompCharacter::DamagePlayerCharacter()
    {
        UGameplayStatics::ApplyDamage(this, 20.0f, GetInstigatorController(),this,GenericDamageType);
    }
  8. Navigate to AHealthCompCharacter::SetupPlayerInputComponent method to assign your OnDamagePressed binding to the DamagePlayerCharacter function:

    void AHealthCompCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
    {
        //Bind OnDamagePressed Action Event
        PlayerInputComponent->BindAction("OnDamagePressed", IE_Pressed, this, &AHealthCompCharacter::DamagePlayerCharacter);
    }
  9. Compile your code.

Finished Code

HealthCompCharacter.h

    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "HealthCompCharacter.generated.h"

    UCLASS(config=Game)
    class AHealthCompCharacter : public ACharacter
    {
        GENERATED_BODY()

    /** Camera boom positioning the camera behind the character */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class USpringArmComponent* CameraBoom;

    /** Follow camera */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UCameraComponent* FollowCamera;

    public:

    AHealthCompCharacter();
    /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
    float BaseTurnRate;

    /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
    float BaseLookUpRate;

    protected:

    virtual void BeginPlay() override;

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
    class UHealthComponent* HealthComponent;

    UFUNCTION()
    void OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);

    //Function which will call damage to our Player
    UFUNCTION()
    void DamagePlayerCharacter();

    //Container for a Damage Type to inflict on the Player
    UPROPERTY(EditDefaultsOnly,BlueprintReadOnly, Category = "Weapon")
    TSubclassOf<UDamageType> GenericDamageType;

    /** Resets HMD orientation in VR. */
    void OnResetVR();

    /** Called for forwards/backward input */
    void MoveForward(float Value);

    /** Called for side to side input */
    void MoveRight(float Value);

    /** 
     * Called via input to turn at a given rate. 
     * @param Rate  This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
     */
    void TurnAtRate(float Rate);

    /**
     * Called via input to turn look up/down at a given rate. 
     * @param Rate  This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
     */
    void LookUpAtRate(float Rate);

    /** Handler for when a touch input begins. */
    void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

    /** Handler for when a touch input stops. */
    void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

    protected:

    // APawn interface
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    // End of APawn interface

    public:

    /** Returns CameraBoom subobject **/
    FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }

    /** Returns FollowCamera subobject **/
    FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }

    };

HealthCompCharacter.cpp

    #include "HealthCompCharacter.h"
    #include "HeadMountedDisplayFunctionLibrary.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CapsuleComponent.h"
    #include "Components/InputComponent.h"
    #include "GameFramework/CharacterMovementComponent.h"
    #include "GameFramework/Controller.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "HealthComponent.h"
    #include "Kismet/GameplayStatics.h"

//////////////////////////////////////////////////////////////////////////

// AHealthCompCharacter

    AHealthCompCharacter::AHealthCompCharacter()
    {

    // Set size for collision capsule
    GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

    // set our turn rates for input
    BaseTurnRate = 45.f;
    BaseLookUpRate = 45.f;

    // Don't rotate when the controller rotates. Let that just affect the camera.
    bUseControllerRotationPitch = false;
    bUseControllerRotationYaw = false;
    bUseControllerRotationRoll = false;

    // Configure character movement
    GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...   
    GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
    GetCharacterMovement()->JumpZVelocity = 600.f;
    GetCharacterMovement()->AirControl = 0.2f;

    // Create a camera boom (pulls in towards the player if there is a collision)
    CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
    CameraBoom->SetupAttachment(RootComponent);
    CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character   
    CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

    // Create a follow camera
    FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
    FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

    // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
    // are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)

    HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComponent"));

    }

    //////////////////////////////////////////////////////////////////////////

    // Input

    void AHealthCompCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
    {

    // Set up gameplay key bindings
    check(PlayerInputComponent);

    PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
    PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
    PlayerInputComponent->BindAxis("MoveForward", this, &AHealthCompCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AHealthCompCharacter::MoveRight);

    // We have 2 versions of the rotation bindings to handle different kinds of devices differently
    // "turn" handles devices that provide an absolute delta, such as a mouse.
    // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick

    PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
    PlayerInputComponent->BindAxis("TurnRate", this, &AHealthCompCharacter::TurnAtRate);
    PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
    PlayerInputComponent->BindAxis("LookUpRate", this, &AHealthCompCharacter::LookUpAtRate);

    // handle touch devices
    PlayerInputComponent->BindTouch(IE_Pressed, this, &AHealthCompCharacter::TouchStarted);
    PlayerInputComponent->BindTouch(IE_Released, this, &AHealthCompCharacter::TouchStopped);

    // VR headset functionality
    PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &AHealthCompCharacter::OnResetVR);

    //Bind OnDamagePressed Action Event
    PlayerInputComponent->BindAction("OnDamagePressed", IE_Pressed, this, &AHealthCompCharacter::DamagePlayerCharacter);
}

    void AHealthCompCharacter::BeginPlay()
    {
    Super::BeginPlay();
    HealthComponent->OnHealthChanged.AddDynamic(this, &AHealthCompCharacter::OnHealthChanged);
    }

    void AHealthCompCharacter::OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
    {
    if (Health <= 0.0f)
    {
        Destroy();
    }
    UE_LOG(LogTemp, Warning, TEXT("The Player's Current Health is: %f"), Health);
    }

    void AHealthCompCharacter::DamagePlayerCharacter()
    {
        UGameplayStatics::ApplyDamage(this, 20.0f, GetInstigatorController(),this,GenericDamageType);
    }

    void AHealthCompCharacter::OnResetVR()
    {

    // If HealthComp is added to a project via 'Add Feature' in the Unreal Editor the dependency on HeadMountedDisplay in HealthComp.Build.cs is not automatically propagated
    // and a linker error will result.
    // You will need to either:
    //Add "HeadMountedDisplay" to [YourProject].Build.cs PublicDependencyModuleNames in order to build successfully (appropriate if supporting VR).
    // or:
    //Comment or delete the call to ResetOrientationAndPosition below (appropriate if not supporting VR)

    UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
    }
    void AHealthCompCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
    {
        Jump();
    }

    void AHealthCompCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
    {
        StopJumping();
    }

    void AHealthCompCharacter::TurnAtRate(float Rate)
    {
    // calculate delta for this frame from the rate information
    AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
    }

    void AHealthCompCharacter::LookUpAtRate(float Rate) 
    {
    // calculate delta for this frame from the rate information
    AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
    }

    void AHealthCompCharacter::MoveForward(float Value)
    {
        if ((Controller != nullptr) && (Value != 0.0f))
        {
            // find out which way is forward
            const FRotator Rotation = Controller->GetControlRotation();
            const FRotator YawRotation(0, Rotation.Yaw, 0);

            // get forward vector
            const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
            AddMovementInput(Direction, Value);
        }
    }

    void AHealthCompCharacter::MoveRight(float Value)
    {

        if ( (Controller != nullptr) && (Value != 0.0f) )
    {

        // find out which way is right
        const FRotator Rotation = Controller->GetControlRotation();
        const FRotator YawRotation(0, Rotation.Yaw, 0);

        // get right vector 
        const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

        // add movement in that direction
        AddMovementInput(Direction, Value);
    }
    }

End Result

You are now ready to test the functionality of your Health Component.

You can move your character using the WASD keys. When pressing the numeric 1 key, your character will receive damage until its health reaches zero, at which point it will be destroyed from the world.

  1. Navigate to the Toolbar, and press Play.

image_56.png

image_57.gif

Additional Resources

There are several concepts that tie into Adding Components to Blueprints and the links below provide additional relevant information:

This page was written for a previous version of Unreal Engine and has not been updated for the current Unreal Engine 5.0 release.