Implement damage application on collision between two Actors in Unreal Engine.
A projectile Actor must deal damage to whatever it strikes. Bind a handler to the collision component's hit delegate and route damage through the engine's damage pipeline so the receiving Actor decides the outcome.
Requirements:
TakeDamage) — do not subtract the victim's health directly from the projectile.
- Apply damage via
UGameplayStatics::ApplyDamage(which fires the target's - Ignore self-hits and hits on the projectile's own owner/instigator.
- Pass the instigator controller so kill credit is attributed correctly.
Complete the bound hit handler:
void AProjectile::OnHit(UPrimitiveComponent*, AActor* OtherActor,
UPrimitiveComponent*, FVector, const FHitResult& Hit)
{
// your code here: guard self/owner hits, then route damage to OtherActor
}
Write the implementation.
Bind a handler to the collision component's OnComponentHit or OnComponentBeginOverlap delegate, then route damage through UGameplayStatics::ApplyDamage. That fires the target's TakeDamage, keeping damage logic on the receiver.
- ✗Polling for overlaps in
Tickinstead of binding the collision delegate - ✗Subtracting health directly instead of routing through
ApplyDamage/TakeDamage - ✗Forgetting to verify the hit Actor is not the projectile's own owner
- →What is the difference between a Hit event and an Overlap event?
- →Why route damage through
ApplyDamageinstead of a custom interface call?
Damage on projectile collision
// Projectile.h
UCLASS()
class AProjectile : public AActor
{
GENERATED_BODY()
public:
AProjectile();
protected:
UPROPERTY(VisibleAnywhere)
USphereComponent* CollisionComp;
UPROPERTY(EditDefaultsOnly)
float Damage = 25.f;
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, FVector NormalImpulse,
const FHitResult& Hit);
};
// Projectile.cpp
AProjectile::AProjectile()
{
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("Collision"));
RootComponent = CollisionComp;
// Bind the handler — the constructor only subscribes the delegate
CollisionComp->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);
}
void AProjectile::OnHit(UPrimitiveComponent*, AActor* OtherActor,
UPrimitiveComponent*, FVector, const FHitResult& Hit)
{
// Don't hit yourself, and don't hit the shooter who owns this projectile
if (!OtherActor || OtherActor == this || OtherActor == GetOwner())
{
return;
}
AController* InstigatorController =
GetInstigator() ? GetInstigator()->GetController() : nullptr;
// Damage is routed to the receiver — its TakeDamage decides the outcome
UGameplayStatics::ApplyDamage(OtherActor, Damage,
InstigatorController, this,
UDamageType::StaticClass());
Destroy();
}
ApplyDamage calls OtherActor->TakeDamage(...), so the damage-reaction logic lives on the target (e.g. in its UHealthComponent) instead of being duplicated in every projectile.