Unreal 개발 본 캠프 57일차

HappyCircle·2026년 2월 23일

Unreal 개발

목록 보기
74/163

📘 TIL –연속 부분 수열 합의 개수, 몬스터 UI/사운드 적용 및 피격·사망 애니메이션 안정화


🧠 1️⃣ 코딩테스트 – 연속 부분 수열 합의 개수 (원형 수열)

📌 문제 핵심

  • 원형 수열
  • 모든 연속 부분 수열 합
  • 서로 다른 합의 개수

🔥 구조적 해결 전략

1️⃣ 원형 → 선형 변환

int n = elements.size();
vector<int> arr2(2*n);

for (int i = 0; i < n; i++)
{
    arr2[i] = elements[i];
    arr2[i+n] = elements[i];
}

2️⃣ Prefix Sum 생성

vector<int> ps(2*n + 1, 0);

for (int i = 0; i < 2*n; i++)
{
    ps[i+1] = ps[i] + arr2[i];
}

3️⃣ 부분합 계산

unordered_set<int> sums;

for (int len = 1; len <= n; len++)
{
    for (int start = 0; start < n; start++)
    {
        int end = start + len;
        int sum = ps[end] - ps[start];
        sums.insert(sum);
    }
}

🧠 인사이트

  • 원형을 직접 처리하지 말 것
  • 누적합으로 반복 계산 제거
  • 시간복잡도 O(n²) 안정적으로 통과

🎮 2️⃣ 몬스터 신규 에셋 추가

📌 목표

  • 새로운 몬스터 타입 추가
  • 기존 스폰 시스템에 자연스럽게 연결
  • AnimSet / TypePresetTable과 연동

🔧 적용 흐름

1️⃣ MonsterClass 매핑 추가

TMap<EMonsterType, TSubclassOf<APotatoMonster>> MonsterClassByType;

신규 타입 Enum 추가 후 TMap에 연결.


2️⃣ TypePresetTable 행 추가

  • BaseHP
  • AttackDamage
  • MoveSpeed
  • AnimSet 참조

3️⃣ FinalStats 생성 후 Monster에 주입

Monster->InitFromStats(FinalStats);

🧠 설계 의미

신규 몬스터는 코드 수정 없이 Data 중심으로 확장 가능해야 한다.


🎮 3️⃣ 몬스터 체력바 적용 완료

📌 구조

  • 몬스터 클래스에 WidgetComponent 추가
  • 체력바 위젯 WBP_HealthBar 연결

몬스터 클래스 내부

UPROPERTY(VisibleAnywhere)
UWidgetComponent* HealthBarWidget;

BeginPlay에서 초기화

if (HealthBarWidget)
{
    HealthBarWidget->SetWidgetSpace(EWidgetSpace::World);
}

체력 감소 시 업데이트

void APotatoMonster::OnDamaged(float NewHP)
{
    if (UHealthBar* HB = Cast<UHealthBar>(HealthBarWidget->GetUserWidgetObject()))
    {
        HB->UpdateHealth(CurrentHP / MaxHP);
    }
}

🎯 주요 이슈

  • WidgetClass 설정 누락 시 Details 창 비어 있음
  • World Space 설정 안 하면 화면에 안 보임
  • Z 오프셋 조정 필요

🎮 4️⃣ 데미지 텍스트 UI 적용

📌 구조

  • DamageTextPoolActor 사용
  • PrewarmCount 만큼 미리 생성
  • SpawnDamageText 호출 시 재사용

호출 구조

DamageTextPool->SpawnDamageText(
    Damage,
    WorldLocation,
    StackIndex
);

위치 계산

FVector Origin, Extent;
Target->GetActorBounds(true, Origin, Extent);

FVector SpawnLoc = Origin + FVector(0,0,Extent.Z);

텍스트 설정

TextBlock->SetText(FText::FromString(FString::FromInt(Damage)));

🎯 개선 포인트

  • 연타 시 StackIndex로 위치 분산
  • Bounds 기반 위치 보정
  • 숫자 변환 로직 점검

🎮 5️⃣ 사운드 에셋 적용 작업 중

📌 기본 적용

UGameplayStatics::PlaySoundAtLocation(
    this,
    HitSFX,
    GetActorLocation()
);

🔥 중복 재생 방지

if (Now - LastHitSFXTime < 0.1f)
    return;

🧠 고려 사항

  • 발소리 타입 분기 필요
  • 사망 후 사운드 중복 방지 필요
  • 글로벌 사운드 버짓 설계 고려

🎮 6️⃣ 몬스터 피격 애니메이션 버그 수정

📌 문제

  • HitReact 과도 재생
  • 이동과 충돌
  • 복귀 상태 꼬임

🔧 해결

1️⃣ 쿨다운 적용

if (Now - LastHitReactTime < HitReactCooldown)
    return;

2️⃣ 피격 중 공격 방지

if (bIsHitReacting)
    return;

3️⃣ 일정 시간 후 복귀

GetWorldTimerManager().SetTimer(
    HitReactResumeTH,
    this,
    &APotatoMonster::ResumeFromHit,
    0.3f,
    false
);

🎮 7️⃣ 사망 애니메이션 버그 수정

📌 Die() 개선 구조

void APotatoMonster::Die()
{
    if (bIsDead) return;
    bIsDead = true;

    StopAIForDead();

    GetCharacterMovement()->StopMovementImmediately();
    GetCharacterMovement()->DisableMovement();

    SetActorEnableCollision(false);

    if (AnimInst && AS->DeathMontage)
    {
        float Len = AnimInst->Montage_Play(AS->DeathMontage);
        SetLifeSpan(Len);
    }
}

🎯 핵심

  • bIsDead 플래그 최우선 체크
  • AI 완전 정지
  • Movement 완전 정지
  • Collision 제거
  • 몽타주 길이 기반 정리

🎯 8️⃣ 전체 정리

🧠 코딩테스트

  • 선형화
  • 누적합
  • 중복 제거

🎮 게임 개발

  • 신규 몬스터 데이터 기반 확장
  • 체력바 + 데미지 텍스트 UI 적용 완료
  • 사운드 적용 구조 정리 중
  • 피격/사망 애니메이션 상태 안정화
  • 상태 기반 플래그 관리 강화

profile
개발합시다!

0개의 댓글