Unity

[Unity] 상태(State)패턴 예제

usingsystem 2024. 6. 24. 16:51
728x90

https://unity.com/kr/how-to/develop-modular-flexible-codebase-state-programming-pattern

 

스테이트 프로그래밍 패턴으로 모듈형 및 유연한 코드베이스를 개발하는 방법 | Unity

상태 프로그래밍 패턴이 깔끔하고 체계적이며 가독성 있는 코드베이스를 구축하고 유지하는 데 어떻게 도움이 되는지 알아보세요.

unity.com

간단한 상태 패턴

using UnityEngine;

public class CubeController : MonoBehaviour
{
    public enum State
    {
        Idle,
        Walk,
    }

    State _state;
    Vector3 _target;
    void Start()
    {
        _state = State.Idle;
    }
    void Update()
    {
        switch (_state)
        {
            case State.Idle:
                Idle();
                break;
            case State.Walk:
                Walk();
                break;
        }
    }
    private void GetInput()
    {
        if (Input.GetKeyDown(KeyCode.A))
            _target = transform.position + Vector3.left;
        else if (Input.GetKeyDown(KeyCode.S))
            _target = transform.position + Vector3.down;
        else if (Input.GetKeyDown(KeyCode.D))
            _target = transform.position + Vector3.right;
        else if (Input.GetKeyDown(KeyCode.W))
            _target = transform.position + Vector3.up;

        if (_target != Vector3.zero)
            _state = State.Walk;
    }
    private void Idle()
    {
        _target = Vector3.zero;
        GetInput();
    }
    private void Walk()
    {
        Vector3 distance = _target - transform.position;

        if (distance.magnitude < 0.01)
        {
            _state = State.Idle;
        }
        else
        {
            float moveDist = Mathf.Clamp(10 * Time.deltaTime, 0, distance.magnitude);
            transform.position += distance.normalized * moveDist;
        }
    }
}

 

인터페이스를 사용하여 패턴 구현하기

using UnityEngine;

public interface IState 
{
    public void Enter()
    {
        // 상태에 처음 진입할 때 실행되는 코드
    }
    public void Update()
    {
        // 프레임당 로직. 새로운 상태로 전환하는 조건 포함
    }
    public void Exit()
    {
        // 상태에서 벗어날 때 실행되는 코드
    }
}
using UnityEngine;
using static UnityEditor.Experimental.GraphView.GraphView;

public class IdleState : IState
{
    CubeController _player;
    public IdleState(CubeController player)
    {
        _player = player;
    }
    public void Enter()
    {
        // 상태에 처음 진입할 때 실행되는 코드
    }
    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            _player.Target += Vector3.left;
            _player.playerStateMachine.TransitionTo(_player.playerStateMachine.walkState);
        }
        else if (Input.GetKeyDown(KeyCode.S))
        {
            _player.Target += Vector3.down;
            _player.playerStateMachine.TransitionTo(_player.playerStateMachine.walkState);
        }
        else if (Input.GetKeyDown(KeyCode.D))
        {
            _player.Target += Vector3.right;
            _player.playerStateMachine.TransitionTo(_player.playerStateMachine.walkState);
        }
        else if (Input.GetKeyDown(KeyCode.W))
        {
            _player.Target += Vector3.up;
            _player.playerStateMachine.TransitionTo(_player.playerStateMachine.walkState);
        }
    }
    public void Exit()
    {
        // 상태에서 벗어날 때 실행되는 코드
    }
}
using System;
using Unity.Mathematics;
using UnityEngine;
using static UnityEngine.GraphicsBuffer;

public class WalkState : IState
{
    CubeController _player;
    Vector3 _target;

    public WalkState(CubeController player)
    {
        _player = player;
    }
    public void Enter()
    {
        // 상태에 처음 진입할 때 실행되는 코드
        if (_player != null)
        {
            _target = _player.Target;
        }
    }
    public void Update()
    {
        Vector3 distance = _target - _player.transform.position ;

        if (distance.magnitude < 0.01)
        {
            _player.playerStateMachine.TransitionTo(_player.playerStateMachine.idleState);
        }
        else
        {
            float moveDist = Mathf.Clamp(10 * Time.deltaTime, 0, distance.magnitude);
            _player.transform.position += distance.normalized * moveDist;
        }
    }
    public void Exit()
    {
        // 상태에서 벗어날 때 실행되는 코드
        _target = Vector3.zero;
    }
}

 

using System;
using Unity.IO.LowLevel.Unsafe;
using UnityEngine;

[Serializable]
public class StateMachine
{
    public IState CurrentState { get; private set; }
    public WalkState walkState;
    public IdleState idleState;
    public StateMachine(CubeController player)
    {
        this.walkState = new WalkState(player);
        this.idleState = new IdleState(player);
    }
    public void Initialize(IState startingState)
    {
        CurrentState = startingState;
        startingState.Enter();
    }
    public void TransitionTo(IState nextState)
    {
        CurrentState.Exit();
        CurrentState = nextState;
        nextState.Enter();
    }
    public void Update()
    {
        if (CurrentState != null)
        {
            CurrentState.Update();
        }
    }
}
using UnityEngine;
using UnityEngine.InputSystem;

public class CubeController : MonoBehaviour
{
    public StateMachine playerStateMachine;

    public Vector3 Target { get; set; } =Vector3.zero;
    void Start()
    {
        playerStateMachine = new StateMachine(this);
        playerStateMachine.Initialize(playerStateMachine.idleState);
    }
    void Update()
    {
        playerStateMachine.Update();
    }
}
728x90