와와

캐릭터 움직임 구현2: 상태 패턴 본문

개발/Unity 3D

캐릭터 움직임 구현2: 상태 패턴

정으주 2023. 6. 20. 22:57

 
플레이어 조작은 상태패턴으로 구현했다..!  

 

 

상태 패턴(State Pattern)

- 객체 지향 프로그래밍에서 사용되는 디자인 패턴
- 객체의 상태에 따라 동작이 달라지는 상황에서 유용하게 사용
- 상태를 클래스로 표현하고, 각 상태마다 해당 상태에서의 동작을 정의하는 방식으로 구성
 

  1. Context(상태를 가지는 객체): 상태 패턴을 적용할 객체 또는 컨텍스트를 나타냅니다. 이 객체는 상태를 가지며, 현재의 상태에 따라 다른 동작을 수행하게 됩니다. 컨텍스트는 상태 객체와 상호작용하며, 상태 전환을 요청하거나 현재 상태에서의 동작을 수행합니다.
  2. State(상태): 상태 패턴에서 상태를 나타내는 인터페이스 또는 추상 클래스입니다. 이 인터페이스는 컨텍스트의 각 상태에서 수행되어야 할 동작을 선언합니다. 주로 상태마다 하나의 메서드로 정의되며, 컨텍스트가 상태에 따라 호출하게 됩니다.
  3. Concrete State(구체적인 상태): State 인터페이스를 구현한 클래스로, 실제로 각 상태에서 동작하는 메서드를 구현합니다. 각 구체적인 상태 클래스는 해당 상태에서 수행되어야 할 동작을 정의하며, 컨텍스트가 요청하는 메서드를 구현하여 동작을 수행합니다. 구체적인 상태 클래스는 컨텍스트에 의해 생성되고 관리됩니다.

 


 
 
 

내 플레이어는
총 4가지 상태로 구성되어 있다.

    public enum PLAYER_STATE
    {
        IDLE,
        RUN,
        JUMP,
        CLIMB
    }

 
각각 상태 클래스에 구현될 인터페이스

public interface IState
{
    void Enter();
    void Execute();
    void FixedExecute();
    void Exit();
}

 
 
 
다음은 상태 컨트롤러다.

- 따라하지 마시오 -

 
첨엔 요딴식으로 코드를 짰었는데 매 순간마다 새로운 상태를 생성해내서 아주 과부하가 왔었다.
정신차리고 상태마다 딕셔너리에 넣어 재활용했다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Enums;
  
public class PlayerStateController : MonoBehaviour
{
    public PLAYER_STATE currentPlayerState;
    public IState currentState;

    private readonly Dictionary<PLAYER_STATE, IState> stateDictionary = new Dictionary<PLAYER_STATE, IState>();


    private void Awake()
    {

        // 기본 상태를 Idle로 설정
        currentPlayerState = PLAYER_STATE.IDLE;
        currentState = new IdleState(this);

        stateDictionary.Add(PLAYER_STATE.IDLE, new IdleState(this));
        stateDictionary.Add(PLAYER_STATE.RUN, new RunState(this));
        stateDictionary.Add(PLAYER_STATE.JUMP, new JumpState(this));
        stateDictionary.Add(PLAYER_STATE.CLIMB, new ClimbState(this));

    }

    private void Start()
    {
        currentState.Enter();
    }

    private void Update()
    {
        currentState.Execute();
    }

    private void FixedUpdate()
    {
        currentState.FixedExecute();
    }

    public void ChangeState(PLAYER_STATE newState)
    {
        if (currentState != null)
        {
            currentState.Exit();
        }

        currentState = stateDictionary[newState];
        currentPlayerState = newState;
        currentState.Enter();
    }
}

 
 
 
 
이제 각 상태마다 클래스를 만들어 주면 된다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Enums;
 
public class RunState : IState
{
    private PlayerStateController stateController;
    

    public RunState(PlayerStateController playerStateController)
    {
        this.stateController = playerStateController;
    }

    public void Enter()
    {
        //Debug.Log("Run Enter()");
    }

    public void Execute()
    {
        //Debug.Log("Run Execute()");
    }

    public void FixedExecute()
    {    
    }

    public void Exit()
    {
        //Debug.Log("Run Exit()");
    }
}

 
 
각 상태에서 다른 상태로 전이해야 하는 타이밍에 ChangeState()를 통해 상태 변화를 하면 된다.