배경 NPC 순찰 AI를 StateTree로
마을을 채우는 배경 NPC가 정해진 반경 안을 어슬렁거리게 만들려고 StateTree 순찰 AI를 붙였다. 구조 자체는 간단했는데, 정작 시간을 잡아먹은 건 ‘캐릭터가 미끄러지듯 움직이는’ 애니 문제와, 원래 가만히 서 있던 NPC라 드러나지 않았던 숨은 전제였다.
구조
ARetrieveVillagerCharacter는ARetrieveNPCCharacter를 상속하고AIControllerClass = ANPCPatrolAIController.ANPCPatrolAIController는 Perception·Team 없이 최소한의UStateTreeAIComponent만 돌린다.FStateTreeTask_VillagerPatrol은PatrolOrigin반경 안에서GetRandomReachablePointInRadius로 목적지를 잡는 단일 태스크.
전투 몬스터 AI를 빌려다 쓰지 않고 별도 클래스 계층으로 나눈 게 핵심이다. 몬스터 StateTree를 재사용했다면 전투 로직과 강하게 엮여 배경 NPC가 딸려 들어갔을 거다.
미끄러지는 애니 — 회전 권위가 둘로 갈렸다
처음엔 NPC가 걷는데 발이 땅을 안 밟고 미끄러지듯 이동했다. 원인은 회전을 누가 책임지는지가 충돌한 것이었다.CharacterMovement의 bOrientRotationToMovement와 MoveTo의 bCanStrafe가 서로 다른 방향으로 캐릭터를 돌리려 하면 이동 방향과 바라보는 방향이 어긋나 미끄러진다.
// 회전 권위를 CharacterMovement로 일원화
CharacterMovement: bOrientRotationToMovement = true, MaxWalkSpeed = 250, MaxAcceleration = 400
MoveToLocation: bCanStrafe = true // 핵심 — 회전 권위를 CharacterMovement에 넘긴다bCanStrafe = true로 두어 이동 노드가 회전을 강제하지 않게 하고, 회전은 CharacterMovement가 전담하게 통일했다.
정적 NPC의 숨은 전제
더 골치 아팠던 건, 원래 가만히 서 있기만 하던 NPC라 이동을 시키기 전엔 안 드러난 전제였다. 메시에 회전 오프셋이 들어가 있었는데, 서 있을 땐 아무 문제가 없다가 이동·회전을 시작하니 그제야 비뚤어져 보였다. 정적 에셋에 새 행동을 줄 때는 ‘이 에셋이 그 행동을 한 번이라도 해 본 적 있나’를 먼저 의심해야 한다.
배운 점
캐릭터를 돌리는 주체는 하나로 통일해야 한다. bCanStrafe와 bOrientRotationToMovement가 서로 다른 방향을 주장하면 미끄러진다.
정적 NPC는 숨은 전제(메시 회전 오프셋 같은)를 감추고 있다. 가만히 있던 에셋에 새 행동을 붙일 땐, 그 에셋이 한 번도 안 해 본 동작이라는 점을 전제하고 검증한다.
역할이 다른 액터는 처음부터 클래스 계층을 나눈다. 편하다고 전투 AI를 빌려 쓰면 안 쓰는 결합까지 딸려 온다.