멀티플레이 환경에서는 PlayerState를 사용해, 서버와 클라이언트 모두 플레이어 간 데이터 동기화를 시킬 수 있다.
아래는 싱글플레이 기준으로 설명할 것이고 동기화가 필요하지 않으므로, 캐릭터 클래스 자체에서 체력을 관리하도록 하였다.
📍 데미지 관련 메서드
✅ AActor::TakeDamage
virtual float TakeDamage
(
float DamageAmount,
struct FDamageEvent const& DamageEvent,
class AController* EventInstigator,
AActor* DamageCauser
)
언리얼 엔진에서 기본 데미지 시스템을 사용하는 대표적인 함수이다.
- DamageAmount: 실제 데미지의 총량을 의미하고, 저항력 및 방어력에 따라 TakeDamage의 float 반환 값은 수정할 수 있다.
- DamageEvent: 데미지의 구체적 유형과 추가 정보를 담고 있는 구조체이다.
FDamageEvent는 기본 데미지 정보를 담고 있는 기본 클래스이고 이를 상속하는 다양한 구조체들이 존재한다.
1. FPointDamageEvent: 특정 시점에서 발생하는 데미지(총알과 같은 명중하는 시점의 데미지)
2. FRadialDamageEvent: 폭발과 같은 범위 기반의 데미지
더보기
더보기
float ACharacter::TakeDamage
(
float DamageAmount,
FDamageEvent const& DamageEvent,
AController* EventInstigator,
AActor* DamageCauser
)
{
// 기본 데미지 적용
float ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
// 체력 감소 처리
Health -= ActualDamage;
if (Health <= 0.0f)
{
OnDeath(); // 캐릭터 사망 처리 함수
}
// 경우에 따라 캐릭터의 방어력, 저항력을 적용해 반환 가능
return ActualDamage;
}
- EventInstigator: 데미지를 유발한 플레이어나 AI를 제어하는 컨트롤러를 의미한다.
데미지의 출처가 누구인지 파악하고, 데미지와 관련된 추가 로직(경험치 부여 등)을 적용할 때 사용된다. - DamageCauser: 데미지를 유발한 실제 액터(폭탄, 총알, 화살 등)이다.
데미지를 유발한 오브젝트에 대한 특수 처리가 필요할 때 사용된다.
✅ UGameplayStatics::ApplyDamage
static float ApplyDamage
(
AActor* DamagedActor,
float BaseDamage,
AController* EventInstigator,
AActor* DamageCauser,
TSubclassOf<class UDamageType> DamageTypeClass
)
액터에 데미지를 입히는 기능을 제공하는 함수이다.
이 함수를 호출하면 해당 액터의 TakeDamage 함수가 자동으로 호출된다. 따라서 데미지를 처리하는 기본 흐름을 간단하게 구성할 수 있다.
- DamagedActor: 데미지를 받을 액터를 의미한다.
- BaseDamage: 데미지의 기본 값을 의미한다.
이 값은 최종 데미지로 그대로 적용되기도 하고, 추가 로직에 의해 변형될 수 있다. - EventInstigator: 데미지를 입힌 컨트롤러를 의미한다.
데미지를 입힌 주체를 파악할 때 사용된다. - DamageCauser: 실제 데미지를 발생시킨 액터를 의미한다.
예를 들어 플레이어가 적에게 총을 쏜 경우, 총알 액터가 이 DamageCauser가 된다. - DamageTypeClass: 데미지의 유형을 정의하는 클래스이다.
기본적으로 언리얼에 UDamageType이라는 클래스가 있고, 이를 상속하여 커스텀 데미지 타입을 정의할 수 있다.
예를 들어 폭발 데미지라면 UDamageType을 상속 받는 UExplosionDamageType 커스텀 클래스를 만드는 등.
📌 PlayerCharacter.h
UCLASS()
class APlayerCharacter : public ACharacter
{
GENERATED_BODY()
public:
APlayerCharacter();
UFUNCTION(BlueprintPure, Category = "Health")
float GetHealth() const { return Health; }
UFUNCTION(BlueprintCallable, Category = "Health")
void AddHealth(float Amount);
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
float MaxHealth;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
float Health;
void OnDeath();
virtual float TakeDamage(
float DamageAmount,
struct FDamageEvent const& DamageEvent,
AController* EventInstigator,
AActor* DamageCauser) override;
};
📌 PlayerCharacter.cpp
APlayerCharacter::APlayerCharacter()
{
MaxHealth = 100.0f;
Health = MaxHealth;
}
void APlayerCharacter::AddHealth(float Amount)
{
Health = FMath::Clamp(Health + Amount, 0.0f, MaxHealth);
}
void APlayerCharacter::OnDeath()
{
// 게임 종료 로직
}
float APlayerCharacter::TakeDamage
(
float DamageAmount,
FDamageEvent const& DamageEvent,
AController* EventInstigator,
AActor* DamageCauser
)
{
float ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
Health = FMath::Clamp(Health - DamageAmount, 0.0f, MaxHealth);
if (Health <= 0.0f)
{
OnDeath();
}
return ActualDamage;
}
📌 MineItem.cpp
void AMineItem::Explode()
{
TArray<AActor*> OverlappingActors;
ExplosionCollision->GetOverlappingActors(OverlappingActors);
for (AActor* Actor : OverlappingActors)
{
if (Actor && Actor->ActorHasTag("Player"))
{
UGameplayStatics::ApplyDamage
(
Actor,
ExplosionDamage,
nullptr,
this,
UDamageType::StaticClass()
);
}
}
DestroyItem();
}
- Actor: 오버랩된 대상 액터
- ExplosionDamage: 폭발 데미지
- nullptr: Mine액터 자체가 데미지를 입히는 것이기에 EventInstigator 컨트롤러가 없으므로 nullptr 전달
- this: 데미지를 입히는 주체가 되는 DamageCauser는 Mine 액터이므로 this 전달
- UDamageType::StaticClass(): 기본 데미지 타입 전달
'내배캠 > Unreal Engine' 카테고리의 다른 글
UI 위젯 설계와 실시간 데이터 연동 (0) | 2025.02.06 |
---|---|
Game State와 Game Mode (0) | 2025.02.04 |
가비지 컬렉션과 메모리 관리 (0) | 2025.01.31 |
Pawn에 Possess 하기 (0) | 2025.01.31 |
데이터 에셋과 데이터 테이블 (0) | 2025.01.28 |