로그인게임하기
현장 강의록

Unity 몬스터 AI 상태 머신 만들기 — 대기·추적·공격·복귀 설계

2026.10.11

현장 강의록 · 애니메이션고 2022 · 8편

Unity 몬스터의 대기·추적·공격·복귀 행동을 어떻게 나누고 전환할까요? 상태 다이어그램과 C# 예제로 상태별 행동, 전환 조건, 상태에 들어갈 때의 처리를 살펴봅니다. Character와 Controller를 분리하고 UI 상속 구조를 구성해 게임 프레임워크로 확장하는 과정도 다룹니다.

수업 정보

2022년 1학기 한국애니메이션고등학교 2학년 「3D 게임 프로그래밍」 3강, 4강 「게임 프레임워크 개발」, 5강 「게임 프레임워크 개발」에서 가르친 내용입니다.

FSM

실습: 선공 몬스터의 상태 머신

네 개의 돌 받침대 위에서 같은 슬라임이 두리번거리기, 이동, 에드윈 추적, 집으로 복귀를 하고 화살표가 고리로 잇는 그림
같은 몬스터가 상태에 따라 다르게 움직입니다.

유한 상태 기계(Finite State Machine)는 사물이 가질 수 있는 상태를 정해 두고, 한 번에 상태 하나에 머물며, 조건이 맞으면 다른 상태로 옮겨 가게 하는 설계입니다.

문제: 선공 몬스터의 상태 머신을 구현하세요
  1. IDLE — 제자리에 멈춰 적을 찾습니다. 적을 찾으면 추적합니다. 15초 동안 못 찾으면 다른 위치로 이동합니다.
  2. Moving — 다음 위치로 이동합니다. 이동 중에 적을 찾으면 추적합니다. 도착하면 IDLE 로 돌아갑니다.
  3. Following — 적을 쫓습니다. 적이나 스폰 위치와 10m 넘게 멀어지면 스폰 위치로 돌아가기 시작합니다. 사정거리 안까지 쫓아가면 공격합니다.
  4. Attacking — 계속 공격합니다. 적이 사정거리 밖으로 나가면 다시 쫓습니다. 적이 죽으면 스폰 위치로 돌아가고, 몬스터가 죽으면 상태 기계를 끝냅니다.
  5. Returning — 스폰 위치로 돌아갑니다. 도착하면 IDLE 로 돌아갑니다. 돌아가는 동안에는 피해를 받지 않습니다.
선공 몬스터의 상태 머신몬스터 스폰IDLEFollowingAttackingMovingReturningentry / 스폰 위치를 바라보게 회전do / 스폰 위치로 이동, 도착하면 IDLE리스폰 쿨타임 뒤 다시 스폰적 발견15초 지남이동 완료적 발견사정거리 안으로사정거리 밖으로스폰과 10m 넘게 멀어짐적 사망스폰 위치 도착몬스터 사망
정답 상태 다이어그램. 검은 점은 시작(몬스터 스폰), 겹친 원은 끝(몬스터 사망)입니다.
모양뜻
둥근 사각형상태
화살표와 글자전환과 그 조건 (적 발견, 15초 지남 …)
entry / …그 상태에 들어갈 때 한 번 하는 일 — Returning 에서는 스폰 위치를 바라보게 회전
do / …그 상태에 있는 동안 계속 하는 일 — 스폰 위치로 이동
검은 점 · 겹친 원시작과 끝

Returning 의 "돌아가는 동안 피해를 받지 않는다" 는 규칙은 게임 디자인에서 중요한 장치입니다. 이 규칙이 없으면 플레이어가 몬스터를 스폰 위치에서 멀리 끌고 가 돌아가는 등 뒤를 공짜로 때릴 수 있습니다. 상태 다이어그램에 규칙을 적어 두면 이런 구멍을 설계 단계에서 찾습니다.

MonsterController.cs설명용 예시 — 위 정답을 C# 으로
enum MonsterState { Idle, Moving, Following, Attacking, Returning }
MonsterState state = MonsterState.Idle;
float idleTime;

void Update()
{
    switch (state)
    {
        case MonsterState.Idle:
            idleTime += Time.deltaTime;
            if (FindEnemy()) Change(MonsterState.Following);
            else if (idleTime > 15f) Change(MonsterState.Moving);
            break;
        case MonsterState.Moving:
            if (FindEnemy()) Change(MonsterState.Following);
            else if (MoveToNextPoint()) Change(MonsterState.Idle);       // 도착
            break;
        case MonsterState.Following:
            if (Distance(target) > 10f || Distance(spawnPoint) > 10f) Change(MonsterState.Returning);
            else if (InAttackRange(target)) Change(MonsterState.Attacking);
            else Chase(target);
            break;
        case MonsterState.Attacking:
            if (target.IsDead) Change(MonsterState.Returning);
            else if (!InAttackRange(target)) Change(MonsterState.Following);
            else Attack(target);
            break;
        case MonsterState.Returning:
            if (MoveTo(spawnPoint)) Change(MonsterState.Idle);           // 도착
            break;
    }
}

void Change(MonsterState next)
{
    state = next;
    idleTime = 0f;
    invincible = next == MonsterState.Returning;                         // 돌아가는 동안 무적
    if (next == MonsterState.Returning) LookAt(spawnPoint);              // entry: 스폰 위치를 바라봄
}

상태가 바뀌는 곳을 Change() 에 모았습니다. entry 에 해당하는 일(바라보기, 무적 켜기)을 여기에 두면, 상태가 늘어나도 들어갈 때의 일을 빠뜨리지 않습니다.

FRAMEWORK

게임 프레임워크의 세 갈래

UI

User Interaction

UI 는 Windows 같은 GUI 운영체제와 닮았습니다. 창 시스템을 설계한다고 생각하고 효율적이고 빠짐없게 설계합니다.

사물

Content Objects

게임은 사람들이 만지고 싸우고 경험치를 얻는 콘텐츠 사물로 이루어집니다. MMORPG 라면 어떤 사물이 필요할지 먼저 적습니다.

AI

Artificial Intelligence

어떤 사물은 스스로 판단합니다. 상태 머신으로 생애를 관리하는 클래스가 많으므로, 맨 위부터 아래까지 효율적인 상속 나무가 필요합니다.

CONTENT

콘텐츠 사물 설계

캐릭터와 컨트롤러 클래스 다이어그램CharacterControllerWeaponMonsterControllerPlayerController
캐릭터는 무기를 가지고, 컨트롤러가 캐릭터를 움직입니다. 몬스터와 플레이어의 컨트롤러는 같은 부모를 물려받습니다.

Character 는 능력치와 모양을 가진 몸이고, Controller 는 그 몸을 움직이는 머리입니다. 같은 Character 에 MonsterController 를 붙이면 AI 가 움직이고, PlayerController 를 붙이면 사람이 움직입니다. 1편의 로봇에서 "부위를 나눈다" 고 했던 생각이 "몸과 머리를 나눈다" 로 자랐습니다.

캐릭터는 프리팹으로 만들고, 동작은 Animator Controller 로 상태를 나눠 둡니다. 애니메이션에도 상태 머신이 쓰입니다.

실습: 카메라 추적, 클릭해서 이동
  1. 마우스로 클릭한 지점으로 캐릭터를 이동시킵니다.
  2. 메인 카메라는 언제나 캐릭터에서 (0, 8.5, -3.5) 만큼 떨어져 따라다닙니다. 캐릭터가 생길 때와 캐릭터의 Update 마다 맞춥니다.
Ray Picking4강 6쪽
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
int layer_mask = LayerMask.GetMask("Terrain");
if (Physics.Raycast(ray, out hit, 1000, layer_mask))
{
    hit.point;   // 피킹된 3D 위치
}

화면의 클릭 위치에서 카메라 방향으로 광선(Ray)을 쏘아, 지형(Terrain) 층에 처음 닿는 점을 찾습니다. 그 점이 캐릭터가 갈 곳입니다. 다음 실습은 스페이스바를 누르면 공격 동작이 나오게 하는 것이었습니다.

실습: 몬스터 상태 머신 붙이기
  1. 몬스터가 IDLE 상태에서 캐릭터를 찾습니다.
  2. 찾으면 Following 상태로 바꿉니다.
  3. Following 중에는 캐릭터를 계속 쫓고, 거리가 7 넘게 벌어지면 마지막으로 쫓던 위치로 돌아옵니다.
UI

UI 클래스 설계

UI 클래스 상속 다이어그램MonoBehaviourUIBaseUIWindowUIDialogueUIListPanelUIElementUIMessageBoxUIMessageConfirmUIMessageItemConfirmButtonUIButton0..*
UI 클래스의 상속 나무. 위로 갈수록 공통 기능, 아래로 갈수록 구체적인 창입니다.

모든 UI 는 UIBase 를 물려받습니다. 화면 전체를 덮는 UIWindow 와 위에 뜨는 UIDialogue 로 나뉘고, 대화창은 다시 메시지 상자 → 확인 상자 → 아이템 확인 상자로 구체화됩니다. 목록 패널(UIListPanel)은 항목(UIElement)을 여러 개 품습니다(꽉 찬 마름모, 0..*).

아이템을 버릴지 묻는 창을 새로 만들 때, 부모가 이미 "메시지를 띄우고 확인 · 취소를 받는" 일을 하므로 아이템 그림을 띄우는 부분만 더하면 됩니다. 상속 나무를 잘 세우면 새 창을 만드는 비용이 점점 줄어듭니다.

FEATURES

프레임워크 위에 기능 얹기

5강에서는 만든 프레임워크 위에 게임 기능을 하나씩 얹었습니다.

실습하는 일핵심
토스트 메시지애니메이션과 함께 뜨는 짧은 알림 프리팹을 만들어 Resources 에 두고, Create 로 화면에 띄운 뒤 3초 뒤에 지웁니다Instantiate(Resources.Load(…)), 부모는 캔버스, Destroy(gameObject, LifeTime)
몬스터 스포너시작할 때 최대 수만큼 몬스터를 만들고, 마지막 사망 시각에서 정한 시간이 지나면 다시 채웁니다Character.Create(id), Random.Range() 로 위치 고르기
적 탐색플레이어를 찾던 SearchEnemies() 를 몬스터도 찾을 수 있게 고칩니다제네릭 where T : Controller
그 밖에플레이어 조작 UI, 피해 숫자 효과, 인벤토리와 아이템, 몬스터의 공격과 사망
SearchEnemies설명용 예시 — 5강 7쪽 실습
// 플레이어 전용이던 탐색을 컨트롤러 종류로 일반화한다
public List<T> SearchEnemies<T>(float radius) where T : Controller
{
    List<T> found = new List<T>();
    foreach (T c in FindObjectsOfType<T>())
    {
        if (Vector3.Distance(c.transform.position, transform.position) <= radius)
            found.Add(c);
    }
    return found;
}

// 쓰는 쪽
var players = SearchEnemies<PlayerController>(10f);
var monsters = SearchEnemies<MonsterController>(10f);

where T : Controller 는 "T 는 Controller 의 자식이어야 한다" 는 약속입니다. 상속 나무를 잘 세워 두었기 때문에 탐색 함수 하나로 플레이어와 몬스터를 모두 찾습니다.

NOW

지금 100턴에서는

「졸업까지 100턴」의 캐릭터도 상태 머신을 씁니다. 다만 상태마다 무엇을 할지를 Strategy 객체로 빼서, 보드의 말과 산책 NPC 와 미니게임 캐릭터가 같은 캐릭터 클래스를 씁니다. 수업의 Character + Controller 가 실제 서비스에서 어떻게 자랐는지는 구조 읽기 4편에 정리했습니다.

정리

  1. 상태는 하나씩, 전환은 조건으로. 상태와 조건을 표로 먼저 적고 다이어그램과 코드로 옮깁니다.
  2. 몸(Character)과 머리(Controller)를 나눕니다. 같은 몸을 AI 도, 사람도 움직입니다.
  3. 상속 나무를 잘 세우면 새 기능이 싸집니다. UI 창도, 적 탐색도 부모가 일을 덜어 줍니다.

다음 편에서는 캐릭터를 움직이고 시야를 계산하는 게임 수학, 벡터와 행렬을 다룹니다.

함께 읽으면 좋은 글

AI가 만든 Unity 코드를 직접 검증해 보고 싶다면

이 글에서 살펴본 구조를 바탕으로 AI에게 작업을 요청하고 결과를 읽는 연습을 이어가세요. 「AI 코드를 읽는 게임 개발자」 무료 세션 1에서 시작하거나, 전체 커리큘럼과 수강 안내를 확인할 수 있습니다.

← 개발 노트 목록