Help with Health potion

I am trying to create a health system for my game. I have already created a HealthComponent which I attached to my MainPlayer. I have also created a HealthBar Widget that shows my health getting lower.

My question is, how do I replenish my health through a separate potion class? What is the best route to take for that?

Here’s my Code:

HealthComponent.h

#pragma once

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


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

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

	// Health
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
	float DefaultHealth;
	UPROPERTY(BlueprintReadOnly)
	float Health;

protected:
	// Called when the game starts
	virtual void BeginPlay() override;
	
	UFUNCTION()
	void TakeDamage(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
};

HealthComponent.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 = false;

	DefaultHealth = 100.f;
	Health = DefaultHealth;
}


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

	AActor* Owner = GetOwner();
	if (Owner)
	{
		Owner->OnTakeAnyDamage.AddDynamic(this, &UHealthComponent::TakeDamage);
	}
	
}

void UHealthComponent::TakeDamage(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser) 
{
	if (Damage <= 0)
	{
		return; 
	}
	
	Health = FMath::Clamp(Health - Damage, 0.0f, DefaultHealth);

	UE_LOG(LogTemp, Warning, TEXT("Health: %f"), Health);
}

Thank you in advance!

One way would let potion class take in a UHealthComponent* as a parameter to your ApplyPotion(UHealthComponent* HealthComponent) function.

You could then use that reference to call another function in you health component to give health, or pass in a negative value to your TakeDamage function.

I tried that and then I was unable to actually use the functions with my action mapping. It kept saying that there was “no instance of overloaded function “UInputComponent::BindAction” matches the argument list?”
All of the ways I have tried, has failed so far!

I’m an amateur so some of what you’re saying is going over my head lol.
Would you be able to show me step by step?

This sounds like a syntax error or incorrect setup of your input binding. Look at the third person cpp example project for how to set your input bindings up correctly.

For the potion:
Assuming you have a potion UObject or AActor derived class lets say AHealthPotion:

  • within that class you create a public ApplyPotion(UHealthComponent* HealthComponent) function.
    *This function will look something like this:
void AHealthPotion::ApplyPotion(UHealthComponent* HealthComponent)
{
  if(HealthComponent){
    HealthComponent->AddHealth(25.f);
  }
}
  • This implies you’ve made a AddHealth(float AddedHealth) function in your Health Component that adds AddedHealth to your health value.

  • You will need to include your HealthComponent.h header file

So I attempted what you suggested and I believe I did what you told me correctly, but I’m still getting errors. I Binded the action to my MainPlayer class, created the ApplyPotion() function in the HealthPotion class, and also created AddHealth() function within the HealthComponent.

I am still getting these errors:

  • error C4458: declaration of ‘HealthComponent’ hides class member

  • note: see declaration of ‘AHealthPotion::HealthComponent’

  • error C2664: ‘FInputActionBinding &UInputComponent::BindAction(const FName,const EInputEvent,UserClass ,RetType (__cdecl AMainPlayer:: )(void))’: cannot convert argument 4 from ‘void (__cdecl UHealthComponent::* )(float)’ to ‘RetType (__cdecl AMainPlayer::* )(void)’
    with
    [
    UserClass=AMainPlayer,
    RetType=void
    ]
    and
    [
    RetType=void
    ]

  • note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Here’s the code I added:

MainPlayer.cpp:

	PlayerInputComponent->BindAction("DrinkPotion", IE_Pressed, this, &UHealthComponent::AddHealth);

HealthComponent.h:

	void AddHealth(float AddedHealth);

HealthComponent.cpp

void UHealthComponent::AddHealth(float AddedHealth) 
{
	if(Health < 100.f)
	{
		Health += AddedHealth;
	}
}

HealthPotion.h:

	UHealthComponent* HealthComponent;
	float HealAmount = 30.f;

	void ApplyPotion(UHealthComponent* HealthComponent);

HealthPotion.cpp:

void AHealthPotion::ApplyPotion(UHealthComponent* HealthComponent) 
{
  if(HealthComponent)
  {
    HealthComponent->AddHealth(HealAmount);
  }
}

What am I missing or just not knowledgeable about??

Thank you!

the BindAction points to ‘this’… replace that reference with your HealthComponent variable and make sure the AddHealth function is public.
something like:

PlayerInputComponent->BindAction("DrinkPotion", IE_Pressed, MyHealthComponent, &UHealthComponent::AddHealth);

Edit: Also, AddHealth should be a void for that bind.

You instead might want to create a
void MyPlayerCharacter::DrinkPotion() {
MyHealthPotion->ApplyPotion(MyHealthComponent);
}

Somehow you need to set up a MyHeathPotion object reference, if you are doing an inventory system, limited pickups, whatever… but if you have a reference to a potion object it should work. To start you could just add a potion object as a member variable, then work out to making it a pick up.

Then your input setup looks like this:
PlayerInputComponent->BindAction("DrinkPotion", IE_Pressed, this, &MyPlayerCharacter::DrinkPotion);

I applied everything you told me and it compiles successfully, the only thing I noticed is that I’m having trouble referencing both the UHealthComponent and AHealthPotion. I’m assuming I just have to reference them in the MainPlayer.cpp file because they are passed in through function arguments, correct?

Idk what else to try!

Your MainPlayer.cpp should have a reference to your healthcomponent already assuming you’re setting it up via CreateDefaultSubobject.

What I was getting at with setting up the AHealthPotion Reference:

The simple approach: doing a limited number of pickup items (like health potion, ammo, shield) then you can store that on your character as int variables like int HealthPotionCount. Then you can just run a function you build in MainPlayer.cpp “DrinkHealthPotion” that tells the health component to increment health. No need to do it in the Health Potion actor… just use that actor as a visual pickup that increments your health potion count when you run into it.

If you are building a game with a lot of different types of inventory, then you have to build that out as it will give you the reference to your health potion. There are different approaches to this and lots of youtube tutorials to get you started.