3 분 소요

Unreal/C++ 과제 8 - 게임 루프 및 UI 재설계

과제 소개 및 목표

게임 플레이 및 UI/UX 리뉴얼을 통한 시각적 완성도 높이기

구현 기능


  • Level이 올라가며 Enemy Spawn 시간이 짧아지는 웨이브 구조
  • Player에 체력, 점수, 시간에 대한 정보 표기
  • Enemy 사망 시 점수 와 사망 위치에 랜덤한 아이템 드랍
  • 디메리트 아이템 2개 구현
    (플레이어 슬로우 아이템 + 플레이어 대미지 아이템)
    (다만 플레이어 대미지 아이템은 영상에서 찍히지는 않았음)
  • 슬로우 아이템 적용 시, 플레이어에게 이펙트를 적용하여 시각적 효과 적용
  • 레벨이 올라갈수록 Enemy Spawn 시간이 짧아짐
  • Enemy는 피격시 자신의 체력을 보여주며 일정 시간 이후 다시 꺼지게 됨

클래스 설명

ATask8Character
- TopDown 형식의 플레이어 조작 캐릭터 클래스
- Game Ability System의 테스트를 위하여 UAbilitySystemComponent와 TaskAttributeSet을 포함
- 사격 기능을 위한 UGameplayAbility 추가

ATask8PlayerController
- 조작을 위한 Input Action과 위젯을 포함하는 클래스

ATaskGameState
- GameManager 역할을 겸하는 GameState 클래스
- 레벨 스타트, 적 생성 및 아이템 스폰 매니저를 관리

AItemSpawnManager
- 특정 Vector에 랜덤한 아이템을 생성해주는 SpawnManager 클래스

Item
- 기본적으론 강의에서 주어진 클래스와 매우 유사
- 다만 Healing의 경우, AttributeSet 에 적용되도록 수정
  (Heal과 관련된 클래스는 BP에서 간략히 구현 - GamePlayEffect)

GA_Fire
- Lyra의 사격 기능을 매우 간단하게 카피한 버전
- 라인 트레이스를 통해 피격된 물체의 어빌리티 시스템 컴포넌트를 확인하고
  대미지 클래스를 적용시킨다
  (대미지 클래스는 BP쪽에서 간략하게 구현)
- 이후 무기의 OnFire 를 호출하여 BP 쪽에서 이펙트를 처리시키는 역할

UTaskAttributeSet
- 체력과 최대체력을 가지는 AttributeSet
- 캐릭터와 Enemy에 적용되어 체력을 관리하는 용도

Enemy
- 플레이어에게 다가와 자폭하는 적 클래스
- 원래는 공격 모션을 넣으려 했으나 에셋을 구할수 없어 자폭으로 대체
- 그렇기에 행동이 매우 간략해 졌기에
  별다른 BT 나 블랙보드 없이 Tick으로 간략히 플레이어를 추격하도록 구현
- 플레이어와는 달리 피격시 HP 위젯이 보이며,
  일정 시간이후 사라지도록 하였다

트러블 슈팅 1 - 체력이 제대로 깎이지 않는다?

Image

분명 LineTrace를 통해
Enemy가 권총의 사격 범위 안에 들어갔으나
피격 후,
‘속도’가 초기화 되지 않고 그대로 달려왔다

또한 플레이어 역시, Enemy의 자폭에 ‘Jump’하지 않는 상황

나는 TaskAttribute 측에서
아래와 같은 코드 방식을 취하면
‘세팅’이 잘 되는줄 알았다

AbilitySystem->InitAbilityActorInfo(this, this);

if (AbilitySystem)
{
	const FGameplayAttribute HealthAttr = UTaskAttributeSet::GetHealthAttribute();
	AbilitySystem->SetNumericAttributeBase(HealthAttr, StartHealth);
	const FGameplayAttribute MaxHealthAttr = UTaskAttributeSet::GetMaxHealthAttribute();
	AbilitySystem->SetNumericAttributeBase(MaxHealthAttr, StartHealth);
}

---

const FGameplayAttribute HealthAttr = UTaskAttributeSet::GetHealthAttribute();
ASC->ApplyModToAttributeUnsafe(HealthAttr, EGameplayModOp::Additive, -Damage);

그런데 결국 ASC에서 AttributeSet 자체를 ‘가지고 있어야 하고’
저러한 ‘Apply’를 ‘정상적’으로 적용할 수 있다는 사실을 나중에 깨달았다
(가지고 있지도 않은 것을 ‘세팅’하려 하니…)

ASC = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("ASC"));
AttributeSet = CreateDefaultSubobject<UTaskAttributeSet>(TEXT("AttributeSet"));

Ability System Component를 생성한 후
AttributeSet 역시 제대로 생성해야 한다

  • ASC 생성 후, AttributeSet을 생성하면
    자동 부착이 됨

트러블 슈팅 2 - 생성한 적이 떨어지지 않는다?

Image

SpawnActor를 통해 Enemy를 ‘궁중’에서 생성하니
매우 이상하게도 전혀 떨어지지 않았다

처음에는 CharacterMovement 쪽의 문제인가 싶어
Simulate Physics 옵션을 설정해주었으나
땅에 도착한뒤 비자연스러운 움직임 등이 발생하는 문제가 존재하였다

그런데 매우 이상하게도
‘에디터’에서 드래그한 경우는 궁중에 있어도 ‘정상적’으로 떨어지고
원하는 대로 Enemy가 동작하였다

그렇기에 곰곰히 생각한 결과…

SpawnActor 가 ‘컨트롤러’를 빙의 시켜 주진 않는다 라는
너무나 당연한 것을 그제서야 깨달았다

Enemy BeginPlay()

if (Controller == nullptr)
{
	// AIController 를 Spawn 시켜 빙의
	SpawnDefaultController();
}

컨트롤러를 빙의시켜 주니
CharacterMovement가 다시 정상적으로 동작하며
‘에디터’에서 드래그한 것처럼 잘 동작한다!

후기

개인적으로 GAS 관련하여 한번 알아보고 싶었기에
짧게 구현해본 프로젝트이다
(과제…에 이걸 시도한 것이 좋은 선택인지는 모르겠지만)

Lyra 쪽에서는 생각보다 얽혀있는게 많았지만
분리해서 보아도 생각보다 응용할 부분이 많아보이는 좋은 시스템이였다

다만 삽질이 많았기에
정작 과제의 주요 요소인

  • 게임 플레이 개선(아이템 인터페이스 + 멀티 웨이브)
  • UI/UX 개선 (HUD / 메뉴)

부분을 소홀히 한 것이 실수라 느낀다
(해당 부분에 대한 구현이 가장 마지막에 있었던 것이…)

개인적으로 한 삽질 목록

  • 트러블 슈팅 1,2 를 해결해보려고 무단한 검색과 탐색, 시행착오
  • AI에 공격 기능을 추가하려 Mixamo를 뒤적거리고 막상 적용하니 Bone 착오로 인한 쓸수 없는 상황이기에
    기획 내용 변경
  • Lyra 프로젝트의 GA_Fire 부분 분석
  • Lyra 프로젝트의 리소스를 가져다 쓰던 중 ABP의 문제로 인해
    기존 프로젝트에 주어진 ABP로 대체
  • 슬로우 이펙트를 어떻게 구현할지 검색 및 탐색 및 시행착오

절대 핑계가 아니다

원래는 게임 내용 부분이 더 빠르게 구현할 줄 알았고
명절 연휴를 이용하기에 좀 더 웅대한 결과물을 기대하였으나….

여러 삽질 + 연휴의 다양한 일로 인하여
조금 아쉬운 결과물이 된 느낌이다

설계 구조를 제대로 짜지 못한게 가장 아쉽지만
그래도 GAS를 한번쯤 만져보고 싶었기에 그 부분은 만족하는 프로젝트였다

댓글남기기