제목 그대로 MVC 패턴을 원래하고는 조금 다르게 유니티에 맞춰서 커스텀해보는 중이다.


이런식으로 컨트롤러 역할을 하는 프레임워크가 존재하며

매니저 클래스를 상속받은 각각의 매니저들이 모델과 뷰를 합친역할을 한다고 생각


이런식으로 설계했을때의 장점은

각각의 파트가 독립적으로 동작하게되며 디버깅의 편리함이 있다.


메세지는 Framework를 통해 전송하며 Manager 클래스를 통해서 Receive 받는다.


-------------------------------------------------------------------------------------------------


우선 Game Model이라는 Framework를 만들었다.

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameModel : MonoBehaviour {
    public const int _PlayerMan     = 0x00000001;
    public const int _KeyMan        = 0x00000010;
    public const int _AllMan        = 0x11111111;
 
    [System.Serializable]
    public class ManagerID
    {
        public string managerName = "";
        public GameObject managerObject = null;
    }
 
    [Header("Managers")]
    public ManagerID[] managers;
    private List<Manager> managerList = new List<Manager>();
    private List<Packet> packets = new List<Packet>();
    private List<Packet> delayPackets = new List<Packet>();
    void Start()
    {
        for (int i = 0; i < managers.Length; i++)
        {
            managerList.Add(managers[i].managerObject.GetComponent<Manager>());
        }
    }
 
    private void LateUpdate()
    {
        delayPackets.Clear();
        foreach (Packet pk in packets)
        {
            if(pk.dispatchTime <= Time.time)
            {
                DispatchMessage(pk);
            }
            else
            {
                delayPackets.Add(pk);
            }
        }
        packets.Clear();
        foreach(Packet pk in delayPackets)
        {
            packets.Add(pk);
        }
    }
 
    public void sendMessage(int senderID, int receiveID, PacketList packet, int iPacket, object objPacket1, object objPacket2)
    {
        Packet pk = new Packet();
        pk.senderID = senderID;
        pk.receiveID = receiveID;
        pk.packetID = packet;
        pk.iMessage = iPacket;
        pk.objMessage1 = objPacket1;
        pk.objMessage2 = objPacket2;
        sendMessage(pk);
    }
 
    public void sendMessage(Packet packet)
    {
        DispatchMessage(packet);
    }
 
    private void DispatchMessage(Packet pk)
    {
        // ex) 0x0001 -> KeyMan
        // 0x0010 -> PlayerMan
        // 0x0100 -> SoundMan
        // 0x1000 -> UIMan
 
        // 예를들어 player, sound, ui에 메세지를 다 보내고싶다면 receiveID를 0x1110으로 보낼것임.
        // receiveID = PlayerMan | SoundMan | UIMan (or연산) = 0x1110
 
        // 그러면 매니저 foreach돌면서 &(and)연산하면서 걸리면(받는다면) 그 매니저에 메세지를 보냄
        // ex) 0x0010 & 0x1110 = 0x0010 -> PlayerMan은 메세지를 받는구나 이런식
 
        foreach(Manager mn in managerList)
        {
            int bReceive = mn.managerID & pk.receiveID;
            if (bReceive != 0)
            {
                mn.ReceiveMessage(pk);
            }
        }
    }
 
    public void postMessage(int senderID, int receiveID, PacketList packet, int iPacket, object objPacket1, object objPacket2)
    {
        Packet pk = new Packet();
        pk.senderID = senderID;
        pk.receiveID = receiveID;
        pk.packetID = packet;
        pk.iMessage = iPacket;
        pk.objMessage1 = objPacket1;
        pk.objMessage2 = objPacket2;
        packets.Add(pk);
    }
 
    public void postMessage(Packet packet)
    {
        packets.Add(packet);
    }
 
    public void delayMessage(int senderID, int receiveID, PacketList packet, int iPacket, object objPacket1, object objPacket2, float lateTime)
    {
        Packet pk = new Packet();
        pk.senderID = senderID;
        pk.receiveID = receiveID;
        pk.packetID = packet;
        pk.iMessage = iPacket;
        pk.objMessage1 = objPacket1;
        pk.objMessage2 = objPacket2;
        pk.dispatchTime = Time.time + lateTime;
        packets.Add(pk);
    }
 
    public void delayMessage(Packet packet, float lateTime)
    {
        packets.Add(packet);
    }
 
    public void GetObject(int senderID, int recieveID, PacketList packet, ref object obj)
    {
        foreach (Manager mn in managerList)
        {
            int bRecive = mn.managerID & recieveID;
            if (bRecive != 0)
            {
                mn.GetObject(packet, ref obj);
            }
        }
    }
}
 
cs

메세지를 전송하는 함수는 당장 바로 보내는 sendMessage와 이후에 보낼 postMessage,

시간을 두고 나중에 보낼 delayMessage를 구현하였고, Object를 받아오는 GetObject를 만들었다.

post는 packets List에 저장하여 LateUpdate에서 보내주도록 하였고,

delay는 dispatchTime을 저장하여 일정 시간 후에 보내도록 하였다.

GetObject는 ref를 이용해서 해당 오브젝트를 찾아올수 있게 만들었다.


키값은 16진수로 각각 다른 한비트만을 사용하게 하여 

여러 사용자에게 동시에 메세지를 보내고싶을때는 or 연산을 통해 보내면 되도록하였다. (DispatchMessage)



Packet 이라는 클래스는 보낼 데이터들을 묶어 하나의 클래스로 만들었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Collections;
using System.Collections.Generic;
 
public enum PacketList
{
    PACKET_KEYDOWN = 0// iMessage : KeyCode
    PACKET_KEYUP = 1,    // iMessage : KeyCode
    PACKET_GETPLAYER = 2
}
public class Packet {
    public int senderID = 0;
    public int receiveID = 0;
    public PacketList packetID;
    public int iMessage = 0// 무슨 키를 눌렀는가
    public object objMessage1 = null;
    public object objMessage2 = null;
    public float dispatchTime = 0// 딜레이 타임
}
 
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameManager{
    private static GameManager _instance = null;
    public static GameManager Instance
    {
        get
        {
            if (_instance == null)
                _instance = new GameManager();
 
            return _instance;
        }
    }
 
    private GameModel _gameModel = null;
    private GameManager()
    {
        var gmModel = GameObject.FindGameObjectWithTag("GameModel");
        if (gmModel)
            _gameModel = gmModel.GetComponent<GameModel>();
    }
 
    public void sendMessage(int senderID, int receiveID, PacketList packet, int iPacket, object objPacket1, object objPacket2)
    {
        _gameModel.sendMessage(senderID, receiveID, packet, iPacket, objPacket1, objPacket2);
    }
 
    public void sendMessage(Packet packet)
    {
        _gameModel.sendMessage(packet);
    }
 
    public void postMessage(int senderID, int receiveID, PacketList packet, int iPacket, object objPacket1, object objPacket2)
    {
        _gameModel.postMessage(senderID, receiveID, packet, iPacket, objPacket1, objPacket2);
    }
 
    public void postMessage(Packet packet)
    {
        _gameModel.postMessage(packet);
    }
 
    public void delayMessage(int senderID, int receiveID, PacketList packet, int iPacket, object objPacket1, object objPacket2, float delayTime)
    {
        _gameModel.delayMessage(senderID, receiveID, packet, iPacket, objPacket1, objPacket2, delayTime);
    }
 
    public void delayMessage(Packet packet, float delayTime)
    {
        _gameModel.delayMessage(packet, delayTime);
    }
 
    public void GetObject(int senderID, int recieveID, PacketList packet, ref object obj)
    {
        _gameModel.GetObject(senderID, recieveID, packet, ref obj);
    }
}
 
cs



-------------------------------------------------------------------------------------------------


그리고 받는 쪽에서 베이스가 되는 매니저 클래스를 abstract로 만들어 각각 메세지를 받으면 동작할 함수를

오버라이드해서 구현하게하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public abstract class Manager : MonoBehaviour {
 
    protected int _managerID = 0;
    public int managerID
    {
        get
        {
            return _managerID;
        }
    }
 
    public abstract void ReceiveMessage(Packet pk);
    public abstract void GetObject(PacketList packet, ref object obj);
}
 
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
34
35
36
37
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class KeyManager : Manager {
    public override void GetObject(PacketList packet, ref object obj)
    {
        throw new System.NotImplementedException();
    }
    public override void ReceiveMessage(Packet pk)
    {
        throw new System.NotImplementedException();
    }
 
    void Start () {
        _managerID = GameModel._KeyMan;
    }
    void Update () {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            GameManager.Instance.sendMessage(GameModel._KeyMan, GameModel._PlayerMan, PacketList.PACKET_KEYDOWN, (int)KeyCode.Space, nullnull);
        }
        if (Input.GetKeyUp(KeyCode.Space))
        {
            GameManager.Instance.sendMessage(GameModel._KeyMan, GameModel._PlayerMan, PacketList.PACKET_KEYUP, (int)KeyCode.Space, nullnull);
        }
        if (Input.GetKeyUp(KeyCode.A))
        {
            object player = null;
            GameManager.Instance.GetObject(GameModel._KeyMan, GameModel._PlayerMan,
                PacketList.PACKET_GETPLAYER, ref player);
            GameObject p = player as GameObject;
            p.transform.position = Vector3.zero;
        }
    }
}
 
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class PlayerManager : Manager {
 
    public override void ReceiveMessage(Packet pk)
    {
        switch (pk.packetID)
        {
            case PacketList.PACKET_KEYDOWN:
                {
                    KeyDown(pk.iMessage);
                }
                break;
            case PacketList.PACKET_KEYUP:
                {
                    KeyUp(pk.iMessage);
                }
                break;
        }
    }
 
    private void KeyDown(int keyCode)
    {
        if (keyCode == (int)KeyCode.Space)
            bSpace = true;
    }
    private void KeyUp(int keyCode)
    {
        if (keyCode == (int)KeyCode.Space)
            bSpace = false;
    }
 
    private bool bSpace = false;
    public GameObject player = null;
 
    void Start () {
        _managerID = GameModel._PlayerMan;
    }
    void Update () {
        if(bSpace)
        {
            transform.position += new Vector3(10* Time.deltaTime * 2f;
        }
    }
 
    public override void GetObject(PacketList packet, ref object obj)
    {
        if (packet == PacketList.PACKET_GETPLAYER)
        {
            obj = player;
        }
    }
}
 
cs


-------------------------------------------------------------------------------------------------


동작화면


Posted by misty_
,