
오늘은 Unity에서 상태 패턴(State Pattern)을 사용하여 캐릭터의 상태를 관리하는 방법을 배웠다. 상태 패턴은 게임에서 캐릭터의 다양한 상태(Idle, Run, Attack 등)를 효율적으로 관리하고, 상태 전환을 매끄럽게 처리할 수 있도록 도와주는 중요한 디자인 패턴이다. 이 패턴을 적용하여 Unity에서 캐릭터의 동작을 체계적으로 구현할 수 있었다.
상태 패턴은 객체의 상태에 따라 동작을 다르게 수행할 수 있게 해주는 디자인 패턴이다. 상태 패턴을 사용하면 상태별로 독립적인 클래스에서 상태 전환과 로직을 처리할 수 있어 코드의 가독성과 유지보수성이 높아진다. 이 패턴은 특히 캐릭터의 상태 관리, 예를 들어 Idle(대기), Run(달리기), Attack(공격)등등 과 같은 상황에 유용하다.
IState 인터페이스
모든 상태 클래스가 구현해야 하는 인터페이스이다. 각 상태 클래스는 이 인터페이스를 구현하여 상태 진입, 상태 실행, 상태 종료 시에 수행할 작업을 정의한다.
public interface IState
{
void Enter(); // 상태에 진입할 때 호출
void Execute(); // 상태가 활성화되어 있을 때 매 프레임 호출
void Exit(); // 상태에서 벗어날 때 호출
}
상태 클래스 구현
각 상태에 해당하는 클래스를 정의한다. 예를 들어, Idle 상태, Run 상태, Attack 상태에 대해 아래와 같이 구현해보았다.
public class IdleState : IState
{
private PlayerController playerController;
public IdleState(PlayerController controller)
{
playerController = controller;
}
public void Enter()
{
Debug.Log("대기 상태");
// playerController.SetAnimation("Idle");
}
public void Execute()
{
// Idle 상태에서는 입력을 감지하여 상태를 변경
if (Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.D))
{
playerController.ChangeState(new RunState(playerController));
}
else if (Input.GetKeyDown(KeyCode.Space))
{
playerController.ChangeState(new AttackState(playerController));
}
}
public void Exit()
{
Debug.Log("대기 상태 종료");
}
}
public class RunState : IState
{
private PlayerController playerController;
public RunState(PlayerController controller)
{
playerController = controller;
}
public void Enter()
{
Debug.Log("달리기 상태");
// playerController.SetAnimation("Run");
playerController.SetSpeed(playerController.runSpeed);
}
public void Execute()
{
// 캐릭터 이동 처리
playerController.MoveCharacter();
// 이동 입력이 없으면 Idle 상태로 전환
if (!Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.D))
{
playerController.ChangeState(new IdleState(playerController));
}
}
public void Exit()
{
Debug.Log("달리기 종료");
playerController.SetSpeed(0); // 속도를 0으로 설정
}
}
public class AttackState : IState
{
private PlayerController playerController;
public AttackState(PlayerController controller)
{
playerController = controller;
}
public void Enter()
{
Debug.Log("공격 상태");
// playerController.SetAnimation("Attack");
}
public void Execute()
{
// 공격 실행 로직
// 공격이 끝나면 Idle 상태로 전환
if (!Input.GetKey(KeyCode.Space))
{
playerController.ChangeState(new IdleState(playerController));
}
}
public void Exit()
{
Debug.Log("공격 상태 종료");
}
}
PlayerController 클래스
PlayerController 클래스는 현재 캐릭터의 상태를 관리하고, 상태 전환을 처리한다. 이 클래스는 게임 루프(Update 메서드)에서 현재 상태를 실행하고, 필요에 따라 상태를 전환한다.
public class PlayerController : MonoBehaviour
{
private StateContext stateContext;
public float runSpeed;
private void Start()
{
stateContext = new StateContext();
stateContext.SetState(new IdleState(this)); // 초기 상태를 Idle로 설정
}
private void Update()
{
stateContext.Update();
}
// 상태 전환을 위한 메서드
public void ChangeState(IState newState)
{
stateContext.SetState(newState);
}
// 애니메이션 설정 (현재 주석 처리)
// public void SetAnimation(string animationName)
// {
// GetComponent<Animator>().Play(animationName);
// }
// 속도 설정
public void SetSpeed(float speed)
{
// 캐릭터의 이동 속도 설정 로직
}
// 캐릭터 이동 처리
public void MoveCharacter()
{
// 이동 입력에 따라 캐릭터를 움직이는 로직
}
}
StateContext 클래스
StateContext 클래스는 현재 상태를 관리하고, 상태 전환 및 상태 업데이트를 처리한다. 이 클래스는 상태 패턴의 핵심 역할을 한다.
public class StateContext
{
private IState currentState;
public void SetState(IState state)
{
if (currentState != null)
{
currentState.Exit(); // 현재 상태에서 벗어날 때 Exit 메서드 호출
}
currentState = state;
currentState.Enter(); // 새로운 상태로 전환할 때 Enter 메서드 호출
}
public void Update()
{
if (currentState != null)
{
currentState.Execute(); // 현재 상태가 실행 중일 때 Execute 메서드 호출
}
}
}
오늘은 Unity에서 상태 패턴을 사용해 캐릭터의 상태 전환을 구현하는 방법을 배웠다. 상태 패턴은 각 상태를 독립적인 클래스로 분리하여 관리하고, 상태 전환 시 일관된 방법으로 상태를 변경할 수 있도록 도와준다. 이로 인해 코드의 가독성과 유지보수성이 크게 향상되었다.
애니메이션 부분은 주석 처리해 두었지만, 실제로는 상태 전환 시 Enter, Exit 메서드에서 적절한 애니메이션 전환을 처리하게 된다. 앞으로 이 패턴을 활용해 다양한 캐릭터 동작을 더욱 체계적으로 구현할 수 있을 것이다.