생존 공포 게임의 추적자, RPG 던전 보스, 전술 밀리터리 봇 등 몰입감 있는 NPC를 제작할 때 가장 큰 문제는 비구조화된 코드입니다. 단일 스크립트에 수백 줄의 if-else 분기를 작성하면 길찾기가 먹통이 되고 서버 프레임이 급락합니다.
상용 게임 개발에서는 거시적 상태를 관리하는 유한 상태 머신(FSM)과 유연한 하위 전술을 결정하는 행동 트리(Behavior Tree)를 결합하여 사용합니다. 본 가이드에서는 블랙보드 데이터 저장소, 시야각(FOV) 레이캐스트, 어그로 시스템, 서버 틱 LOD 분산 기법을 상세히 다룹니다.
게임 장르와 복잡도에 따른 아키텍처 선정 기준:
서버 성능 저하 없이 NPC에게 정밀한 지각 능력을 부여하는 방법:
-- Modular Finite State Machine for Roblox NPC
local StateMachine = {}
StateMachine.__index = StateMachine
function StateMachine.new(npcInstance, states, initialState)
local self = setmetatable({}, StateMachine)
self.NPC = npcInstance
self.States = states
self.CurrentState = nil
self.Blackboard = {
Target = nil,
LastSeenPos = nil,
Health = 100,
PatrolPoints = {}
}
self:ChangeState(initialState)
return self
end
function StateMachine:ChangeState(newStateName)
if self.CurrentState and self.States[self.CurrentState].Exit then
self.States[self.CurrentState]:Exit(self.NPC, self.Blackboard)
end
self.CurrentState = newStateName
if self.States[newStateName] and self.States[newStateName].Enter then
self.States[newStateName]:Enter(self.NPC, self.Blackboard)
end
end
function StateMachine:Update(dt)
if self.CurrentState and self.States[self.CurrentState].Update then
local nextState = self.States[self.CurrentState]:Update(self.NPC, self.Blackboard, dt)
if nextState and nextState ~= self.CurrentState then
self:ChangeState(nextState)
end
end
end
return StateMachine
계층적 우선순위 판단 시스템 구성:
100마리 이상의 몬스터가 동시 활동할 때 서버 60 FPS를 사수하는 비결:
Instance.new와 Destroy를 반복하지 않고, 미리 생성된 NPC 풀에서 투명도와 CFrame만 변경해 재사용합니다.Heartbeat마다 모든 NPC의 레이캐스트와 경로 계산을 실행하기 때문입니다. AI LOD를 적용해 원거리 NPC의 연산 주기를 늘리고 프레임별로 분산 처리해야 합니다.
새로운 행동을 추가할 때 기존 상태들의 전이 화살표를 일일이 수정할 필요 없이, 트리에 노드 하나만 끼워 넣으면 되는 유연성과 모듈성입니다.
NPC의 머리에서 플레이어의 몸통으로 레이캐스트를 쏘아, 벽이나 기둥에 가려지는지 RaycastResult로 검증해야 합니다.
대미지 판정이나 타깃 지정 등 핵심 로직은 반드시 서버가 제어해야 핵과 변조를 방지할 수 있습니다. 클라이언트는 시각적 애니메이션 보간만 담당해야 합니다.
시스템 아키텍처 설계 역량을 진단하고 정밀한 인지 분석 도구를 DopaBrain에서 체험해 보세요.
DopaBrain 인지 테스트 시작하기