본문 바로가기
Development/멋쟁이사자처럼 게임개발 부트캠프

[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 27일차 (2) - State 패턴 횡스크롤 2D

by jjeondeuk1008 2025. 4. 18.
반응형

 

[ 목차 ]


       

      오늘의 포스팅은

      상속을 활용한 횡스크롤 2D를 간단하게 실습한 이후에

       

      게임디자인 패턴에서 배운 state 패턴 응용을 하는 것이다.

       


       

      1. 스테이트머신 패턴 응용

       

       

      이제 스테이트머신 패턴을 응용한 2D를 만들어보겠다.

       

      새로운 URP 프로젝트를 생성한다.

       

      그리고 스크립트 3개를 만든다.

      Player

      PlayerState (상태를 나타내는 객체)

      PlayerStateMachine (상태를 관리, 상태 머신)

       

       

       

      PlayerState 스크립트로 가서 (플레이어 상태를) 관리를 위한 기본 설계를 한다.

      protected PlayerStateMachine stateMachine;
      protected Player player;
      private string animBoolName;
      
      player protected 이 상태를 가진 주인공 객체 (Player 클래스 참조)
      stateMachine protected 플레이어 상태 전환을 관리하는 FSM (상태 기계)
      animBoolName private 애니메이션 Bool 트리거 이름 (Animator에 전달용)

       

       

       

       

      상태를 생성할 때 플레이어의 객체, 상태머신, 애니메이션 이름을 전달받아 초기화한다.

      public PlayerState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName)
      
      this.player = _player;
      this.stateMachine = _stateMachine;
      this.animBoolName = _animBoolName;
      

       

       

       

       

       

      그렇게 PlayerState 전체 스크립트이다.

      using UnityEngine;
      
      public class PlayerState
      {
          protected PlayerStateMachine stateMachine;
          protected Player player;
      
          private string animBoolName;
      
          public PlayerState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName)
          {
              this.player = _player;
              this.stateMachine = _stateMachine;
              this.animBoolName = _animBoolName;
          }
      
          public virtual void Enter()
          {
      
          }
      
          public virtual void Update()
          {
      
          }
      
          public virtual void Exit()
          {
      
          }
      }
      
      

       

       

       

       

      이제 PlayerStateMachine 스크립트로 간다.

       

      이 스크립트는 플레이어의 상태를 전환하고 관리하는 클래스이다.

      현재 상태를 기억하고 바꾸어주는 시스템이라고도 할 수 있다.

       

      현재 플레이어 상태가 어떤 상태인지 저장하는 변수의 프로퍼티이다.

      public PlayerState currentState { get; private set; }
      

       

       

       

       

      상태머신의 초기 상태를 설정한다.

      초기화해서 어떤 동작을 실행할 것인지에 대한 코드이다.

      public void Initialize(PlayerState _startState)
      {
          currentState = _startState;
          currentState.Enter();
      }
      
      

       

       

       

       

      상태 전환하는 코드이다.

      public void ChangeState(PlayerState _newState)
      {
          currentState.Exit();      // 이전 상태 종료 처리
          currentState = _newState; // 새 상태로 변경
          currentState.Enter();     // 새 상태 시작
      }
      

       

       

       

       

      그렇게 PlayerStateMachine 전체 코드이다.

      using UnityEngine;
      
      public class PlayerStateMachine : MonoBehaviour
      {
          public PlayerState currentState { get; private set; }
      
          //초기화
          public void Initialize(PlayerState _startState)
          {
              currentState = _startState;
              currentState.Enter();
          }
      
          //State를 바꾸어야 한다면?
          public void ChangeState(PlayerState _newState)
          {
              currentState.Exit();        //상태 종료
              currentState = _newState;   //새로운 상태
              currentState.Enter();       //상태 실행
          }
      }
      
      

       

       

       

       

      이제 새로운 스크립트 PlayerIdleState, PlayerMoveState를 생성한다.

      애니메이션의 기본 동작과 움직이는 동작을 코드 짜는 것이다.

       

       

       

      PlayerIdleState 스크립트를 PlayerState 상속으로 받게 한다.

       

       

       

      그리고 생성자 생성을 통해 PlayerState 것을 가져온다.

       

       

       

       

      그리고 재정의 생성을 통해 Enter(), Update(), Exit() 메서드를 가져온다.

       

       

       

       

      생성자 생성과 재정의 생성은 어떻게 하냐?

      class 부분에 PlayerIdleState를 더블 클릭해 범위를 잡아준 뒤에 Alt + Enter를 누르면 된다.

       

       

       

       

      그렇게 PlayerIdleStatePlayerMoveState를 설정한다.

      using UnityEngine;
      
      public class PlayerMoveState : PlayerState
      {
          public PlayerMoveState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
          {
          }
      
          public override void Enter()
          {
              base.Enter();
          }
      
          public override void Exit()
          {
              base.Exit();
          }
      
          public override void Update()
          {
              base.Update();
          }
      }
      

       

       

       

       

      Player 스크립트를 작성할 것이다.

       

      플레이어에 붙이는 메인 스크립트이다.

      플레이어가 현재 어떤 상태인지 관리하는 프로퍼티이다.

      외부에서는 읽기만 가능하고, 수정은 이 클래스에서 할 수 있다.

      public PlayerStateMachine stateMachine { get; private set; }
      

       

       

       

       

      플레이어가 가질 수 있는 상태 idle과 move

      각각 Enter() / Exit() 같은 로직을 가지며 상태 변경 시에 사용된다.

      public PlayerIdleState idleState { get; private set; }
      public PlayerMoveState moveState { get; private set; }
      

       

       

       

       

      유니티 중 가장 먼저 호출되는 함수 중 하나인 Awake()

      여기에서 상태머신과 각 상태들을 초기화한다.

      그리고 상태머신 인스턴스를 생성한다.

      private void Awake()
      {
          stateMachine = new PlayerStateMachine();
      
          idleState = new PlayerIdleState(this, stateMachine, "Idle");
          moveState = new PlayerMoveState(this, stateMachine, "Move");
      }
      

       

       

       

       

      게임 시작 시에는 idle 상태

      private void Start()
      {
          //게임 시작 시 초기 상태를 대기 상태(idle)로 설정
          stateMachine.Initialize(idleState);
      }
      

       

       

       

       

      매 프레임마다 현재 상태를 업데이트 해준다.

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

       

       

       

       

      그렇게 Player 전체 스크립트이다.

      using UnityEngine;
      
      public class Player : MonoBehaviour
      {
          public PlayerStateMachine stateMachine { get; private set; }
      
          public PlayerIdleState idleState { get; private set; }
          public PlayerMoveState moveState { get; private set; }
      
          private void Awake()
          {
              stateMachine = new PlayerStateMachine();
      
              // 각 상태 인스턴스 생성 (this: 플레이어 객체, stateMachine: 상태 머신, "Idle"/"Move": 상태 이름)
              idleState = new PlayerIdleState(this, stateMachine, "Idle");
              moveState = new PlayerMoveState(this, stateMachine, "Move");
          }
      
          private void Start()
          {
              //게임 시작 시 초기 상태를 대기 상태(idle)로 설정
              stateMachine.Initialize(idleState);
          }
      
          private void Update()
          {
              stateMachine.currentState.Update();
          }
      }
      

       

       

       

       

      이제 idle에서 move로 가는 트랜지션을 코드로 짜보겠다.

      PlayerIdleState 스크립트로 가본다.

      테스트로 N을 누르면 moveState로 가게 하는 스크립트이다.

      public override void Update()
      {
          base.Update();
      
          if (Input.GetKeyDown(KeyCode.N))
              player.stateMachine.ChangeState(player.moveState);
      }
      

       

       

       

       

      반대로 move에서 idle로 가는 스크립트를 만들어본다.

      PlayerMoveState 스크립트로 간다.

      이것도 위와 비슷하게 가지만 ChangeState(player.idleState) 부분이 바뀐다.

      public override void Update()
      {
          base.Update();
      
          if (Input.GetKeyDown(KeyCode.N))
              player.stateMachine.ChangeState(player.idleState);
      }
      

       

       


       

      일단 기본적인 상속을 통한 생성자 생성, 재정의 생성

       

      기본으로 갖추어야 할 스크립트를 실습해 보았다.

       

      아직은 이게 좋은 것일까? 생각은 드는데,

      State가 많아지면 좋을 것 같다고 생각한다.

       

      State가 적을 때에는 비효율적이지만,

      연습을 한다면 해보는 것도 좋다고 생각한다.

       

       

       

       

       

       

       

       


      목차