AI 포탑이 단일 Actor Blueprint인 이유: 게임에서 살아남지 못하는 구조적 문제
요약
단일 Actor Blueprint에 모든 로직을 넣는 방식의 구조적 한계와 성능 문제를 지적합니다. 확장성과 최적화를 위해 지각, 상태, 진영, 무기 로직을 분리하는 아키텍처 설계의 중요성을 강조합니다.
핵심 포인트
- 단일 블루프린트 방식은 확장성이 낮고 성능 저하를 유발함
- UAIPerceptionComponent를 활용한 엔진 레벨의 지각 처리 권장
- 상태 로직(State logic)의 격리를 통한 유지보수성 향상
- IGenericTeamAgentInterface를 이용한 데이터 중심 진영 관리
- 무기 시스템의 모듈화 설계 필요성
게임 개발 4주 차입니다. 이 포탑은 목표물을 추적하고, 발사도 정확하며, 에디터에서는 보기 좋습니다.
그러다가 누군가 질문합니다. '두 번째 포탑 유형을 추가할 수 있을까요?', '아군과 적군이 서로 사격하는 것을 막을 수는 없나요?', '왜 이 포탑 세 개를 같은 레벨에 넣자마자 프레임 속도가 떨어지죠?'
이것들은 버그가 아닙니다. 1주 차에 내린 하나의 아키텍처적 결정, 즉 모든 것을 단일 Actor Blueprint 안에 넣은 것의 자연스러운 결과입니다.
단일 Actor 접근 방식이 무너지는 이유
기본 튜토리얼 접근 방식은 이해할 만합니다. 지각(Perception) 로직, 상태 관리(State management), 무기 전환, 진영 확인(Faction checks) 등 모든 것을 하나의 Blueprint 안에 넣습니다. 프로토타입을 만들기는 빠릅니다. 데모를 위해서는 작동합니다.
이는 게임에는 작동하지 않습니다.
두 번째 포탑 유형을 추가한다는 것은 수백 개의 노드를 복제하는 것을 의미합니다. 진영 지원을 추가한다는 것은 기존의 모든 상태를 거쳐 조건들을 수동으로 연결해야 함을 뜻합니다. 틱(tick)마다 실행되는 감지 로직이 열 개의 포탑이 서른 개의 잠재적 목표물을 스캔할 때 발생하는 문제는, 테스트했던 에디터에서는 발견하지 못하고 패키징된 빌드에서만 알게 되는 프레임 속도 문제입니다.
문제가 된 것은 포탑 자체가 아닙니다. 아키텍처입니다.
분리되어야 할 세 가지 레이어
프로덕션 환경에서도 살아남을 수 있는 포탑 시스템은 튜토리얼들이 거의 항상 무너뜨리는 세 가지 요소를 분리합니다:
지각(Perception) - Actor가 아닌 엔진 레벨에서 처리
UE5의 UAIPerceptionComponent는 시야, 청각, 피해 이벤트를 네이티브하게 처리합니다. 이는 엔진 최적화가 되어 있습니다. 포탑 Actor는 자체적인 감지 루프를 틱마다 실행하는 대신, 지각 이벤트를 받습니다. 여러 개의 동시 작동하는 포탑 간의 성능 차이는 매우 크고 협상의 여지가 없습니다.
잘 구성된 지각 레이어는 시야(설정 가능한 원뿔 각도와 범위), 청각(사운드 이벤트 전파), 그리고 피해 감지 기능을 지원하여, 사격당한 포탑이 단순히 추적하던 목표물뿐만 아니라 공격자에게 반응하도록 만듭니다.
*상태 로직 (State logic) - 격리 및 전이 중심
*
대기 (Idle). 순찰 (Patrol). 경계 (Alert). 교전 (Engaged). 조사 (Investigate). 각 상태는 격리되어야 하며, 상태 간에는 명확한 조건 기반의 전이 (transition)가 이루어져야 합니다. 각 상태가 독립적일 때, 새로운 행동을 추가하는 것은 기존에 작동하던 모든 것에 수술을 가하는 것이 아니라 단순히 기능을 덧붙이는 작업이 됩니다.
상태 로직이 거대한 단일 블루프린트 (monolith Blueprint) 내부에 존재하는 순간, 모든 변경 사항은 인접한 모든 요소에 위험 요소가 됩니다.
*진영 로직 (Faction logic) - 태그 기반이 아닌 데이터 중심
*
이 부분은 가장 흔히 생략되지만, 플레이 테스트 시 가장 눈에 띄는 버그를 유발하는 부분입니다.
UE5의 IGenericTeamAgentInterface는 바로 이 목적을 위해 존재합니다. 포탑, NPC, 그리고 플레이어 모두 동일한 인터페이스를 구현합니다. 진영 관계는 하드코딩된 문자열 태그 (string tags)가 아니라 데이터 구조 (data structure) 내에 존재합니다. 포탑은 "이 Actor가 적대적인가?"라고 묻고, 시스템이 이에 답합니다.
이것은 아군 포탑, 진영을 바꾸는 해킹 가능한 포탑, 그리고 두 개 이상의 진영 카테고리가 있는 모든 장면을 스파게티 코드로 만들지 않고 처리할 수 있는 유일한 아키텍처입니다.
*무기 모듈화 (Weapon Modularity): 단순한 기능이 아닌 설계적 함의
*
각 무기 유형은 단순히 가하는 피해량뿐만 아니라, 조우 (encounter)의 의미 자체를 변화시킵니다.
총기 (단발, 점사, 또는 연사)는 지속적인 압박을 가합니다. 유도 로켓 발사기 (Homing Rocket Launcher)는 플레이어에게 끊임없는 움직임을 강요하며, 가만히 서 있을 수 없게 만듭니다. 유탄 발사기 (Grenade Launcher)는 지역 거부 (area denial)를 사용하여 위치 선정을 제어합니다. 레이저 (지속 빔, 지속 피해 (damage over time), 또는 피해 곡선 변형)는 방어력과 거리만으로는 동일하게 해결할 수 없는 다른 종류의 위협을 생성합니다. 지뢰 (Mines, 근접 및 지면)는 포탑이 파괴된 후에도 지속되는 환경적 위험 요소로 포탑을 변화시킵니다. 폭격기 (Bomber)는 포탑의 정의 자체를 바꿉니다. 이제 포탑은 단순한 고정식 총기가 아니라, 투사 시스템 (delivery system)이 됩니다.
이것들은 서로 교체 가능한 무기 스킨이 아닙니다. 각각은 별개의 레벨 디자인 도구입니다. 이들을 호스팅하는 시스템은 AI 로직을 다시 작성하지 않고도 무기 교체 (weapon swapping)를 지원할 수 있어야 하며, 이를 위해서는 무기 유형별로 하드코딩된 발사 동작 (hardcoded firing behavior)이 아닌 깔끔한 부착 인터페이스 (attachment interface)가 필요합니다.
*이동 및 탐지: 디자이너에게 실제로 필요한 레버
*
고정된 위치에서 추적 사격 (tracking fire)을 하거나 정해진 방향으로 발사하는 장착형 포탑 (Mounted turrets)이 시작점입니다. 이동형 포탑 (Mobile turrets)은 레벨 디자인을 완전히 바꿉니다. 정해진 경로를 따라 순찰하거나, 특정 반경 내의 무작위 지점으로 이동하거나, 완전히 확인할 수 없는 무언가를 감지했을 때 조사 상태 (investigate state)로 진입합니다.
공격 우선순위 (Attack priority) 또한 디자인 레버로서 똑같이 중요합니다:
Lock On (록온)은 하나의 타겟에 전념합니다. 플레이어들은 이를 이용하는 법을 배웁니다.
Closer to AI (AI와 더 가까운 대상)는 항상 가장 가까운 유닛을 위협합니다. 플레이어들은 포지셔닝 (positioning)에 대해 고민해야 합니다.
Attacker Priority (공격자 우선순위)는 방금 발사한 대상에게 대응합니다. 이것이 가장 공정하게 느껴지며, 대응할 때 가장 만족감이 높습니다.
디자이너들은 포탑 인스턴스(turret instance)별로 이러한 값들을 조정할 수 있어야 합니다. 이를 위해 블루프린트 (Blueprint)를 직접 건드릴 필요가 없어야 합니다.
*출시 전 성능 체크리스트
*
어떤 포탑 시스템이 빌드에 포함되기 전에:
AI 인지 (AI Perception) 업데이트 간격은 매 틱 (tick)이 아니라 조정된 간격으로 설정할 것
투사체 (Projectile)와 머즐 플래시 (muzzle flash)는 발사 시마다 새로 생성하는 것이 아니라 풀링 (pooled)할 것
회전 보간 (Rotation interpolation)은 수동 델타 계산이 아닌 RInterpTo를 사용할 것
Niagara 이펙트가 타겟 플랫폼의 성능 예산 (performance budget) 내에 있는지 확인할 것
충돌 (Collision) 및 트레이스 채널 (trace channels)이 올바른지 확인할 것. 탐지가 통과해서는 안 되는 지형물을 뚫고 지나가서는 안 됩니다.
명시적으로 언급할 가치가 있는 플랫폼 관련 참고 사항: 실제 타겟 플랫폼에서 조기에 테스트하십시오. 에디터 내에서 성능이 잘 나오는 포탑 AI 시스템이라도 패키지 빌드 (packaged build)에서는, 특히 인지 업데이트 타이밍과 관련하여 다르게 동작할 수 있습니다.
우리가 만든 것
300Mind에서 저희는 Unreal Engine 5 (버전 5.3부터 5.5까지)를 위한 C++ 기반 터렛 시스템인 Advanced AI Turret Framework를 제작하였으며, 이 아키텍처를 즉시 사용 가능한 플러그인 (plugin) 형태로 구현했습니다.
이 시스템은 31개의 C++ 클래스 (classes)와 23개의 블루프린트 (Blueprints)로 구성되어 있습니다. 6가지의 모든 무기 부착 (weapon attachment) 유형이 포함되어 있으며, 고정형 (mounted) 및 이동형 (mobile) 이동 모드를 지원합니다. IGenericTeamAgentInterface를 통한 진영 (faction) 지원이 가능하며, 시각, 청각 및 데미지 감지를 위한 AI 인지 (AI Perception) 기능이 포함되어 있습니다. 록온 (Lock On), AI 근접 대상 (Closer to AI), 공격자 우선순위 (Attacker Priority) 탐지 모드를 지원합니다. 시각 효과를 위한 나이아가라 (Niagara)가 적용되었으며, 체력, 속도, 발사 속도 (fire rate), 데미지 및 순찰 (patrol) 파라미터를 사용자 정의할 수 있습니다. 정밀한 처리를 위한 커스텀 충돌 (collision) 및 트레이스 (trace) 채널도 제공합니다.
향상된 입력 시스템 (Enhanced Input System)을 사용합니다. 현재 Windows를 지원하며, UE5.3부터 5.5까지 호환됩니다. 구매 전 플레이 가능한 데모, 전체 기술 문서 (technical documentation), 그리고 Discord 서버를 이용하실 수 있습니다.
Windows 기반의 슈팅, 서바이벌, 또는 타워 디펜스 게임을 제작 중이면서, 제작 시작 3주 만에 아키텍처 문제를 발견하는 대신 이미 그 문제들을 해결해 놓은 터렛 기반 구조를 원하신다면, 한 번 살펴보실 가치가 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기