게임에서 어떤 레버를 당기면 문이 열리고, 그 레버를 또 당기면 문이 닫힌다고 해보자. 내가 어떤 동작을 수행했을 때 내부적으로 현재 상태를 알아서 바꾸는 경우, 상태패턴을 사용하면 객체지향적으로 간단히 만들 수 있다.



플레이어가 레버를 클릭한다 -> 닫힌 상태였다면 열림 / 열린 상태였다면 닫힘.



클래스 구조를 그림으로 보면 아래와 같이 된다.


클래스 구조




함수의 호출 순서를 글로 풀어보면 아래와 같다.


1. 플레이어가 레버 앞에서 액션키를 누름 -> Lever의 Handle() 함수 실행


2. Handle()함수 안에는 context.Operate()함수가 실행됨.


3. Operate()함수 안에는 curState.Execute(DoorStateContext context, Door door)함수가 실행됨.


4. Execute(...) 함수 안에는 매개변수 door의 Open() 혹은 Close() 함수가 실행되고, 그 후에 매개변수 context의 SetState(...) 함수를 이용해서 현 상태를 바꿔줌.



플레이어는 레버를 누를 뿐이고, 그 레버는 context의 Operate()함수를 실행할 뿐이다. 그럼 하위 State 객체들이 알아서 상태를 바꿔준다.





본격적인 코드는 아래와 같다.



1
2
3
4
5
6
7
8
9
10
public class Lever : MonoBehaviour
{
    public DoorStateContext context;
 
    //플레이어가 레버를 당겼을 때 실행되는 함수
    public void Handle()
    {
        context.Operate();
    }
}
cs




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class DoorStateContext : MonoBehaviour
{
    //레버에 반응할 문 게임오브젝트.
    //유니티 인스펙터에서 드래그해서 넣어주기로 하자.
    public Door door;
 
    //열리거나 닫히거나, 현재 상태.
    public IState curState;
 
    void Start()
    {
        //기본은 닫힌 상태.
        curState = new StateClose();
    }
 
    //현재 상태의 동작을 호출해주는 함수.
    public void Operate()
    {
        curState.Execute(this, door);
    }
 
    //새로운 상태를 세팅해줄때 사용하는 함수.
    public void SetState(IState newState)
    {
        curState = newState;
    }
}
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public interface IState
{
    //상태의 행동 선언.
    void Execute(DoorStateContext context, Door door);
}
 
 
public class StateOpen : IState
{
    //상태의 행동 정의.
    public void Execute(DoorStateContext context, Door door)
    {
        //열려있다면 닫아준다.
        door.Close();
 
        //닫힘으로 상태 전환.
        context.SetState(new StateClose());
    }
}
 
 
public class StateClose : IState
{
    //상태의 행동 정의.
    public void Execute(DoorStateContext context, Door door)
    {
        //문이 닫혀있을 땐 열어준다.
        door.Open();
 
        //상태를 열림상태로 전환.
        context.SetState(new StateOpen());
    }
}
cs




1
2
3
4
5
6
7
8
9
10
11
12
public class Door : MonoBehaviour
{
    public void Open()
    {
        Debug.Log("열림");
    }
 
    public void Close()
    {
        Debug.Log("닫힘");
    }
}
cs


+ Recent posts