Using DamageTypes in Unreal Engine 5 with C++
Real quick let's make some DamageTypes in UE5

Game Engine
Unreal Engine 5.5.3
IDE
Rider 2024.3.6
Project Name
MyProject
OS
macOS Sequoia 15.3.1
When applying and receiving damage we can use custom DamageTypes
to help determine how we want our actors to react to the damage. For example, we might have three different types of bombs and some enemies might have certain weaknesses or buffs against specific damage types.
For this quick example I'll focus on Gas, Fire, and Water DamageType
s. We'll pass this DamageType
through the ApplyDamage
function and the actor will react to it in the OnTakeAnyDamage
delegate. You can refer to my ApplyDamage post or OnTakeAnyDamage post for quick overviews on those methods.
Start by creating custom UObject
class that contains custom damage types along with a custom enumerator. The enum
will be used in switch statement to return the StataicClass()
that we need to pass to the ApplyDamage
function. We also need separate UDamageType
classes for each unique type. So we'll need a Gas, Fire, and Water class that inherit from UDamageType
. Below is the header file I created for the DamageType
s.
MyDamageTypes.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "GameFramework/DamageType.h"
#include "MyDamageTypes.generated.h"
UENUM(BlueprintType)
enum class EMyDamageTypes : uint8
{
Gas UMETA(DisplayName = "Gas"),
Fire UMETA(DisplayName = "Fire"),
Water UMETA(DisplayName = "Water")
};
UCLASS()
class MYPROJECT_API UGasDamageType : public UDamageType
{
GENERATED_BODY()
};
UCLASS()
class MYPROJECT_API UFireDamageType : public UDamageType
{
GENERATED_BODY()
};
UCLASS()
class MYPROJECT_API UWaterDamageType : public UDamageType
{
GENERATED_BODY()
};
UCLASS()
class MYPROJECT_API UMyDamageTypes : public UObject
{
GENERATED_BODY()
public:
static TSubclassOf<UDamageType> GetDamageTypeClass(EMyDamageTypes DamageType);
};
The GetDamageTypeClass
will be a simple switch statement that returns a TSubclassOf<UDamageType>
. We do this to satisfy the ApplyDamage
's las parameter of TSubclassOf<UDamageType> DamageTypeClass
.
MyDamageTypes.cpp
#include "MyDamageTypes.h"
TSubclassOf<UDamageType> UMyDamageTypes::GetDamageTypeClass(EMyDamageTypes DamageType)
{
switch (DamageType)
{
case EMyDamageTypes::Gas:
return UGasDamageType::StaticClass();
case EMyDamageTypes::Fire:
return UFireDamageType::StaticClass();
case EMyDamageTypes::Water:
return UWaterDamageType::StaticClass();
default:
return UDamageType::StaticClass();
}
}
With our custom damage types in place we can now apply and receive damage using our newly created types. When using ApplyDamage
we can do something similar to the snippet below. We'll trigger ApplyDamage
inside an OnHit
function and use our new GetDamageTypeClass
method along with our new EMyDamageTypes
enum
to create our TSubclassOf<UDamageType>
variable. In the snippet below we're passing in our "fire" DamageType
. I think in some cases we might be able to bypass the enum
and GetDamageTypeClass
method all together, and just use the available classes, but having an enum
and custom function might help keep things consistent throughout our project. As always, adjust as you see fit.
MyProjectile.h (example
#include "MyProject/Enums/MyDamageTypes.h"
...
void AMyProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
if (IsValid(OtherActor))
{
AController* InstigatorController = GetInstigatorController();
TSubclassOf<UDamageType> DamageType = UMyDamageTypes::GetDamageTypeClass(EMyDamageTypes::Fire);
UGameplayStatics::ApplyDamage(OtherActor, 100.f, InstigatorController, this, DamageType);
Destroy();
}
}
Now in our receiving actor we can perform conditional logic inside our OnTakeAnyDamage
function. In this example we can pretend that our enemy is a fire creature thus making it immune to fire damage. So if it's a fire bomb, there will not be any damage applied, if it's a water bomb we'll multiply the damage by two, if it's a gas bomb we'll halve the damage, and for everything else the regular damage amount be applied.
MyCreatureCharacter.cpp (example)
#include "MyProject/Enums/MyDamageTypes.h"
AMyMovingCharacter::AMyCreatureCharacter()
{
...
OnTakeAnyDamage.AddDynamic(this, &AMyMovingCharacter::MyDamageFunction);
}
void AMyCreatureCharacter::MyDamageFunction(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
{
if (DamageType != nullptr)
{
if (DamageType->IsA(UGasDamageType::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Gas DamageType"));
// Creature receives half damage from gas type
Health -= (Damage * 0.5);
}
else if (DamageType->IsA(UFireDamageType::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Fire DamageType"));
// Do nothing to Health, Creature is immune
}
else if (DamageType->IsA(UWaterDamageType::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Water DamageType"));
// Creature is weak to water, 2x damage
Health -= (Damage * 2);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Default DamageType"));
Health -= Damage;
}
}
if (Health <= 0.f)
{
Destroy();
}
}
I hope this helped. I found it a little tricky to connect the custom enum
to custom DamageType
static classes, but I think we eventually go there with the custom GetDamageTypeClass
function.