Make Unreal REAL.
article thumbnail
ARAG (A Really Awesome Game) Commit b3af3

 

이번 작업 결과는 다음과 같다.

[몬스터]

  • AI 몬스터 구현
  • 몬스터의 속성, 애니메이션을 데이터 에셋으로 관리하도록 작성

[캐릭터]

  • 캐릭터 클래스의 GAS, 데이터 관련 코드를 컴포넌트로 분할
  • 캐릭터의 속성, 애니메이션을 데이터 에셋으로 관리하도록 변경
  • 캐릭터의 피격, 죽음 구현
  • 캐릭터 보행 Blendspace 자연스럽게 수정

[무기]

  • 활 착용 시 화살이 없으면 근접 공격 하도록 수정
  • 활 조준 시 조준선 표시
  • 화살을 앞 방향이 아닌 카메라가 보는 방향으로 쏘도록 수정
  • 활 조준 시 Aim Offset 적용

[버그 수정]

  • 화살집의 화살이 몬스터에게 데미지를 입히던 버그 수정

 

 

이번 작업에서 느낀 점 👨‍💻👨‍💻👨‍💻
  • 역시 AI 구현은 FSM을 활용하는 게 가장 편한 것 같다.
  • 데이터 에셋으로 몬스터의 속성을 관리하니, 다른 몬스터를 빠르게 추가할 수 있었다.
  • 특정 역할을 담당하는 코드(기본 속성값 관리 등)는 컴포넌트로 분할해 관리하면 좋다.
  • 코드 문제가 아닌 엔진 자체 문제로 크래시가 발생하는 경우가 생각보다 잦다..

 

AI는 Behavior Tree를 이용해 구현했는데, Tree 형태가 아닌 마인드맵 형태로 제작했다.

  • 각 상태에서 수행하는 로직을 명확하게 구분하기 위함이다.
  • 물론, Service 대신 Decorator를 통해 공격 거리나 이동 반경을 확인해 Tree 형태로 구성할 수도 있다.

 

 

몬스터는 다음과 같은 상태와 속성을 가지며, 애니메이션과 속성은 데이터 에셋을 통해 관리한다.

 

 

AI Controller는 폰에 빙의할 때 데이터 에셋으로부터 읽어들인 속성 값으로 AI의 시야 설정을 갱신한다.

 

 

Modify AIPerception Sight Range at runtime [4.7.6]

I’m trying to manipulate my AI’s vision radius at game time. This could be caused by a buff, upgrade or pickup. As it stands I see a get Sight Radius but not a set. Am I missing something or is it just not available until 4.8 (or maybe later)

forums.unrealengine.com

 

플레이어 감지는 AI Perception 컴포넌트를 이용하고, 감지된 플레이어가 있으면 Target으로 설정한 후 추적(Chase) 상태로 전환한다.

  • 멀티 플레이어를 고려해 현재 감지된 플레이어 수를 nDetectedTargets 속성으로 관리하도록 했다.

 

 

추적(Chase) 상태에서는 공격 거리(AttackRange) 만큼 타겟에 가까워졌으면 공격(Attack) 상태로 전환하고, 이동 반경(MaxTraceDistance)을 벗어났으면 복귀(Return) 상태로 전환한다.

  • 거리를 비교할 때 굳이 제곱근을 계산할 필요는 없으므로, 최적화를 위해 FVector::Distance() 함수 대신 FVector::DistSquared() 함수를 사용했다.

 

 

이동 Blendspace, 공격 애니메이션 몽타주, 죽음/피격 애니메이션은 AI를 구성하는 애니메이션의 공통된 부분이라고 생각했기 때문에 데이터 에셋으로 관리했다.

  • 덕분에 다른 몬스터를 추가할 때, 다른 애니메이션이 지정된 데이터 에셋으로 교체만 해주면 애니메이션 BP를 수정하지 않고 그대로 재활용할 수 있었다.

 

 

몬스터의 상태는 여러 곳에서 사용되고 중요한 속성이기 때문에 각 오브젝트가 다른 값을 가지면 곤란하다.

 

그래서 몬스터 클래스에 상태를 변경하는 SetState() 함수를 만들고, 다른 클래스에서는 OnStateChanged라는 델리게이트에 상태를 받아오는 로직을 등록해 동기화시키기로 했다.

  • 이렇게 구성하면 SetState() 함수를 통해 상태가 변경될 때마다 OnStateChanged 델리게이트가 발동해 모든 오브젝트는 동일한 몬스터 상태를 유지할 수 있다.
  • 이런 구현 방식을 옵저버 패턴이라고 한다.
    (멀티캐스트 델리게이트 자체가 옵저버 패턴이긴 하다.)

 

 

캐릭터 BP에 간단한 로직을 구현해, 런타임 도중 무기를 교체하는 테스트도 진행했다.

 

 

User Widget 클래스에서 UWidget::SetVisibility() 함수의 래퍼 함수를 제공하도록 하여, 다른 클래스에서 간편하게 UI의 가시성을 조정할 수 있도록 했다.

 

 

현재 피격은 데미지 프레임워크를 통해 처리하고 있고 HP는 임시 변수로 관리하고 있다.

  • 나중에 Gameplay Effect와 Attribute로 변경할 예정이다.

 

 

작업 도중 마주했던 문제들 👇👇👇

 

BP에서 액터에 추가한 컴포넌트가 Details 패널에 아무 정보도 뜨지 않고 NULL인 문제가 있었다.

BP 오류이다.
생성자에서 컴포넌트를 생성해 할당하는 부분을 주석처리하고 컴파일 한 후, 다시 주석 해제하고 컴파일 해주면 해결된다.
만약 Character Movement 컴포넌트 같은 기본 컴포넌트에 이런 일이 생기면, 부모 클래스를 다른 클래스로 변경했다가 Reparent하는 수 밖에 없다.

 

C++ 클래스 이름을 함부로 바꾸면 BP 링크가 깨진다.

DefaultEngine.ini 파일에 ActiveClassRedirects 속성을 통해 기존 이름을 새로운 이름으로 Redirect하도록 지정해 해결할 수 있다.
이후 Binaries 폴더를 삭제한 다음 다시 컴파일 해주면 된다.

 

같은 이름을 가진 델리게이트 정의의 두 헤더를 동시에 include하면 충돌이 발생한다.

A, B 클래스 모두에 FOnDamaged라는 델리게이트를 정의하면 충돌로 인해 컴파일 오류가 발생한다.
따라서, 델리게이트 이름은 충돌을 최소화하도록 상세하게 정의하는 것이 좋다.

 

캐릭터와 달리 AI는 PossessdBy() -> PostInitializeComponents() 순으로 호출되었다.

아마, 레벨에 미리 배치된 몬스터에 AI Controller가 빙의해서 그런 것 같다.

 

몬스터가 피격 애니메이션 재생 시 메시가 보이지 않는 버그가 있었다.

피격 애니메이션을 No Additive로 설정해 해결했다.
 

Player character disappears when Jumping

Thanks! It got fixed by checking the root lock tick box in the jump animation

forums.unrealengine.com

 

몬스터를 추가할 때, 같은 애니메이션 BP를 사용하면서 애니메이션 정보를 가진 데이터 에셋만 교체하면 되도록 구현했지만, Skeleton이 다르면 어차피 같은 ABP를 쓸 수 없었다.

그래도 ABP의 노드를 복사하고 변수만 똑같이 추가해주면 빠르게 다른 몬스터를 추가할 수 있었다.

profile

Make Unreal REAL.

@diesuki4

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그