[ActorComponent] 캐릭터 스킬, 스텟 로직 컴포넌트 구조로 만들기

2025. 4. 8. 21:21·Dev./UE 언리얼 엔진

📒학습 내용

🧩 언리얼 엔진 컴포넌트 시스템 이해하기

 

게임 코드 리팩터링: 5가지 핵심 결정 원칙

💭회고 🫧Clean Code :: 클린 코드 가이드💭회고개발에서 가장 중요한 역량 중 하나인 '클린 코드'에 대해 정리해보았다. 특히 언리얼 엔진 환경에서 어떻게 코드 품질을 높일 수 

raindrovvv.tistory.com

언리얼 엔진은 컴포넌트 기반 아키텍처를 사용한다. 이는 게임 오브젝트(Actor)가 여러 기능 블록(Component)으로 구성된다는 의미...!

두 가지 주요 컴포넌트 유형

  1. UActorComponent : 비주얼 요소가 없는 순수 로직용 컴포넌트
  2. USceneComponent : 3D 공간에 위치하는 시각적/물리적 컴포넌트

가장 기본적인 원칙: 위치가 필요한가, 필요하지 않은가?

컴포넌트 선택 가이드라인

사용 목적 권장 컴포넌트 예시
순수 게임 로직 UActorComponent 스텟 시스템, 버프/디버프 관리, 인벤토리
시각적/위치 기반 요소 USceneComponent 메시, 파티클, 충돌 영역

💡 UActorComponent: 비주얼 없는 순수 로직

UActorComponent는 다음과 같은 상황에서 최적의 선택:

  • 시각적 표현이 필요 없는 게임 시스템
  • 위치나 회전 정보가 불필요한 기능
  • 순수 데이터 처리 및 계산이 주 목적인 경우
// 스텟 컴포넌트 예시
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class GAME_API UCharacterStatComponent : public UActorComponent
{
    GENERATED_BODY()
    
private:
    // 캐릭터 기본 스텟
    UPROPERTY(EditAnywhere, Category = "Stats", meta = (AllowPrivateAccess = "true"))
    float BaseHealth = 100.0f;
    
    UPROPERTY(EditAnywhere, Category = "Stats", meta = (AllowPrivateAccess = "true"))
    float BaseAttackPower = 10.0f;
    
    // 현재 스텟 값 (버프 등이 적용된 최종값)
    UPROPERTY(VisibleAnywhere, Category = "Stats", meta = (AllowPrivateAccess = "true"))
    float CurrentHealth;
    
    UPROPERTY(VisibleAnywhere, Category = "Stats", meta = (AllowPrivateAccess = "true"))
    float CurrentAttackPower;
    
public:
    // 생성자
    UCharacterStatComponent();
    
    // 게임 시작시 호출
    virtual void BeginPlay() override;
    
    // 스텟 관련 주요 함수들
    float GetAttackPower() const;
    float GetCurrentHealth() const;
    void TakeDamage(float DamageAmount);
    
    // 버프 적용 함수
    void ApplyAttackBuff(float Multiplier, float Duration);
};

UActorComponent의 장점

  1. 가벼운 메모리 사용: 변환 정보(Transform)가 없어 메모리 사용량이 적다.
  2. 단순한 구조: 계층 구조나 부착(Attachment) 개념이 없어 관리가 간단.
  3. 성능 최적화: 렌더링이나 물리 연산과 무관하여 CPU 부하가 적다.

🌟 USceneComponent: 3D 공간에서의 위치가 중요할 때

SceneComponent는 다음과 같은 경우에 사용:

  • 게임 월드 내에서 특정 위치에 존재해야 하는 요소
  • 다른 컴포넌트와의 계층 구조가 필요한 경우
  • 위치, 회전, 크기 조절이 필요한 기능
// 스킬 이펙트 컴포넌트 예시
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class GAME_API USkillEffectComponent : public USceneComponent
{
    GENERATED_BODY()
    
private:
    // 스킬 이펙트용 파티클 시스템
    UPROPERTY(EditAnywhere, Category = "Effects", meta = (AllowPrivateAccess = "true"))
    UParticleSystemComponent* SkillParticle;
    
    // 스킬 범위 표시용 메시
    UPROPERTY(EditAnywhere, Category = "Effects", meta = (AllowPrivateAccess = "true"))
    UStaticMeshComponent* RangeIndicatorMesh;
    
public:
    // 생성자
    USkillEffectComponent();
    
    // 스킬 이펙트 활성화
    void ActivateSkillEffect(float Duration);
    
    // 스킬 범위 표시
    void ShowRangeIndicator(float Radius);
};

USceneComponent의 특징

  1. 트랜스폼 정보: 위치, 회전, 크기 정보를 가진다.
  2. 계층 구조: 부모-자식 관계를 형성할 수 있어 복잡한 구조 구현이 가능.
  3. 시각적 디버깅: 에디터에서 시각적으로 위치와 방향을 확인할 수 있다.

⚔️ 실전 적용: 캐릭터 스킬 및 스텟 시스템 구현하기

버프 컴포넌트 구현 예시

// BuffComponent.h
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class GAME_API UBuffComponent : public UActorComponent
{
    GENERATED_BODY()
    
private:
    // 활성화된 버프 목록
    UPROPERTY()
    TArray<FBuffInfo> ActiveBuffs;
    
    // 버프 업데이트를 위한 타이머 핸들
    FTimerHandle BuffUpdateTimerHandle;
    
public:
    // 생성자
    UBuffComponent();
    
    // 게임 시작시 호출
    virtual void BeginPlay() override;
    
    // 버프 적용 함수
    void ApplyBuff(EBuffType BuffType, float Value, float Duration);
    
    // 현재 버프 상태 확인
    float GetCurrentBuffValue(EBuffType BuffType) const;
    
    // 버프 업데이트 함수 (타이머에 의해 주기적으로 호출)
    void UpdateBuffs();
    
    // 특정 버프 제거
    void RemoveBuff(EBuffType BuffType);
};

스텟 컴포넌트와 버프 컴포넌트의 연동

// 캐릭터 클래스 내부에서의 컴포넌트 초기화
AMyCharacter::AMyCharacter()
{
    // 스텟 컴포넌트 생성
    StatComponent = CreateDefaultSubobject<UStatComponent>(TEXT("StatComponent"));
    
    // 버프 컴포넌트 생성
    BuffComponent = CreateDefaultSubobject<UBuffComponent>(TEXT("BuffComponent"));
}

// 스킬 사용 시 버프 적용 예시
void AMyCharacter::UseSkill(int32 SkillIndex)
{
    // ... 스킬 사용 로직 ...
    
    // 버프 적용
    if (BuffComponent)
    {
        // 공격력 30% 증가 버프를 10초간 적용
        BuffComponent->ApplyBuff(EBuffType::AttackPower, 1.3f, 10.0f);
    }
    
    // 스텟 업데이트 (버프 반영)
    if (StatComponent)
    {
        // 버프를 고려한 최종 공격력 계산
        float FinalAttackPower = StatComponent->BaseAttackPower * 
            BuffComponent->GetCurrentBuffValue(EBuffType::AttackPower);
        
        StatComponent->SetCurrentAttackPower(FinalAttackPower);
    }
}
🔍실무 팁 : 실제 프로젝트에서는 스텟 컴포넌트와 버프 컴포넌트 간의 의존성을 최소화하는 것이 좋다. 이벤트 기반 통신이나 인터페이스를 활용하여 두 컴포넌트가 직접적으로 서로를 참조하지 않도록 설계하면 유지보수가 더 용이해진다.

🌐 리플리케이션(Replication) 구현하기

멀티플레이어 게임에서는 컴포넌트의 상태를 네트워크로 동기화해야 한다.

// StatComponent.h의 생성자 내부
UStatComponent::UStatComponent()
{
    // 컴포넌트 리플리케이션 활성화
    SetIsReplicatedByDefault(true);
}

// 리플리케이션 속성 설정
void UStatComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    
    // 현재 체력을 모든 클라이언트에게 복제
    DOREPLIFETIME(UStatComponent, CurrentHealth);
    
    // 공격력은 소유 클라이언트에게만 복제
    DOREPLIFETIME_CONDITION(UStatComponent, CurrentAttackPower, COND_OwnerOnly);
}

// 리플리케이션 이벤트 처리
UFUNCTION()
void UStatComponent::OnRep_CurrentHealth()
{
    // 체력 변경 시 UI 업데이트 등의 로직
    if (OwnerCharacter)
    {
        // 캐릭터 상태 UI 업데이트
        OwnerCharacter->UpdateHealthUI(CurrentHealth);
    }
}

🔵블루프린트와의 통합

C++ 컴포넌트를 블루프린트에서 활용하는 방법

// StatComponent.h에 블루프린트 호출 가능 함수 추가
UFUNCTION(BlueprintCallable, Category = "Stats")
float GetCurrentHealth() const { return CurrentHealth; }

UFUNCTION(BlueprintCallable, Category = "Stats")
void SetCurrentHealth(float NewHealth);

// 블루프린트에서 이벤트 발생시키기
UFUNCTION(BlueprintImplementableEvent, Category = "Stats")
void OnHealthChanged(float NewHealth, float OldHealth);

// C++ 내부에서 이벤트 호출
void UStatComponent::SetCurrentHealth(float NewHealth)
{
    float OldHealth = CurrentHealth;
    CurrentHealth = FMath::Clamp(NewHealth, 0.0f, MaxHealth);
    
    // 블루프린트에서 구현 가능한 이벤트 발생
    OnHealthChanged(CurrentHealth, OldHealth);
}

🟣오늘의 옵시디언 현황

'Dev. > UE 언리얼 엔진' 카테고리의 다른 글

[TIL_250410] 프로젝트 진행 상황 정리  (0) 2025.04.10
캐릭터 스킬, 스텟 로직 컴포넌트 구조로 만들기 (응용)  (0) 2025.04.09
🚨트러블슈팅 :: Git 잠금 파일 오류 해결 가이드  (0) 2025.04.07
템플릿을 활용한 게임 개발 :: HUD_CharacterSelectPanel, HUD_CharacterInfo, HUD_MapTile  (0) 2025.04.04
템플릿을 활용한 게임 개발 :: HUD_Menus, MainMenu // BP_WidgetMacros  (1) 2025.04.03
'Dev./UE 언리얼 엔진' 카테고리의 다른 글
  • [TIL_250410] 프로젝트 진행 상황 정리
  • 캐릭터 스킬, 스텟 로직 컴포넌트 구조로 만들기 (응용)
  • 🚨트러블슈팅 :: Git 잠금 파일 오류 해결 가이드
  • 템플릿을 활용한 게임 개발 :: HUD_CharacterSelectPanel, HUD_CharacterInfo, HUD_MapTile
raindrovvv
raindrovvv
raindrovvv 님의 블로그 입니다.
  • raindrovvv
    raindrovvv 님의 블로그
    raindrovvv
  • 전체
    오늘
    어제
    • 분류 전체보기 (100) N
      • Dev. (93) N
        • UE 언리얼 엔진 (48)
        • Unity 유니티 (0)
        • Wwise 와이즈 (7) N
        • 게임 네트워크 (8)
        • 그래픽스 Graphics (22) N
        • 프로젝트 (4)
        • 기타 개발 관련 (4)
      • Computer Science (0)
        • 하드웨어 HW (0)
        • 소프트웨어 SW (0)
        • 통신 (0)
        • 데이터 (0)
      • 블로그 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    TA
    고라니
    Wwise
    게임음향
    게임네트워크
    unrealengine
    언리얼엔진
    언리얼
    그래픽스
    네트워크
    오디오미들웨어
    와이즈
    UE
    AI
    게임개발
    게임사운드
    셰이더
    Unreal
    머티리얼
    게임
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
raindrovvv
[ActorComponent] 캐릭터 스킬, 스텟 로직 컴포넌트 구조로 만들기
상단으로

티스토리툴바