上一节完成了服务器连接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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class Singleton<T> where T : new() { private static readonly object sycObj = new object(); private static T t; public static T Instance { get { if (t == null) { lock (sycObj) { if (t == null) { t = new T(); } } } return t; } } } |
HandlerMediat
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 |
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using ExitGames.Client.Photon; namespace Net { public class HandlerMediat { public delegate void Act(OperationResponse t); static Dictionary<OperationCode, Delegate> messageTable = new Dictionary<OperationCode, Delegate>(); /// <summary> /// 注册监听 /// </summary> /// <param name="type"></param> /// <param name="act"></param> public static void AddListener(OperationCode type, Act act) { if (!messageTable.ContainsKey(type)) { messageTable.Add(type, null); } Delegate d = 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; } } /// <summary> /// 移除监听 /// </summary> /// <param name="type"></param> /// <param name="act"></param> public static void RemoveListener(OperationCode type, Act act) { if (messageTable.ContainsKey(type)) { Delegate d = messageTable[type]; if (d == null) { Debug.LogError(string.Format("Attempting to remove listener with for event type \"{0}\" but current listener is null.", type)); } else if (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)); } } /// <summary> /// 发送事件 /// </summary> /// <param name="type"></param> /// <param name="param"></param> public static void Dispatch(OperationCode type, OperationResponse param) { Delegate d; if (messageTable.TryGetValue(type, out d)) { Act callback = d as Act; if (callback != null) { callback(param); } else { Debug.LogError(string.Format("no such event type {0}", type)); } } } /// <summary> /// 移除所有监听 /// </summary> /// <param name="type"></param> public static void RemoveAllListener(OperationCode type) { 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
1 2 3 4 5 6 7 8 9 |
namespace Net { public enum OperationCode : byte { Login, Register, Default } } |
HandlerBase
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 |
using UnityEngine; using System.Collections; namespace Net { public abstract class HandlerBase : MonoBehaviour { public virtual void Awake() { AddListener(); } public virtual void OnDestroy() { RemoveListener(); } public abstract void AddListener(); public abstract void RemoveListener(); } } |
LoginHandler
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 |
using UnityEngine; using System.Collections; using ExitGames.Client.Photon; using System; namespace Net { public class LoginHandler : HandlerBase { /// <summary> /// 注册监听事件 /// </summary> public override void AddListener() { HandlerMediat.AddListener(OperationCode.Login, OnLoginReceived); HandlerMediat.AddListener(OperationCode.Register, OnRegisterReceived); } /// <summary> /// 移除监听事件 /// </summary> public override void RemoveListener() { HandlerMediat.RemoveAllListener(OperationCode.Login); HandlerMediat.RemoveAllListener(OperationCode.Register); } /// <summary> /// 收到登录消息 /// </summary> void OnLoginReceived(OperationResponse response) { ReturnCode returnCode = (ReturnCode)response.ReturnCode; if (returnCode == ReturnCode.Success) { //验证成功,跳转到下一个场景 Debug.LogError("用户名和密码验证成功"); } else if (returnCode == ReturnCode.Failed) { Debug.LogError("用户名或密码错误"); } } /// <summary> /// 收到注册消息 /// </summary> void OnRegisterReceived(OperationResponse response) { ReturnCode returnCode = (ReturnCode)response.ReturnCode; if (returnCode == ReturnCode.Success) { Debug.LogError("注册成功,请返回登陆"); } else if (returnCode == ReturnCode.Failed) { Debug.LogError("所用的用户名已被注册,请更改用户名"); } } } } |
LoginRequest
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 |
using UnityEngine; using System.Collections; using System.Collections.Generic; namespace Net { public class LoginRequest : Singleton<LoginRequest> { /// <summary> /// 发送登录请求 /// </summary> public void SendLoginRequest(string username, string password) { Dictionary<byte, object> data = new Dictionary<byte, object>(); data.Add(1, username); data.Add(2, password); PhotonEngine.Peer.OpCustom((byte)OperationCode.Login, data, true); } /// <summary> /// 发送注册请求 /// </summary> public void SendRegisterRequest(string username, string password) { Dictionary<byte, object> data = new Dictionary<byte, object>(); data.Add(1, username); data.Add(2, password); PhotonEngine.Peer.OpCustom((byte)OperationCode.Register, data, true); } } } |
LoginPanel
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 |
using UnityEngine; using System.Collections; using UnityEngine.UI; public class LoginPanel : MonoBehaviour { public GameObject registerPanel; public InputField usernameInput; public InputField passwordInput; public Button loginButton; public Button registerButton; /// <summary> /// 登录按钮事件,外部挂载 /// </summary> public void OnLoginButtonEvent() { string username = usernameInput.text; string password = passwordInput.text; Net.LoginRequest.Instance.SendLoginRequest(username, password); } public void OnLoginRegisterButtonEvent() { gameObject.SetActive(false); registerPanel.SetActive(true); } } |
RegisterPanel
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 |
using UnityEngine; using System.Collections; using UnityEngine.UI; public class RegisterPanel : MonoBehaviour { public GameObject loginPanel; public InputField usernameInput; public InputField passwordInput; public Button registerButton; public Button returnButton; /// <summary> /// 注册按钮事件,外部挂载 /// </summary> public void OnRegisterButtonEvent() { string username = usernameInput.text; string password = passwordInput.text; Net.LoginRequest.Instance.SendRegisterRequest(username, password); } public void OnReturnButtonEvent() { loginPanel.SetActive(true); gameObject.SetActive(false); } } |
PhotonEngine
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 |
using UnityEngine; using ExitGames.Client.Photon; using System.Collections.Generic; namespace Net { public enum ReturnCode { Success = 0, Failed = -1 } public class PhotonEngine : MonoBehaviour, IPhotonPeerListener { public static PhotonEngine Instance; private static PhotonPeer peer; public static PhotonPeer Peer//让外界可以访问我们的PhotonPeer { get { return peer; } } private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(this.gameObject); } else if (Instance != this) { Destroy(this.gameObject); return; } } // Use this for initialization void Start() { //连接服务器端 //通过Listender连接服务器端的响应 //第一个参数 指定一个Licensed(监听器) ,第二个参数使用什么协议 peer = new PhotonPeer(this, ConnectionProtocol.Udp); //连接 UDP的 Ip地址:端口号,Application的名字 peer.Connect("127.0.0.1:5055", "MyGame1"); } // Update is called once per frame void Update() { peer.Service();//需要一直调用Service方法,时时处理跟服务器端的连接 } //当游戏关闭的时候(停止运行)调用OnDestroy private void OnDestroy() { //如果peer不等于空并且状态为正在连接 if (peer != null && peer.PeerState == PeerStateValue.Connected) { peer.Disconnect();//断开连接 } } // public void DebugReturn(DebugLevel level, string message) { } //如果客户端没有发起请求,但是服务器端向客户端通知一些事情的时候就会通过OnEvent来进行响应 public void OnEvent(EventData eventData) { //switch (eventData.Code) //{ // case 1: // Debug.Log("服务器直接发送了数据过来"); // Dictionary<byte, object> 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; //} } //当我们在客户端向服务器端发起请求后,服务器端接受处理这个请求给客户端一个响应就会在这个方法里进行处理 public void OnOperationResponse(OperationResponse operationResponse) { OperationCode code = (OperationCode)operationResponse.OperationCode;//得到响应的OperationCode HandlerMediat.Dispatch(code, operationResponse); } //如果连接状态发生改变的时候就会触发这个方法。 //连接状态有五种,正在连接中(PeerStateValue.Connecting),已经连接上(PeerStateValue.Connected),正在断开连接中( PeerStateValue.Disconnecting),已经断开连接(PeerStateValue.Disconnected),正在进行初始化(PeerStateValue.InitializingApplication) public void OnStatusChanged(StatusCode statusCode) { } } } |
这一节主要做客户端的部署,下节将服务器端的部署
- 本文固定链接: http://www.u3d8.com/?p=1457
- 转载请注明: 网虫虫 在 u3d8.com 发表过