[TIL] 2026-01-22 | Automata, State Machine

2026. 1. 22. 17:11·내배캠Unreal_TIL/UE
역량강화 분반 - 챌린지 - 이론

스테이트 머신

▷ 객체가 어떤 상태인지 명확히 정하고, 그 상태에서만 가능한 행동과 전환을 허용하는 구조

 

직접 구현 VS 스테이트 머신

더보기

직접 구현 (나쁜 예시)

  1. 상태 플래그 여러 개가 동시에 true가 될 수 있음 (논리 오류)
  2. if문 순서가 중요함 (순서 바뀌면 버그)
  3. 새 상태 추가 시 모든 곳 수정
  4. 디버깅 극악의 난이도
// 캐릭터 클래스
class Character {
    bool bIsIdle = true;
    bool bIsWalking = false;
    bool bIsRunning = false;
    bool bIsJumping = false;
    bool bIsAttacking = false;
    bool bIsDead = false;

    void Update(float DeltaTime) {
        // if 지옥...
        if (bIsDead) {
            // Dead 로직
            return;
        }

        if (bIsAttacking) {
            if (AttackAnimFinished()) {
                bIsAttacking = false;
                bIsIdle = true;
            }
            return;
        }

        if (bIsJumping) {
            if (IsOnGround()) {
                bIsJumping = false;
                bIsIdle = true;
            }
            // Jump 물리...
            return;
        }

        if (InputAttack()) {
            bIsIdle = false;
            bIsWalking = false;
            bIsRunning = false;
            bIsAttacking = true;
            // 공격 시작
            return;
        }

        if (InputJump()) {
            bIsIdle = false;
            bIsWalking = false;
            bIsRunning = false;
            bIsJumping = true;
            // 점프 시작
            return;
        }

        if (InputMove()) {
            bIsIdle = false;
            if (InputSprint()) {
                bIsWalking = false;
                bIsRunning = true;
                // Run 로직
            } else {
                bIsWalking = true;
                bIsRunning = false;
                // Walk 로직
            }
        } else {
            bIsWalking = false;
            bIsRunning = false;
            bIsIdle = true;
            // Idle 로직
        }
    }
};
더보기

스테이트 머신 (좋은 예시)

// 상태 정의
enum class CharacterState {
    Idle,
    Walk,
    Run,
    Jump,
    Attack,
    Dead
};

class Character {
    CharacterState CurrentState = CharacterState::Idle;

    void Update(float DeltaTime) {
        // 현재 상태에서만 로직 실행
        switch (CurrentState) {
            case CharacterState::Idle:
                UpdateIdle(DeltaTime);
                break;
            case CharacterState::Walk:
                UpdateWalk(DeltaTime);
                break;
            case CharacterState::Run:
                UpdateRun(DeltaTime);
                break;
            case CharacterState::Jump:
                UpdateJump(DeltaTime);
                break;
            case CharacterState::Attack:
                UpdateAttack(DeltaTime);
                break;
            case CharacterState::Dead:
                UpdateDead(DeltaTime);
                break;
        }
    }

    void ChangeState(CharacterState NewState) {
        // 상태 전환
        CurrentState = NewState;
    }
};

오토마타

▷ 계산 이론(Theory of Computation)에서 사용하는 추상적인 계산 모델

▷ 입력을 받아서 상태를 전환하며, 출력을 생성하는 수학적 기계

 

구성 요소

  1. States (상태들): Q = {q₀, q₁, q₂, …}
  2. Input Alphabet (입력 기호): Σ = {a, b, c, …}
  3. Transition Function (전환 함수): δ(q, a) = q’
  4. Initial State (초기 상태): q₀
  5. Accepting States (수락 상태, 완료): F ⊆ Q

오토마타의 종류

종류 용도 설명
유한 오토마타 (FA) 정규표현식, 게임 AI 유한한(현재) 상태만 저장
푸시다운 오토마타 (PDA) 파서, 컴파일러 현재 상태 + 스택 메모리 추가
튜링 머신 (TM) 이론적 계산 모델 무한(이론상) 테이프 메모리

📌게임에서는 유한 오토마타 (Finite Automaton), DFA 만 사용!

 

유한 상태 기계 (FSM)

캐릭터 FSM 다이어그램 예시

1. Enter (OnEnter, OnStateBegin)

  • 상태에 진입할 때 한 번 실행
    • 공격 애니메이션 재생, 효과음

2. Update (Tick, OnStateUpdate)

  • 상태가 활성화된 동안 매 프레임 실행
    • 이동, 물리 계산

3. Exit (OnExit, OnStateEnd)

  • 상태를 떠날 때 한 번 실행
    • 정리 작업, 다음 상태 준비

FSM 구현 방법

1. Enum + Switch

▷ 가장 간단하고 직관적인 방법

더보기
// CharacterFSM_Enum.h
#pragma once

enum class ECharacterState {
    Idle,
    Jump,
    Attack,
    Dead
};

class CharacterFSM_Enum {
private:
    ECharacterState CurrentState;

public:
    CharacterFSM_Enum() : CurrentState(ECharacterState::Idle) {}

    void Update(float DeltaTime) {
        switch (CurrentState) {
            case ECharacterState::Idle:
                UpdateIdle(DeltaTime);
                break;
            case ECharacterState::Jump:
                UpdateJump(DeltaTime);
                break;
            case ECharacterState::Attack:
                UpdateAttack(DeltaTime);
                break;
            case ECharacterState::Dead:
                UpdateDead(DeltaTime);
                break;
        }
    }

    void ChangeState(ECharacterState NewState) {
        // Exit current state
        ExitState(CurrentState);

        // Change state
        ECharacterState OldState = CurrentState;
        CurrentState = NewState;

        // Enter new state
        EnterState(NewState);

        // 로그
        printf("State changed:%d ->%d\n", (int)OldState, (int)NewState);
    }

private:
    void EnterState(ECharacterState State) {
        switch (State) {
            case ECharacterState::Idle:
                printf("Enter Idle\n");
                break;
            case ECharacterState::Attack:
                printf("Enter Attack: Play attack animation\n");
                break;
            case ECharacterState::Dead:
                printf("Enter Dead: Character died\n");
                break;
        }
    }

    void ExitState(ECharacterState State) {
        switch (State) {
            case ECharacterState::Attack:
                printf("Exit Attack: Cleanup\n");
                break;
            // 다른 상태는 Exit 처리 없음 (필요 시 추가)
        }
    }

    void UpdateIdle(float DeltaTime) {
        // Idle 로직
        // 예: 입력 대기
    }

    void UpdateJump(float DeltaTime) {
        // Jump 로직
        // 예: 착지 체크
        if (IsOnGround()) {
            ChangeState(ECharacterState::Idle);
        }
    }

    void UpdateAttack(float DeltaTime) {
        // Attack 로직
        // 예: 애니메이션 종료 체크
        if (IsAttackFinished()) {
            ChangeState(ECharacterState::Idle);
        }
    }

    void UpdateDead(float DeltaTime) {
        // Dead 로직
        // (아무것도 안 함)
    }

    // 헬퍼 함수들
    bool IsOnGround() {
        //TODO: 실제 구현
        return false;
    }

    bool IsAttackFinished() {
        //TODO: 실제 구현
        return false;
    }
};

 

2. State Pattern

▷ GoF Design Pattern 중 하나인 State Pattern을 사용

더보기

IState.h (인터페이스)

#pragma once

class CharacterFSM_StatePattern; // 전방 선언

// 상태 인터페이스
class IState {
public:
    virtual ~IState() = default;

    // 상태 진입
    virtual void OnEnter(CharacterFSM_StatePattern* Owner) = 0;

    // 상태 업데이트
    virtual void OnUpdate(CharacterFSM_StatePattern* Owner, float DeltaTime) = 0;

    // 상태 탈출
    virtual void OnExit(CharacterFSM_StatePattern* Owner) = 0;
};

 

IdleState.h:

#pragma once
#include"IState.h"
#include<iostream>

class IdleState : public IState {
public:
    void OnEnter(CharacterFSM_StatePattern* Owner) override {
        std::cout << "[Idle] Enter: Character is idle\n";
    }

    void OnUpdate(CharacterFSM_StatePattern* Owner, float DeltaTime) override {
        // Idle 로직
        // 예: 입력 대기, Idle 애니메이션
    }

    void OnExit(CharacterFSM_StatePattern* Owner) override {
        std::cout << "[Idle] Exit\n";
    }
};

 

... 생략

State Pattern이란?

객체가 특정 상태에 따라 행위를 달리하는 상황에서, 상태를 조건문으로 검사해서 행위를 달리하는 것이 아닌, 상태를 객체화 하여 상태가 행동을 할 수 있도록 위임하는 패턴

- 각 상태를 클래스로 만듦
- 다형성 활용 (가상 함수)
- 상태별 로직 캡슐화

 

계층적 상태 기계 (HSM, Hierarchical State Machine)

▷ 상태를 계층적으로 구성한 FSM

그냥 상속받아서 만들면 안되나요?

📌됩니다. 다만 trade-off가 있습니다.
상속을 쓰면 계층 구조가 타입 시스템에 고정됩니다. 상태 타입과 계층을 분리하지 않는다면,
- 상태를 동적으로 재구성하기 어렵고
- 하나의 상태가 여러 상위 개념을 갖기 힘듭니다.
   - Attack이 Combat이면서 동시에 Airborne 계열일 수도 있다면? → 다중 상속 </aside>

 

Unreal Engine과의 연관성

1. Animation Blueprint의 State Machine은 HSM

 

2. StateTree는 UE5의 새로운 AI 시스템으로, HSM + Behavior Tree의 장점을 결합

특징

  • 계층적 상태
  • 선택자 (Selector): 조건에 따라 상태 선택
  • 태스크 (Task): 상태에서 실행할 동작
  • 평가자 (Evaluator): 조건 평가
  • GAS 연동: GameplayTag 기반 조건

 

3. Behavior Tree는 FSM의 대안

FSM Behavior Tree
상태 중심 행동 중심
전환 명시적 전환 자동 (우선순위)
다이어그램: 그래프 다이어그램: 트리

UBehaviorTreeComponent가 틱마다

  1. 루트부터 내려가며 조건(Decorator) 평가
  2. 우선순위에 맞는 경로를 선택
  3. 선택된 Task를 실행(진행 중이면 계속 Tick)

📌전환을 명시적으로 연결한다기보다 조건/우선순위로 자동 선택한다

 

4. Gameplay Ability System (GAS)는 Tag 기반 FSM

'내배캠Unreal_TIL > UE' 카테고리의 다른 글

[TIL] 2026-01-26 | Attribute System  (0) 2026.01.26
[TIL] 2026-01-23 | 캐릭터 에셋 끄적거리기, 리깅이 안되어 있을 때  (4) 2026.01.23
[TIL] 2026-01-22 | UE GameplayTags  (0) 2026.01.22
[TIL] 2026-01-21 | UE 게임 기초 시스템 구현  (0) 2026.01.21
[TIL] 2026-01-20 | 과제 6에 타이머로 자동문 추가  (2) 2026.01.20
'내배캠Unreal_TIL/UE' 카테고리의 다른 글
  • [TIL] 2026-01-26 | Attribute System
  • [TIL] 2026-01-23 | 캐릭터 에셋 끄적거리기, 리깅이 안되어 있을 때
  • [TIL] 2026-01-22 | UE GameplayTags
  • [TIL] 2026-01-21 | UE 게임 기초 시스템 구현
윤윤씨
윤윤씨
🎮 내일배움캠프 Unreal 7기
  • 윤윤씨
    컴퓨터온열맛사지
    윤윤씨
  • 전체
    오늘
    어제
    • 분류 전체보기 (62) N
      • 내배캠Unreal_TIL (62) N
        • C++ (23)
        • UE (31) N
        • 팀프로젝트 (7)
      • etc (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
    • Solved.ac
    • YouTube
  • 태그

    스테이트머신
    오토마타
    코드카타
    디자인패턴
    ta
    챌린지
    언리얼과제
    머티리얼
    프로그래머스
    gas
    STL
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.6
윤윤씨
[TIL] 2026-01-22 | Automata, State Machine
상단으로

티스토리툴바