上一节完成了服务器连接MySQL数据,这节我们使用Unity连接PhotonServer服务器实现登录和注册的功能,并搭建简易框架。
在Unity客户端搭建界面
这里的客户端我还是用PhotonServer(二)创建unity客户端里面的客户端,有不懂的可自行去了解.这里我把上次测试的PhotonText脚本取消了,这里不需要。
Unity客户端脚本部署
UI搭建完成后,这步我们来部署脚本。
一、首先是工具类Singleton封装的单例脚本
二、消息订阅分发类HandlerMediat,用于分发接收到的服务器消息。如果不太懂观察者模式使用的 可以参考:消息订阅分发机制的实际应用
三、HandlerMediat类对应的枚举OperationCode,该枚举值是与服务器消息类型保持一致。记录该消息是属于什么类型,比如用户登录消息、用户注册消息、获取背包消息等等
四、创建监听服务器消息抽象基类HandlerBase
五、创建监听服务器登录消息类LoginHandler继承自:HandlerBase,这里因为登录和注册消息比较简单,所以我统一放在了登录消息类里。
该类建完后,在登录场景中创建物体, 命名为“Handler”,并挂载LoginHandler脚本
六、消息发送类LoginRequest,同样这里将登录消息和注册消息都放在了该类里
七、UI脚本,我们创建LoginPanel和RegisterPanel分别管理登录界面和注册界面的UI。这里为了方便,所有UI都是外部挂载上去的。
八、修改第二节挂载的PhotonEngine脚本。添加一个ReturnCode枚举值,对应服务器消息成功失败。在OnOperationResponse方法里处理接收到的消息。
为了方便管理,有关网络的脚本,都上了Net命名空间,在调用的时候要注意下。
Singleton
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
publicclassSingletonwhereT:new()
{
privatestaticreadonlyobjectsycObj=newobject();
privatestaticTt;
publicstaticTInstance
{
get
{
if(t==null)
{
lock(sycObj)
{
if(t==null)
{
t=newT();
}
}
}
returnt;
}
}
}
HandlerMediat
C#
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
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem;
usingExitGames.Client.Photon;
namespaceNet
{
publicclassHandlerMediat
{
publicdelegatevoidAct(OperationResponset);
staticDictionarymessageTable=newDictionary();
///
/// 注册监听
///
///
///
publicstaticvoidAddListener(OperationCodetype,Actact)
{
if(!messageTable.ContainsKey(type))
{
messageTable.Add(type,null);
}
Delegated=messageTable[type];
if(d!=null&&d.GetType()!=act.GetType())
{
Debug.LogError(string.Format(“Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}”,type,d.GetType().Name,act.GetType().Name));
}
else
{
messageTable[type]=(Act)messageTable[type]+act;
}
}
///
/// 移除监听
///
///
///
publicstaticvoidRemoveListener(OperationCodetype,Actact)
{
if(messageTable.ContainsKey(type))
{
Delegated=messageTable[type];
if(d==null)
{
Debug.LogError(string.Format(“Attempting to remove listener with for event type \”{0}\” but current listener is null.”,type));
}
elseif(d.GetType()!=act.GetType())
{
Debug.LogError(string.Format(“Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}”,type,d.GetType().Name,act.GetType().Name));
}
else
{
messageTable[type]=(Act)messageTable[type]-act;
if(d==null)
{
messageTable.Remove(type);
}
}
}
else
{
Debug.LogError(string.Format(“Attempting to remove listener for type \”{0}\” but Messenger doesn’t know about this event type.”,type));
}
}
///
/// 发送事件
///
///
///
publicstaticvoidDispatch(OperationCodetype,OperationResponseparam)
{
Delegated;
if(messageTable.TryGetValue(type,outd))
{
Actcallback=dasAct;
if(callback!=null)
{
callback(param);
}
else
{
Debug.LogError(string.Format(“no such event type {0}”,type));
}
}
}
///
/// 移除所有监听
///
///
publicstaticvoidRemoveAllListener(OperationCodetype)
{
if(messageTable.ContainsKey(type))
{
messageTable[type]=null;
messageTable.Remove(type);
}
else
{
Debug.LogError(string.Format(“Attempting to remove listener for type \”{0}\” but Messenger doesn’t know about this event type.”,type));
}
}
}
}
OperationCode
C#
1
2
3
4
5
6
7
8
9
namespaceNet
{
publicenumOperationCode:byte
{
Login,
Register,
Default
}
}
HandlerBase
C#
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
usingUnityEngine;
usingSystem.Collections;
namespaceNet
{
publicabstractclassHandlerBase:MonoBehaviour
{
publicvirtualvoidAwake()
{
AddListener();
}
publicvirtualvoidOnDestroy()
{
RemoveListener();
}
publicabstractvoidAddListener();
publicabstractvoidRemoveListener();
}
}
LoginHandler
C#
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
usingUnityEngine;
usingSystem.Collections;
usingExitGames.Client.Photon;
usingSystem;
namespaceNet
{
publicclassLoginHandler:HandlerBase
{
///
/// 注册监听事件
///
publicoverridevoidAddListener()
{
HandlerMediat.AddListener(OperationCode.Login,OnLoginReceived);
HandlerMediat.AddListener(OperationCode.Register,OnRegisterReceived);
}
///
/// 移除监听事件
///
publicoverridevoidRemoveListener()
{
HandlerMediat.RemoveAllListener(OperationCode.Login);
HandlerMediat.RemoveAllListener(OperationCode.Register);
}
///
/// 收到登录消息
///
voidOnLoginReceived(OperationResponseresponse)
{
ReturnCodereturnCode=(ReturnCode)response.ReturnCode;
if(returnCode==ReturnCode.Success)
{
//验证成功,跳转到下一个场景
Debug.LogError(“用户名和密码验证成功”);
}
elseif(returnCode==ReturnCode.Failed)
{
Debug.LogError(“用户名或密码错误”);
}
}
///
/// 收到注册消息
///
voidOnRegisterReceived(OperationResponseresponse)
{
ReturnCodereturnCode=(ReturnCode)response.ReturnCode;
if(returnCode==ReturnCode.Success)
{
Debug.LogError(“注册成功,请返回登陆”);
}
elseif(returnCode==ReturnCode.Failed)
{
Debug.LogError(“所用的用户名已被注册,请更改用户名”);
}
}
}
}
LoginRequest
C#
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
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
namespaceNet
{
publicclassLoginRequest:Singleton
{
///
/// 发送登录请求
///
publicvoidSendLoginRequest(stringusername,stringpassword)
{
Dictionarydata=newDictionary();
data.Add(1,username);
data.Add(2,password);
PhotonEngine.Peer.OpCustom((byte)OperationCode.Login,data,true);
}
///
/// 发送注册请求
///
publicvoidSendRegisterRequest(stringusername,stringpassword)
{
Dictionarydata=newDictionary();
data.Add(1,username);
data.Add(2,password);
PhotonEngine.Peer.OpCustom((byte)OperationCode.Register,data,true);
}
}
}
LoginPanel
C#
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
usingUnityEngine;
usingSystem.Collections;
usingUnityEngine.UI;
publicclassLoginPanel:MonoBehaviour{
publicGameObjectregisterPanel;
publicInputFieldusernameInput;
publicInputFieldpasswordInput;
publicButtonloginButton;
publicButtonregisterButton;
///
/// 登录按钮事件,外部挂载
///
publicvoidOnLoginButtonEvent()
{
stringusername=usernameInput.text;
stringpassword=passwordInput.text;
Net.LoginRequest.Instance.SendLoginRequest(username,password);
}
publicvoidOnLoginRegisterButtonEvent()
{
gameObject.SetActive(false);
registerPanel.SetActive(true);
}
}
RegisterPanel
C#
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
usingUnityEngine;
usingSystem.Collections;
usingUnityEngine.UI;
publicclassRegisterPanel:MonoBehaviour{
publicGameObjectloginPanel;
publicInputFieldusernameInput;
publicInputFieldpasswordInput;
publicButtonregisterButton;
publicButtonreturnButton;
///
/// 注册按钮事件,外部挂载
///
publicvoidOnRegisterButtonEvent()
{
stringusername=usernameInput.text;
stringpassword=passwordInput.text;
Net.LoginRequest.Instance.SendRegisterRequest(username,password);
}
publicvoidOnReturnButtonEvent()
{
loginPanel.SetActive(true);
gameObject.SetActive(false);
}
}
PhotonEngine
C#
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
usingUnityEngine;
usingExitGames.Client.Photon;
usingSystem.Collections.Generic;
namespaceNet
{
publicenumReturnCode
{
Success=0,
Failed=-1
}
publicclassPhotonEngine:MonoBehaviour,IPhotonPeerListener
{
publicstaticPhotonEngineInstance;
privatestaticPhotonPeerpeer;
publicstaticPhotonPeerPeer//让外界可以访问我们的PhotonPeer
{
get
{
returnpeer;
}
}
privatevoidAwake()
{
if(Instance==null)
{
Instance=this;
DontDestroyOnLoad(this.gameObject);
}
elseif(Instance!=this)
{
Destroy(this.gameObject);return;
}
}
// Use this for initialization
voidStart()
{
//连接服务器端
//通过Listender连接服务器端的响应
//第一个参数 指定一个Licensed(监听器) ,第二个参数使用什么协议
peer=newPhotonPeer(this,ConnectionProtocol.Udp);
//连接 UDP的 Ip地址:端口号,Application的名字
peer.Connect(“127.0.0.1:5055″,”MyGame1”);
}
// Update is called once per frame
voidUpdate()
{
peer.Service();//需要一直调用Service方法,时时处理跟服务器端的连接
}
//当游戏关闭的时候(停止运行)调用OnDestroy
privatevoidOnDestroy()
{
//如果peer不等于空并且状态为正在连接
if(peer!=null&&peer.PeerState==PeerStateValue.Connected)
{
peer.Disconnect();//断开连接
}
}
//
publicvoidDebugReturn(DebugLevellevel,stringmessage)
{
}
//如果客户端没有发起请求,但是服务器端向客户端通知一些事情的时候就会通过OnEvent来进行响应
publicvoidOnEvent(EventDataeventData)
{
//switch (eventData.Code)
//{
// case 1:
// Debug.Log(“服务器直接发送了数据过来”);
// Dictionary data = eventData.Parameters;
// object intValue; object StringValue;
// data.TryGetValue(1, out intValue);
// data.TryGetValue(2, out StringValue);
// Debug.Log(“收到服务器的数据信息:” + intValue.ToString() + StringValue.ToString());
// break;
// default:
// break;
//}
}
//当我们在客户端向服务器端发起请求后,服务器端接受处理这个请求给客户端一个响应就会在这个方法里进行处理
publicvoidOnOperationResponse(OperationResponseoperationResponse)
{
OperationCodecode=(OperationCode)operationResponse.OperationCode;//得到响应的OperationCode
HandlerMediat.Dispatch(code,operationResponse);
}
//如果连接状态发生改变的时候就会触发这个方法。
//连接状态有五种,正在连接中(PeerStateValue.Connecting),已经连接上(PeerStateValue.Connected),正在断开连接中( PeerStateValue.Disconnecting),已经断开连接(PeerStateValue.Disconnected),正在进行初始化(PeerStateValue.InitializingApplication)
publicvoidOnStatusChanged(StatusCodestatusCode)
{
}
}
}
这一节主要做客户端的部署,下节将服务器端的部署
最后编辑:2017-11-15作者:网虫虫
分享是一种快乐;
分享是一种美德;
分享是一种幸福!