언리얼 RPG 프로젝트 2 C++
- 프로그래밍/언리얼
- 2024. 12. 16.
언리얼 RPG 프로젝트 2 C++
GAS(GamePlay Ability System)프레임워크를 사용해보고 싶어서 사용해 봤습니다.
(GAS에 대한 자세한 내용은 아래.)
GAS를 사용하는데 RPG가 제일 맞는 것 같았습니다.
게임에 대해.
개발 언어: C++, Blueprint
개발 엔진: Unreal 5.4
개발 환경(실행 환경): Window 11
코드.
깃허브 주소.
https://github.com/ykarr/RPG_Blade_1.git
기능.
캐릭터.
-Attribute
처음 시작할 때 동기적으로 데이터를 가져와서 Attribute를 적합니다.
-Weapon Spawn / 아이템 장착
게임을 시작할 때 무기를 소환하고 소켓에 장착.
Weapon Class to Spawn만 바꾸면 됩니다.
-가벼운 공격.
Light Attack Montage를 여러 개 만들어서 콤보에 따라 다른 공격이 나가도록 설정했습니다.
데미지 계산식.
if (UsedLightAttackComboCount !=0) {
//콤보가 1인경우(시작공격) 데미지증가 0
const float DamageIncreasePercentLight = (UsedLightAttackComboCount - 1) * 0.05f+1.f;
BaseDamage *= DamageIncreasePercentLight;
//Debug::Print(TEXT("ScaledBaseDamageLight"), BaseDamage);
}
-강공격
강공은 공격력만 다르고 가벼운 공격과 비슷합니다.
데미지.
if (UsedHeavyAttackComboCount != 0) {
//콤보가 1인경우(시작공격) 데미지증가 0
const float DamageIncreasePercentHeavy = (UsedHeavyAttackComboCount - 1) * 0.15f + 1.f;
BaseDamage *= DamageIncreasePercentHeavy;
//Debug::Print(TEXT("ScaledBaseDamageHeavy"), BaseDamage);
}
-분노상태.
분노 게이지를 모아서 분노 상태로 들어갈 수 있도록 만들었습니다.
분노 상태에서는 원거리 공격을 할 수 있고, 사용중일 때 무적입니다.
Enemy의 원거리 공격과 다르게 Overlap으로 설정해서 일정 거리까지 닿아도 없어지지 않고 작동합니다.
-특별한 공격.
범위 안의 적을 공격하거나, 어떤 위치에 있는 적에게 순간이동하며 공격하거나 하는 쿨타임이 존재하는 능력입니다.
-막기
적의 특별한 공격을 제외하고 막을 수 있습니다.
아슬아슬하게 막은 경우 잠시동안 시간이 느려집니다.
-구르기
Roll Ability를 실행하면, 특정한 방향으로 구르게 됩니다.
난이도에 따라 구르기 레벨이 달라지고 구르기 레벨에 따라 이동거리가 달라집니다.
-타겟락
범위 안에 Enemy가 있는 경우 가장 가까운 적에게 Target Lock을 사용할 수 있습니다.
TargetLock을 사용하면 PlayerCharacter가 Targeting된 적을 바라보고 Strafing으로 움직임이 바뀝니다.
-죽음.
캐릭터가 죽을 경우 Player Death Ability를 실행하고, UI가 실행됩니다.
게임을 다시 실행 / 메뉴로 이동 / 게임 종료.
-UI 애니메이션
-GameplayTag
-쿨타임.
Ability에 있는 기능을 이용해 구현하고 CoolTime UI를 위해 GamePlayAbility Tick을 구현해 사용했습니다.
Enemy.
-Attribute
처음 시작할 때 비동기적으로 작동합니다.
비동기적으로 Status를 적용하고, 무기를 불러오는 등...
-아이템 장착.
Enemy가 소환된 후 무기를 소환하고, 무기를 장착합니다.
-공격
플레이어가 근접 공격이 가능한 영역에 들어오면, AI는 EQS를 사용하여 주변 환경을 평가하고, 이를 기반으로 공격하고 빠지는 전투를 수행합니다.
-막을 수 없는 공격
UI가 나오면서 막을 수 없는 공격을 경고합니다.
-아이템 드롭.
Enemy가 죽으면서 아이템을 드롭합니다.
일정한 확률로 드롭하고, 거기서 일정한 확률로 Health/Range를 채워줍니다.
(GamePlayEffect)
-원거리 Enemy
Character가 근처로 막을 수 없는 공격을 진행하거나 도망갑니다.
원거리에서 공격하고 EnemyProjectileAttackAbility을 이용해 Projectile Actor를 소환해서 공격합니다.
-보스
보스가 나타날 경우 보스의 HP가 나타나고, HP가 일정 이하로 줄어들면 보스가 아닌 Enemy를 소환합니다.
-소환
Wave마다 랜덤 한 종류의 정해진 수의 Enemy를 소환합니다.
-UI
Enemy의 머리 상단에 표시할 HealthBar UI.
-AI
AI는 Behavior Tree를 이용해 행동을 구현했고, EQS(Environment Query)를 사용했습니다.
Behavior Tree : AI의 행동을 트리 구조로 구성하여, 상태에 행동을 제어.
EQS : AI가 주변 환경을 평가하고, 이를 기반으로 최적의 행동을 선택하도록 돕는 시스템.
Item
-회복 아이템.
아이템을 사용할 수 있을 때 상호작용 아이콘이 나타납니다.
-무기.
무기에 InputMappingContext와 무기에 맞는 Animation, Ability, WeaponStatus 등을 넣어 사용합니다.
WeaponStatus-> 난이도에 따라 데미지가 달라집니다.
기타 기능.
-로딩.
-난이도 설정.
위젯을 통해 난이도를 설정->USaveGame으로 저장합니다.
게임을 시작할 때는 USaveGame->PlayerCharcter->GameModeBase형식으로 됩니다.
(USaveGame을 사용하면 데이터가 저장되어 게임을 껐다 켜도 데이터가 유지됩니다.)
알게된점.
Gameplay Ability System은 액터의 능력 및 스킬을 구축하기 위한 프레임워크입니다.
능력과 Actor를 분리시켜 의존성을 없애고, 유연한 개발이 가능하도록 해줍니다.
AbilitySystemComponent
-액터의 모든 어빌리티를 관리.
- 캐릭터, NPC 등 특정 액터에 부착.
GameplayAbility
-액터가 수행할 수 있는 능력을 정의.
- 공격, 힐링, Targeting 등의 스킬이나 행동.
AbilityTask
-GameplayAbility 내에서 세부적인 동작을 정의.
- 충돌 감지 등.
GameplayTag
-능력, 상태, 효과등을 식별하고 분류하는 데 사용.
- 태그를 이용해 죽었는지 살았는지부터 공격 중인지 화염상태인지 등 여러 가지 상태 식별.
Gameplay Attribute
-캐릭터의 수치를 관리.
- 캐릭터의 체력, 마나, 방어력, 공격력 등의 수치를 관리.
GameplayEffect
-능력이나 아이템 사용 시 적용되는 효과 정의.
- 체력 포션을 먹었을 때 피 50회복/피 10초간 지속회복.
GameplayCue
-능력 발동 시 발생하는 연출(비주얼, 사운드).
- 캐릭터가 스킬을 사용할 때 나오는 이펙트와 사운드 등.
아쉬운 점.
혼자서 개발하는 것이 제일 아쉬운 점이었던 것 같습니다.
혼자서 개발하다 보니 리소스를 구하는 부분이나 Level을 구성하는 부분이 너무 오래 걸렸습니다.
또한 GAS를 사용해보고 싶어서 시작한 프로젝트였기 때문에 GAS도 공부하면서 웬만하면 C++을 위주로 하고 싶어서 블루프린트 코드들을 C++로 바꾸고 진행하다 보니 이런 코드들이 블루프린트에서는 보이지만 C++에서는 보이지 않는 것들이 몇 개 있어서 이런 것들을 찾고, 만들고 하다 보니 시간이 너무 오래 걸렸습니다.
느낀 점.
GAS(GamePlay Ability System)를 사용하며 이 시스템의 강력함과 유연함을 직접 체감할 수 있었습니다.
하지만, 소규모 프로젝트에서는 GAS가 과하게 느껴지는 부분도 많았습니다.
GAS는 확장성이 뛰어나고, 능력이나 효과를 체계적으로 관리할 수 있는 구조 덕분에 대규모 프로젝트에서는 매우 유용한 도구가 될 것이라고 생각합니다. 하지만 소규모 개발에서는 초기 설정과 학습 곡선이 조금 부담스러웠습니다.
"과한 것이 반드시 좋은 것은 아니다" 라는 말을 GAS를 공부하고 적용하면서 떠올리게 되었습니다.
GAS를 공부하고 적용하는데 들인 시간에 비해, 간단한 기능이라면 직접 구현했을 경우 더 빠르게 개발을 완료할 수 있었을 겁니다.
찾아보니까 GAS는 대규모 시스템을 목표로 설계되었기 때문에 간단한 능력 구현에도 불필요한 구조와 시스템이 포함되는 경우가 많았습니다. 그럼에도 불구하고, GAS는 한번 익혀두면 꽤 쓸만하다는 생각이 들었고, 특히 네트워크 동기화가 필요한 멀티 플레이 환경에서는 큰 장점이 될 것이라고 생각합니다.
결론적으로, GAS는 프로젝트의 규모와 필요성에 따라 선택적으로 사용하는 것이 가장 효과적일 것 같고, 작은 규모의 프로젝트나 간단한 기능이라면 직접적인 방식으로 구현하는 것이 효과적일 것이라고 느꼈습니다.
실행 영상.