📍 3주차 4강
- 필요한 것
Health MaxHealth(100) public:
// 2. 체력을 갖고 오는 함수
UFUNCTION(Blueprintpure, Category = "Health")
float GetHealth() const;
protected:
// 1. 체력
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
float MaxHealth;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
float Health;
get 전용 = BlueprintPure
ASpartaCharacter::ASpartaCharacter()
{
// 1. 체력 변수들 초기화
MaxHealth = 100.0f;
Health = MaxHealth;
}
// ...
// 2. GetHealth 함수 갖고 오기
float ASpartaCharacter::GetHealth() const
{
return Health;
}
UGamePlayStatics::ApplyDamage() - 데미지 입힘AActor::TakeDamage() - 데미지 받음protected:
// 1. 데미지 받는 함수 오버라이드
virtual float TakeDamage(
float DamageAmount, // 데미지 얼마나 입었나
struct FDamageEvent const& DamageEvent, // 데미지 유형 - 스킬에 따라 어떤 데미지?
AController* EventInstigator, // 데미지 누가 입힘? (지뢰를 심은 사람)
AActor* DamageCasuer) override; // 데미지를 일으킨 오브젝트 (지뢰)
void OnDeath(); // 2. 사망처리 함수
// 1. 데미지 받는 함수
float ASpartaCharacter::TakeDamage(
float DamageAmount,
struct FDamageEvent const& DamageEvent,
AController* EventInstigator,
AActor* DamageCasuer)
{
// 부모 클래스 거 호출
float ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCasuer);
Health = FMath::Clamp(Health - DamageAmount, 0.0f, MaxHealth);
UE_LOG(LogTemp, Warning, TEXT("Health decreased to: %f"), Health);
if (Health <= 0.0f)
{
OnDeath(); // 사망
}
return ActualDamage;
}
// 2. 사망 처리 함수
void ASpartaCharacter::OnDeath()
{
// 게임 종료 로직
}
Damage 차이
DamageAmount 나한테 들어온 데미지 (방어력 없다고 생각하면 됨, 찐 데미지)ActualDamage 내가 입은 데미지 (방어구 착용했거나 저항시스템 있으면 데미지 덜 입음)Clamp 함수
// 구조
타입 FMath::Clamp(타입 Value, 타입 Min, 타입 Max);
// 예시
float Result = FMath::Clamp(Score, 0.0f, 100.0f);
// 얼마 회복 받을지
UFUNCTION(BlueprintCallable, Category = "Heal")
void AddHealth(float Amount);
void ASpartaCharacter::AddHealth(float Amount)
{
Health = FMath::Clamp(Health + Amount, 0.0f, MaxHealth);
UE_LOG(LogTemp, Warning, TEXT("Health increased to: %f"), Health);
}
#include "SpartaCharacter.h"
void AHealingItem::ActivateItem(AActor* Activator)
{
// DestroyItem();
if (Activator && Activator->ActorHasTag("Player"))
{
// Activator가 Actor 클래스이므로 얘를 SpartaCharacter로 캐스팅 해야함
if (ASpartaCharacter* PlayerCharacter = Cast<ASpartaCharacter>(Activator))
{
PlayerCharacter->AddHealth(HealAmount);
}
DestroyItem();
}
}
#include "Kismet/GameplayStatics.h"
// ...
void AMineItem::Explode()
{
TArray<AActor*> OverlappingActors; // 범위 내 겹치는 액터 검색
ExplosionCollision->GetOverlappingActors(OverlappingActors);
// 범위 내 돌면서 태그 확인
for (AActor* Actor : OverlappingActors)
{
if (Actor && Actor->ActorHasTag("Player")) // Actor가 nullptr이 아니고 플레이어 태그가 있는지 확인
{
UGameplayStatics::ApplyDamage(
Actor, // 데미지를 받을 액터
ExplosionDamage, // 데미지의 양
nullptr, // 데미지를 유발한 주체
this, // 데미지를 입힌 액터
UDamageType::StaticClass() // 데미지의 유형 - 데미지 타입의 기본 유형을 class로 넘겨줌
);
}
}
DestroyItem();
}
→ ActorHasTag("Player") 조건이 통과되지 않아서 ApplyDamage() 호출도 안 된 듯... 플레이어 블루프린트에서 Actor Tag는 제대로 되어 있었음
// 이전 코드
if (Actor && Actor->ActorHasTag("Player"))
// 수정 후
if (Cast<ASpartaCharacter>(Actor))

#include "SpartaCharacter.h"
void AHealingItem::ActivateItem(AActor* Activator)
{
// DestroyItem();
if (Activator && Activator->ActorHasTag("Player"))
{
// Activator가 Actor 클래스이므로 얘를 SpartaCharacter로 캐스팅 해야함
if (ASpartaCharacter* PlayerCharacter = Cast<ASpartaCharacter>(Activator))
{
PlayerCharacter->AddHealth(HealAmount);
}
DestroyItem();
}
}

#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameStateBase.h"
#include "SpartaGameStateBase.generated.h"
UCLASS()
class SPARTAPROJECT_API ASpartaGameStateBase : public AGameStateBase
{
GENERATED_BODY()
public:
ASpartaGameStateBase(); // 생성자
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Score")
int32 Score;
UFUNCTION(BlueprintPure, Category = "Score")
int32 GetScore() const;
UFUNCTION(BlueprintCallable, Category = "Score")
void AddScore(int32 Amount);
};
#include "SpartaGameStateBase.h"
ASpartaGameStateBase::ASpartaGameStateBase()
{
Score = 0;
}
int32 ASpartaGameStateBase::GetScore() const
{
return Score;
}
void ASpartaGameStateBase::AddScore(int32 Amount)
{
Score += Amount;
}
#include "CoinItem.h"
#include "Engine/World.h" // GameState를 가져오기 위해 World 먼저 갖고 오기
#include "SpartaGameStateBase.h"
ACoinItem::ACoinItem() // 생성자
{
PointValue = 0; // 초기화, 부모클래스라서 0점, 자손클래스에서 본인에 해당하는 변수로 값을 넘겨 받음 <다형성>
ItemType = "DefaultCoin"; // 아이템 타입 초기화
}
void ACoinItem::ActivateItem(AActor* Activator)
{
if (Activator && Activator->ActorHasTag("Player"))
{
if (UWorld* World = GetWorld())
{
if (ASpartaGameStateBase* GameState = World->GetGameState<ASpartaGameStateBase>())
{
GameState->AddScore(PointValue);
}
}
DestroyItem();
}
}
#include "CoinItem.h"
#include "Engine/World.h" // GameState를 가져오기 위해 World 먼저 갖고 오기
#include "SpartaGameStateBase.h"
ACoinItem::ACoinItem() // 생성자
{
PointValue = 0; // 초기화, 부모클래스라서 0점, 자손클래스에서 본인에 해당하는 변수로 값을 넘겨 받음 <다형성>
ItemType = "DefaultCoin"; // 아이템 타입 초기화
}
void ACoinItem::ActivateItem(AActor* Activator)
{
if (Activator && Activator->ActorHasTag("Player"))
{
if (UWorld* World = GetWorld())
{
if (ASpartaGameStateBase* GameState = World->GetGameState<ASpartaGameStateBase>())
{
GameState->AddScore(PointValue);
}
}
DestroyItem();
}
}

코인 블루프린트 들어가서 값 직접 설정하기
짜잔~ 해결 완료
1️⃣ UPROPERTY 변수들 (리플렉션 변수)
2️⃣ 생성자 / BeginPlay / Tick 등 오버라이드 함수들 (가상함수 포함)
3️⃣ UFUNCTION 함수들 (리플렉션 함수)
4️⃣ 일반 함수들 (private helper 등)
UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// 1. 리플렉션 변수
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Health;
// 2. 가상 함수 (오버라이드)
virtual void BeginPlay() override;
// 3. 리플렉션 함수
UFUNCTION(BlueprintCallable)
void Heal(float Amount);
// 4. 그냥 함수
void LogHealth();
};