AActor::TakeDamage 함수
float AActor::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float ActualDamage = DamageAmount;
UDamageType const* const DamageTypeCDO = DamageEvent.DamageTypeClass ? DamageEvent.DamageTypeClass->GetDefaultObject<UDamageType>() : GetDefault<UDamageType>();
if (DamageEvent.IsOfType(FPointDamageEvent::ClassID))
{
// point damage event, pass off to helper function
FPointDamageEvent* const PointDamageEvent = (FPointDamageEvent*) &DamageEvent;
ActualDamage = InternalTakePointDamage(ActualDamage, *PointDamageEvent, EventInstigator, DamageCauser);
// K2 notification for this actor
if (ActualDamage != 0.f)
{
ReceivePointDamage(ActualDamage, DamageTypeCDO, PointDamageEvent->HitInfo.ImpactPoint, PointDamageEvent->HitInfo.ImpactNormal, PointDamageEvent->HitInfo.Component.Get(), PointDamageEvent->HitInfo.BoneName, PointDamageEvent->ShotDirection, EventInstigator, DamageCauser, PointDamageEvent->HitInfo);
OnTakePointDamage.Broadcast(this, ActualDamage, EventInstigator, PointDamageEvent->HitInfo.ImpactPoint, PointDamageEvent->HitInfo.Component.Get(), PointDamageEvent->HitInfo.BoneName, PointDamageEvent->ShotDirection, DamageTypeCDO, DamageCauser);
// Notify the component
UPrimitiveComponent* const PrimComp = PointDamageEvent->HitInfo.Component.Get();
if (PrimComp)
{
PrimComp->ReceiveComponentDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
}
}
}
else if (DamageEvent.IsOfType(FRadialDamageEvent::ClassID))
{
// radial damage event, pass off to helper function
FRadialDamageEvent* const RadialDamageEvent = (FRadialDamageEvent*) &DamageEvent;
ActualDamage = InternalTakeRadialDamage(ActualDamage, *RadialDamageEvent, EventInstigator, DamageCauser);
// K2 notification for this actor
if (ActualDamage != 0.f)
{
FHitResult const& Hit = (RadialDamageEvent->ComponentHits.Num() > 0) ? RadialDamageEvent->ComponentHits[0] : FHitResult();
ReceiveRadialDamage(ActualDamage, DamageTypeCDO, RadialDamageEvent->Origin, Hit, EventInstigator, DamageCauser);
OnTakeRadialDamage.Broadcast(this, ActualDamage, DamageTypeCDO, RadialDamageEvent->Origin, Hit, EventInstigator, DamageCauser);
// add any desired physics impulses to our components
for (int HitIdx = 0; HitIdx < RadialDamageEvent->ComponentHits.Num(); ++HitIdx)
{
FHitResult const& CompHit = RadialDamageEvent->ComponentHits[HitIdx];
UPrimitiveComponent* const PrimComp = CompHit.Component.Get();
if (PrimComp && PrimComp->GetOwner() == this)
{
PrimComp->ReceiveComponentDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
}
}
}
}
// generic damage notifications sent for any damage
// note we will broadcast these for negative damage as well
if (ActualDamage != 0.f)
{
ReceiveAnyDamage(ActualDamage, DamageTypeCDO, EventInstigator, DamageCauser);
OnTakeAnyDamage.Broadcast(this, ActualDamage, DamageTypeCDO, EventInstigator, DamageCauser);
if (EventInstigator != nullptr)
{
EventInstigator->InstigatedAnyDamage(ActualDamage, DamageTypeCDO, this, DamageCauser);
}
}
return ActualDamage;
}
간단히 살펴보자면,
float AActor::TakeDamage(
float DamageAmount, // 전달할 데미지 수치
FDamageEvent const& DamageEvent, // 데미지 이벤트 종류
AController* EventInstigator, // 데미지 전달 명령의 가해자 (controller)
AActor* DamageCauser // 데미지 전달에 사용된 도구
)
이처럼 4가지의 파라미터를 통해 데미지를 피해자 액터 입장에서 관리한다.
무기야, 여러 가지 방식의 물리 액션을 생각할 수 있지만
가장 primitive 한 형태로 검/창/도끼/둔기 등의 한손/양손 무기를 들어 휘두르는 것을 가정해보자.
이 때 필요한 건
물론 기본적인 캐릭터 액터와 더불어,
무기에 대한 액터,
캐릭터의 Skeletal Mesh에 부착할 손에 관련한 Socket 이 필요하다.