C#

상태 패턴

잼잼재미 2024. 1. 9. 12:14

State 패턴?


  • 객체 내부의 상태가 변경될 때 해당 객체가 그의 행동을 변경할 수 있도록 하는 행동 디자인 패턴
  • 캐릭터는 끊임없이 상태가 전환됨
  • 캡슐화가 잘 되어있음
  • FSM과 유사하나, 상태패턴을 공부한 뒤, FSM을 사용할 것

 

기본 예시


public class PlayerController : MonoBehaviour
{
    public enum PlayerState
    {
        Die,
        Moving,
        Idle
    }

    PlayerState _state = PlayerState.Idle;

    void UpdateDie()
    {
        // ... 실행 로작 ...
    }

    void UpdateMoving()
    {
    	// ... 실행 로직 ...
    }

    void UpdateIdle()
    {
        // ... 실행 로직 ...
    }

    void Update()
    {
        switch (_state)
        {
            case PlayerState.Die:
                UpdateDie();
                break;
            case PlayerState.Moving:
                UpdateMoving();
                break;
            case PlayerState.Idle:
                UpdateIdle();
                break;
        }
    }
}

 

가장 기본적인 예시, Interface를 사용하는 것이 일반적임.

 

 

적 구현 심화 예시


  • IState : 구체적인 상태 클래스로 연결할 수 있도록 설정
  • Context : 클라이언트가 객체의 내부 상태를 변경할 수 있도록 요청하는 인터페이스를 정의

 

스크립트

IEnemyState

public interface IEnemyState
{
    void Handle(EnemyController controller);
}

 

 

EnemyStateContext

public class EnemyStateContext
{
    public IEnemyState CurrentState
    {
        get; set;
    }

    private readonly EnemyController _enemyController;

    public EnemyStateContext(EnemyController enemyController)
    {
        _enemyController = enemyController;
    }

    public void Transition()
    {
        CurrentState.Handle(_enemyController);
    }

    public void Transition(IEnemyState state)
    {
        CurrentState = state;
        CurrentState.Handle(_enemyController);
    }
}

 

 

EnemyController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyController : MonoBehaviour
{
    public EnemyStateContext _enemyStateContext { get; private set; }

    private IEnemyState _idleState;
    private IEnemyState _chasingState;
    private IEnemyState _walkState;
    private IEnemyState _attackState;

    private void Start()
    {
        _enemyStateContext = new EnemyStateContext(this);
        _idleState = gameObject.AddComponent<EnemyIdleState>();
        _chasingState = gameObject.AddComponent<EnemyChaisngState>();
        _walkState = gameObject.AddComponent<EnemyWalkState>();
        _attackState = gameObject.AddComponent<EnemyAttackState>();

        _enemyStateContext.Transition(_idleState);
    }

    public void IdleStart()
    {
        _enemyStateContext.Transition(_idleState);
    }

    public void ChasingStart()
    {
        _enemyStateContext.Transition(_chasingState);
    }

    public void WalkStart()
    {
        _enemyStateContext.Transition(_walkState);
    }
    
    public void AttackStart()
    {
        _enemyStateContext.Transition(_attackState);
    }
}

 

 

EnemyIdleState

using System.Collections;
using UnityEngine;

public class EnemyIdleState : MonoBehaviour, IEnemyState
{
    private EnemyController _enemyController;
    private float _idleTime;
    private float _time;

	// Start문과 동일하게 사용
    public void Handle(EnemyController enemyController)
    {
        if (!_enemyController)
            _enemyController = enemyController;

        Debug.Log("Idle 상태 시작");   
        _idleTime = Random.Range(_enemyController.EnemySO.MinIdleTime, _enemyController.EnemySO.MaxIdleTime);
        _time = 0;

        StartCoroutine(COUpdate());
    }

	// Update문과 동일하게 사용
    IEnumerator COUpdate()
    {
        while (true)
        {
        	// 각각의 상태 변환 조건 설정
            if (_enemyController.Distance <= _enemyController.EnemySO.SwordAttackRange)
            {
                _enemyController.AttackStart();
                break;
            }          
            if (_time >= _idleTime)
            {
                _enemyController.WalkStart();
                break;
            }
          
            yield return null;
        }
    }
}

'C#' 카테고리의 다른 글

10진수를 2진수, 8진수, 16진수로 변환  (0) 2024.02.15
제곱근 구하기 (Math.Sqrt)  (0) 2023.12.18
절대값 구하기  (1) 2023.12.06
삼각함수  (0) 2023.12.04
static (정적 변수, 정적 함수, 정적 클래스)  (0) 2023.11.23