Game Development/Devlog

[UE5] 적 AI 추가, 핵심 기능 구현 완료 (프로젝트ASR - 개발일지5)

Dlaiml 2024. 9. 14. 14:49

저번 포스팅 이후 개발일지를 블로그에 따로 작성하지 않았다. 프로젝트 두 개를 병행하고 있어 따로 정리할 시간이 많이 없었다. 대신 유튜브와 Git에 이를 기록하고 있다.

 

DeepUnreal

 

www.youtube.com

 

GitHub - yjunej/ProjectASR: ProjectASR - Developed with Unreal Engine 5.4

ProjectASR - Developed with Unreal Engine 5.4. Contribute to yjunej/ProjectASR development by creating an account on GitHub.

github.com

 

블로그에는 기능과 코드대신 개발하면서 고민한 부분, 겪었던 문제들에 대해 이야기해보려 한다.

 

전투 시스템 

게임의 기본 전투 시스템은 HitInterface를 상속하는 클래스의 객체가 공격 애니메이션을 실행하고 Trace를 수행하는 AnimNotify가 Fire 되면 Trace 이후 충돌이 일어난 객체가 HitInterface를 상속하고 있다면 피격 함수인 GetHit을 호출하는 보편적인 방식을 사용하고 있다.

충돌 결과인 FHitResult만 사용하다가 대미지, 공격 타입, 사운드, 이펙트를 모두 전달할 수 있도록 구조체인 FHitData를 따로 정의하였고 parameter로 추가하였다.

 

공격타입, 대미지, 사운드, 이펙트 모두 공격자가 정의하지만 피격받은 대상이 재생할 애니메이션은 해당 정보를 토대로 피격자가 결정하도록 하였다.

공중에 떠있는 상태라면 공중에서 피격당하는 애니메이션을 재생하도록 GetHit 함수에서 피격자가 처리하고 사망, 스턴과 같은 우선순위가 높은 애니메이션이 재생중일 때는 일반 피격 애니메이션을 무시하거나 물리엔진을 활용하여 피격당한 부위의 Bone에만 작은 Transform을 주는 방식을 사용하기 위함이다.

 

매번 타격받을 때마다 적이 피격 애니메이션을 재생한다면 플레이어가 공격속도가 빠를 경우 적은 계속 경직 상태에서 벗어날 수 없게 된다. 약 20개 정도의 게임을 참고하였는데 이는 게임 디자인에 달린 것으로 보스와의 전투가 아닌 일반 적과의 전투에서 이를 허용하는 게임도 많았다.

 

 

AnimNotify를 사용하는 현재 시스템에서는 애니메이션 재생 중 적의 State는 바뀌지 않고 애니메이션을 재생하는 것 밖에 할 수 없게된다. 앞으로 추가될 보스의 전투, 전투 시스템의 확장을 위해 HitReactionState를 추가하였다.

 

UENUM(BlueprintType)
enum class ECombatState : uint8
{
	ECS_None		UMETA(DisplayName = "Default State"),
	ECS_Attack		UMETA(DisplayName = "Attack"),
	ECS_Dodge		UMETA(DisplayName = "Dodge"),
	ECS_Guard		UMETA(DisplayName = "Guard"),
	ECS_Flinching	UMETA(DisplayName = "Flinching"),
	ECS_KnockDown	UMETA(DisplayName = "Knockout"),

	// Special State - Execution
	ECS_Death		UMETA(DisplayName = "Death"),

	ECS_MAX			UMETA(Hidden)
};

UENUM(BlueprintType)
enum class EHitReactionState : uint8
{
	EHR_None		UMETA(DisplayName = "Default State"),
	EHR_Aerial		UMETA(DisplayName = "Aerial State"),
	EHR_Armor		UMETA(DisplayName = "Armor State"),
	EHR_SuperArmor  UMETA(DisplayName = "Super Armor State"),
	EHR_Parry		UMETA(DisplayName = "Parry State"),

	EHR_MAX			UMETA(Hidden)
};

 

 

새로 추가된 HitReactionState의 경우 피격 인터페이스 함수에서 피격 애니메이션에 진입할지 여부를 결정하거나 Parry State와 같이 피격 애니메이션이 아닌 공격 애니메이션을 실행할 수 있도록 하였다.

 

 

Hit Reaction - 타격감

최근 2주 동안 가장 고민을 많이 한 주제이며 아직 개선이 필요한 부분이다. 애니메이션과 전투시스템, 타격 사운드까지 만들고 나서 직접 테스트해 보니 공격이 허공을 가르는 듯한 느낌이 들고 전투가 전혀 매력적이지 않았다.

이후 코드를 작성하고 개발하는 시간보다 다른 게임을 참고하고 타격감을 만들기 위해 사용된 요소들을 조사하는데 시간을 더 많이 썼다.

 

세키로, 다크소울 3, 엘든링, 팬텀블레이드제로, P의 거짓, 데빌메이크라이, 스텔라블레이드, 검은 신화:오공, 붉은 사막 플레이 영상을 보면서 요소들을 하나씩 뜯어보았다.

 

HitStop

스텔라블레이드, 엘든링에서 적을 타격할 때 잠깐 시간이 멈추거나 느려지는 듯한 효과를 참고하여 피격 함수에 효과를 추가로 구현하였다.

void ABaseEnemy::ApplyHitStop(float Duration, float TimeDilation)
{
	CustomTimeDilation = TimeDilation;
	FTimerHandle TimerHandle;
	GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &ABaseEnemy::ResetTimeDilation, Duration, false);
}

void ABaseEnemy::ResetTimeDilation()
{
	CustomTimeDilation = 1.0f;
}

 

Camera Setting

팬텀블레이드제로, 세키로의 게임 플레이 영상을 뜯어보면서 수평선의 위치가 화면 중앙에 왔을 때를 기준으로 카메라의 각도, 캐릭터와의 거리를 SpringArm의 TargetArmLength, Socket offset를 조정하여 맞췄다.

 

Vfx

타격 이펙트의 경우 조사한 게임에서도 큰 차이가 있었다. 주로 템포가 빠르고 공격 범위가 큰 Hack and Slash 장르에서는 이펙트가 크고 화려했으며 소울라이크 장르의 게임에서는 스파크, 혈흔 정도가 전부였다. 아직 여러 게임 장르를 모두 구현해 보는 학습 목적의 프로젝트라서 이를 확정하지 않아 고민이 필요한 부분이다. 

 

스텔라블레이드, 붉은 사막에서는 Radial Blur 또는 Motion blur와 같은 효과를 사용하여 빠른 속도로 이동하며 적을 공격하거나 회피하는 모션에서 더 역동적인 전투를 구현해 냈다. 

 

 

AnimNotiftyState를 사용하여 Motion Warping이 실행되는 순간에 PostProcess Volume을 활성화하여 추가시켜 둔 Rendering Material인 Radial Blur를 적용하도록 하였다.

 

3일 정도 유튜브에 있는 다양한 이펙트 튜토리얼을 따라 하면서 Niagara, Material의 기초를 학습하였고 여러 애셋의 Emitter들을 조합하거나 변형하여 참고한 게임들의 이펙트를 레퍼런스 삼아 타격 이펙트를 만들었다

 

 

타격 이펙트에 추가로 화면이 왜곡되는 Distortion material을 제작하여 원형의 공간을 왜곡시키도록 하였다.

간단한 원형 Normal Map, 엔진 기본 Normal map인 Water에 Panner를 추가하여 만든 버전 두 가지 버전으로 초기 테스트를 해보았고 이후 프레임 단위로 다른 게임을 참고하면서 이펙트의 범위, 강도, 왜곡 속도? 를 조정하기 위한 노드들을 추가하였다.

 

 

CameraShake

타격감을 주려면 가장 필요하다고 생각했던 CameraShake는 생각보다 많이 사용되지 않고 있었다. 매우 짧은 시간 작게 흔들리거나 주요 스킬이나 보스킬 등 중요한 순간에만 활용하는 게임도 있었다. 우선 피격 함수에 World Camera Shake 함수를 추가하고 여러 세팅을 테스트해 보았는데 과도하게 사용할 경우 조금만 플레이해도 눈이 아프고 어지러웠다. 

 

Roll, Pitch, Location XYZ 중 어떤 항목에 Shake를 적용하였는지 한 프레임씩 뜯어보아도 알기가 쉽지 않아 여러 세팅을 테스트하면서 조금씩 개선하고 있다.

 

Time Dilation

잠시동안 시간이 느려지는 효과로 많은 게임에서 활용하고 있었으며 주로 스킬 연출이 화려한 게임에서 많이 사용되는 것을 볼 수 있었다. 많은 게임에서 적의 공격을 타이밍 맞게 회피하거나 받아치는 경우 극적인 효과를 위해 큰 수치로 Dilation을 조정하여 더 역동적인 느낌을 만들어냈다. 

 

빠른 속도로 적을 추적하거나 적의 주요 공격을 방어하는 경우 AnimNotifyState를 활용하여 Glboal Time dilation을 조정하는 식으로 구현하였다.

Mesh Collision

현재 Capsule Collision에 Sphere Trace를 사용하여 충돌을 판정하고 있어 정확한 타격지점을 알 수 없어 타격 부위에 알맞은 정확한 애니메이션, 물리 효과를 적용하기가 어려운 상태이다. 여러 게임을 마찬가지로 프레임 단위로 뜯어보며 참고하였는데 속도감 있고 화려한 액션 게임의 경우 간단한 충돌판정을 주로 활용하고 있었다. 타격 이펙트 자체가 크고 밝아서 정확한 타격 부위에 이펙트가 Spawn 되지 않아도 보기에 문제가 없었으며 오히려 세로로 베거나 얇은 검기를 날리는 경우 Mesh보다 훨씬 큰 범위에서도 충돌이 일어나고 있었다. 

 

장르가 확정되지는 않았지만 우선 현재 Sphere Trace + Enemy Capsule 기반 충돌판정 시스템을 유지하기로 하였다. 

 


 

이외에도 공격모션, 조작감 등 요소들을 파헤치느라 예상 개발일정보다 개발이 조금 늦어지게 되었다. 하지만 게임을 재미있게 만드는 요소들에 대한 이해는 게임 개발자로서 꼭 갖춰야될 역량이라고 생각한다.