Adding Components to an Actor

A tutorial for adding Components to Actors.

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 project.

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

    Click for full view.

  2. 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.

    Click for full view.

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 Parent Class menu, select Actor Component to create a new Actor Component named Bp_HealthComponent.

    03_BP_CreateBPActorComponentClass.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.

    04_BP_AddVariables.png

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

    05_BP_MaxHealthDetails.png

Creating The Event Dispatcher: Handle Damage

Event Dispatchers 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.

    06_BP_AddEventDispatcher.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.

    07_BP_AddDispatcherInputs.png

  3. Click Compile and Save.

    08_BP_CompileSaveButtons.png

Creating The Event Begin Play Script of Health Component

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

    Copy Node Graph

    09_BPScript_01_01.png

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

    Copy Node Graph

    10_BPScript_01_02.png

  3. 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.

    Copy Node Graph

    11_BPScript_01_03.png

  4. From the Set 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.

    Copy Node Graph

    12_BPScript_01_04.png

  5. 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.

    Copy Node Graph

    13_BPScript_01_05.png

  6. 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.

    Copy Node Graph

    14_BPScript_01_06.png

  7. From the Create Event node, click the Select Function dropdown menu and select the Create matching function.

    15_BPScript_01_07.png

Creating The Function: Take Damage

When you finish Creating The Event Begin Play Script of Health Component, the function, you created in the last step will automatically open.

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

To do this, follow the steps below:

  1. Rename created function to Take Damage.

    16_RenameFunction.png

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

    Copy Node Graph

    17_BPScript_02_01.png

  3. From the Take Damage node, drag off the Damage variable. Then from the Actions menu, search for and select Subtract.

    Copy Node Graph

    18_BPScript_02_02.png

  4. Drag off from the Health pin and connect it to the A subtraction float of the Subtract node.

    Copy Node Graph

    19_BPScript_02_03.png

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

    Copy Node Graph

    20_BPScript_02_04.png

  6. 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.

    Copy Node Graph

    21_BPScript_02_05.png

  7. Drag off the execution pin from the Take Damage node, then from the Actions menu search for and select the Branch.

    Copy Node Graph

    22_BPScript_02_06.png

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

    Copy Node Graph

    23_BPScript_02_07.png

  9. From the Less Equal operator node, drag off of the boolean return pin, and plug it into the Condition pin of the Branch node.

    Copy Node Graph

    24_BPScript_02_08.png

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

    Copy Node Graph

    25_BPScript_02_09.png

  11. 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.

    Copy Node Graph

    26_BPScript_02_10.png

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

    Copy Node Graph

    27_BPScript_02_11.png

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

    Copy Node Graph

    28_BPScript_02_12.png

  14. From the Call Handle Take Damage node, drag off the input pin Damage Actor, then from the Actions menu search for and select Get a reference to self.

    Copy Node Graph

    29_BPScript_02_13.png

  15. 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.

    Copy Node Graph

    30_BPScript_02_14.png

  16. Click Compile and Save.

    31_CompileSaveButton.png

Finished Blueprint

Take Damage Function

Copy Node Graph

32_BPFinalScript1.png

Begin Play

Copy Node Graph

33_BPFinalScript2.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.

    34_OpenThirdPerCharacter.png

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

    35_AddBPHealthComponent.png

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

    Copy Node Graph

    36_BPScript_03_01.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.

    Copy Node Graph

    37_BPScript_03_02.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.

    Copy Node Graph

    38_BPScript_03_03.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.

    Copy Node Graph

    39_BPScript_03_04.png

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

    Copy Node Graph

    40_BPScript_03_05.png

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

    Copy Node Graph

    41_BPScript_03_06.png

  9. Connect output execution pin of the Event BeginPlay node with input execution pin of Bind Event to Handle Take Damage.

    Copy Node Graph

    42_BPScript_03_07.png

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

    Copy Node Graph

    43_BPScript_03_08.png

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

    Copy Node Graph

    44_BPScript_03_09.png

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

    Copy Node Graph

    45_BPScript_03_10.png

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

    Copy Node Graph

    46_BPScript_03_11.png

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

    Copy Node Graph

    47_BPScript_03_12.png

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

  15. From the OnHealthChanged node, drag off of the Execution pin then from the Actions menu search for and select Print String.

    Copy Node Graph

    48_BPScript_03_13.png

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

  16. Connect the Health pin from the OnHealthChanged node to the In String pin of the Print String node.

    49_BPScript_03_14.png

  17. Click Compile and Save.

    50_CompileSaveButton.png

Finished Blueprint

Copy Node Graph

51_BPFinalScript3.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.

Navigate to the Toolbar, and click Play.

52_PlayButton.png

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 project.

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

    Click for full view.

  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.

    Click for full view.

    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 Tools > New C++ Class to create a C++ Class, then from the Choose Parent Class menu, select Actor Component and click Next.

    Click for full view.

  2. Name your Actor Component Class HealthComponent and click Create.

    Click for full view.

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

        DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComponent, float, Health, float, DamageAmount, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);
  4. 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);
  5. Navigate to the HealthComponent.cpp file and inside the HealthComponent Constructor, initialize the following class variable:

        UHealthComponent::UHealthComponent()
        {
            MaxHealth = 100.0f;
        }
  6. 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->OnTakeAnyDamage.AddDynamic(this,&UHealthComponent::HandleTakeDamage);
            }
            //Set Health Equal to Max Health.
            Health = MaxHealth;
        }
  7. Declare the following code for the HandleTakeDamage method:

        void UHealthComponent::HandleTakeDamage(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);
        }
  8. 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();

    protected:

        // Called when the game starts
        virtual void BeginPlay() override;

    public:

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

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

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)
        {
            //The Owner Object is now bound to respond to the OnTakeAnyDamage Function.
            MyOwner->OnTakeAnyDamage.AddDynamic(this,&UHealthComponent::HandleTakeDamage);
        }
        //Set Health Equal to Max Health.
        Health = MaxHealth;
    }

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

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

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:
    
            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;
  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=Input)
        float TurnRateGamepad;

    protected:

        /** 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; }

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

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
        TurnRateGamepad = 50.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, 500.0f, 0.0f); // ...at this rotation rate

        // Note: For faster iteration times these variables, and many more, can be tweaked in the Character Blueprint
        // instead of recompiling to adjust them
        GetCharacterMovement()->JumpZVelocity = 700.f;
        GetCharacterMovement()->AirControl = 0.35f;
        GetCharacterMovement()->MaxWalkSpeed = 500.f;
        GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
        GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;

        // Create a camera boom (pulls in towards the player if there is a collision)
        CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
        CameraBoom->SetupAttachment(RootComponent);
        CameraBoom->TargetArmLength = 400.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("Move Forward / Backward", this, &AHealthCompCharacter::MoveForward);
        PlayerInputComponent->BindAxis("Move Right / Left", 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 Right / Left Mouse", this, &APawn::AddControllerYawInput);
        PlayerInputComponent->BindAxis("Turn Right / Left Gamepad", this, &AHealthCompCharacter::TurnAtRate);
        PlayerInputComponent->BindAxis("Look Up / Down Mouse", this, &APawn::AddControllerPitchInput);
        PlayerInputComponent->BindAxis("Look Up / Down Gamepad", this, &AHealthCompCharacter::LookUpAtRate);

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

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

    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 * TurnRateGamepad * GetWorld()->GetDeltaSeconds());
    }

    void AHealthCompCharacter::LookUpAtRate(float Rate)
    {
        // calculate delta for this frame from the rate information
        AddControllerPitchInput(Rate * TurnRateGamepad * 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);
        }
    }

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

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.

Navigate to the Toolbar, and press Play.

05_PlayButton.png

Additional Resources

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

Help shape the future of Unreal Engine documentation! Tell us how we're doing so we can serve you better.
Take our survey
Cancel