WeaveSocket框架-Unity太空大战游戏-客户端-3(换成Markdown富文本重写,之前排版有点乱)

客户端项目结构

客户端主要使用的类为WeaveSocketGameClientUseEZThread

using DigitalRuby.Threading;
using MyTcpCommandLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using UnityEngine;
using WeaveBase;namespace MyTcpClient
{public class WeaveSocketGameClientUseEZThread{//public Thread threadA;//public Thread threadB;//private ThreadPoolScheduler myThreadScheduler;WeaveBaseManager xmhelper = new WeaveBaseManager();/// <summary>/// 是否连接成功/// </summary>public bool isok = false;/// <summary>/// 在接收数据/// </summary>public bool isReceives = false;/// <summary>/// 是否在线了/// </summary>public bool IsOnline = false;DateTime timeout;/// <summary>/// 数据超时时间/// </summary>int mytimeout = 90;/// <summary>/// 队列中没有排队的方法需要执行/// </summary>List<TempPakeage> mytemppakeList = new List<TempPakeage>();public List<byte[]> ListData = new List<byte[]>();public string tokan;public String ip;public int port;public event ReceiveMessage ReceiveMessageEvent;public event ConnectOk ConnectOkEvent;public event ReceiveBit ReceiveBitEvent;public event TimeOut TimeOutEvent;public event ErrorMessage ErrorMessageEvent;public event JumpServer JumpServerEvent;public TcpClient tcpClient;// System.Threading.Thread receives_thread1;// System.Threading.Thread checkToken_UpdateList_thread2;SocketDataType s_datatype = SocketDataType.Json;public WeaveSocketGameClientUseEZThread(SocketDataType _type){s_datatype = _type;}#region  客户端注册类,,服务端可以按方法名调用public void AddListenClass(object obj){GetAttributeInfo(obj.GetType(), obj);//xmhelper.AddListen()//objlist.Add(obj);}public void DeleteListenClass(object obj){deleteAttributeInfo(obj.GetType(), obj);//xmhelper.AddListen()//objlist.Add(obj);}public void deleteAttributeInfo(Type t, object obj){foreach (MethodInfo mi in t.GetMethods()){InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute));if (myattribute == null){}else{xmhelper.DeleteListen(mi.Name);}}}public void GetAttributeInfo(Type t, object obj){foreach (MethodInfo mi in t.GetMethods()){InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute));if (myattribute == null){ }else{Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true);xmhelper.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type);}}}#endregion/// <summary>/// 连接服务器/// </summary>/// <param name="_ip">IP地址</param>/// <param name="_port">端口号</param>/// <param name="_timeout">过期时间</param>/// <param name="_takon">是否takon</param>/// <returns></returns>public bool StartConnect(string _ip, int _port, int _timeout, bool _takon){mytimeout = _timeout;ip = _ip;port = _port;return StartConnectToServer(ip, port, _takon);}public bool RestartConnectToServer(bool takon){return StartConnectToServer(ip, port, takon);}private bool StartConnectToServer(string _ip, int _port, bool _takon){try{if (s_datatype == SocketDataType.Json && ReceiveMessageEvent == null)Debug.Log("没有注册receiveServerEvent事件");if (s_datatype == SocketDataType.Json && ReceiveBitEvent == null)Debug.Log("没有注册receiveServerEventbit事件");ip = _ip;port = _port;//tcpClient = new TcpClient(ip, port);tcpClient = new TcpClient();//  tcpc.ExclusiveAddressUse = false;try{tcpClient.Connect(ip, port);}catch{return false;}IsOnline = true;isok = true;timeout = DateTime.Now;if (!isReceives){isReceives = true;/*开始执行线程开始*/// myThreadScheduler = Loom.CreateThreadPoolScheduler();//--------------- Ending Single threaded routine 单线程程序结束--------------------// threadA = Loom.StartSingleThread(ReceivesThread, null, System.Threading.ThreadPriority.Normal, true);//--------------- Ending Single threaded routine 单线程程序结束--------------------//--------------- Continues Single threaded routine 在单线程的程序--------------------// threadB = Loom.StartSingleThread(CheckToken_UpdateListDataThread, System.Threading.ThreadPriority.Normal, true);//--------------- Continues Single threaded routine  在单线程的程序--------------------/*开始执行线程结束*//*改用新的EZThreading插件的方法开始*/EZThread.ExecuteInBackground(() => ReceivesThread());EZThread.ExecuteInBackground(() => CheckToken_UpdateListDataThread());/*改用新的EZTheading插件的方法结束*/}int ss = 0;if (!_takon)return true;while (tokan == null){// System.Threading.Thread.Sleep(1000);// Loom.WaitForNextFrame(10);Loom.WaitForSeconds(1);ss++;if (ss > 10)return false;}if (ConnectOkEvent != null)ConnectOkEvent();return true;}catch (Exception e){IsOnline = false;if (ErrorMessageEvent != null)ErrorMessageEvent(1, e.Message);return false;}}#region  几个方法的方法public bool SendParameter<T>(byte command, String Request, T Parameter, int Querycount){WeaveBase.WeaveSession b = new WeaveBase.WeaveSession();b.Request = Request;b.Token = this.tokan;b.SetParameter<T>(Parameter);b.Querycount = Querycount;return SendStringCheck(command, b.Getjson());}public bool SendRoot<T>(byte command, String Request, T Root, int Querycount){WeaveBase.WeaveSession b = new WeaveBase.WeaveSession();b.Request = Request;b.Token = this.tokan;b.SetRoot<T>(Root);b.Querycount = Querycount;return SendStringCheck(command, b.Getjson());}public void Send(byte[] b){tcpClient.Client.Send(b);}public bool SendStringCheck(byte command, string text){try{//byte[] sendb = System.Text.Encoding.UTF8.GetBytes(text);//byte[] part3_length = System.Text.Encoding.UTF8.GetBytes(sendb.Length.ToString());//byte[] b = new byte[2 + part3_length.Length + sendb.Length];//b[0] = command;//b[1] = (byte)part3_length.Length;//part3_length.CopyTo(b, 2);//扩充 第四部分数据(待发送的数据)的长度,扩充到b数组第三位开始的后面//sendb.CopyTo(b, 2 + part3_length.Length);//扩充 第四部分数据实际的数据,扩充到b数组第三部分结尾后面...byte[] b = MyGameClientHelper.CodingProtocol(command, text);int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1);if (count == 0){//判定数据长度,,实际指的是大小是不是小于40kb,,,tcpClient.Client.Send(b);}else{for (int i = 0; i < count; i++){int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960);byte[] temp = new byte[zz];Array.Copy(b, i * 40960, temp, 0, zz);tcpClient.Client.Send(temp);//分割发送......System.Threading.Thread.Sleep(1);}}}catch (Exception ee){IsOnline = false;CloseConnect();if (TimeOutEvent != null)TimeOutEvent();SendStringCheck(command, text);if (ErrorMessageEvent != null)ErrorMessageEvent(9, "send:" + ee.Message);return false;}// tcpc.Close();return true;}public bool SendByteCheck(byte command, byte[] text){try{//byte[] sendb = text;//byte[] lens = MyGameClientHelper.ConvertToByteList(sendb.Length);//byte[] b = new byte[2 + lens.Length + sendb.Length];//b[0] = command;//b[1] = (byte)lens.Length;//lens.CopyTo(b, 2);//sendb.CopyTo(b, 2 + lens.Length);byte[] b = MyGameClientHelper.CodingProtocol(command, text);int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1);if (count == 0){tcpClient.Client.Send(b);}else{for (int i = 0; i < count; i++){int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960);byte[] temp = new byte[zz];Array.Copy(b, i * 40960, temp, 0, zz);tcpClient.Client.Send(temp);System.Threading.Thread.Sleep(1);// Loom.WaitForNextFrame(10);// Loom.WaitForSeconds(0.001f);}}}catch (Exception ee){IsOnline = false;CloseConnect();if (TimeOutEvent != null)TimeOutEvent();SendByteCheck(command, text);if (ErrorMessageEvent != null)ErrorMessageEvent(9, "send:" + ee.Message);return false;}// tcpc.Close();return true;}#endregion/// <summary>/// 通过主线程执行方法避免跨线程UI问题/// </summary>public void OnTick(){if (mytemppakeList.Count > 0){try{TempPakeage str = mytemppakeList[0];//xmhelper.Init(str.date, null);//receiveServerEvent(str.command, str.date);}catch{}try{mytemppakeList.RemoveAt(0);}catch { }}Debug.Log("队列中没有排队的方法需要执行。");}public void CloseConnect(){try{isok = false;IsOnline = false;//发送我要断开连接的消息this.SendRoot<int>((byte)CommandEnum.ClientSendDisConnected, "OneClientDisConnected", 0, 0);// receives_thread1.Abort();//checkToken_UpdateList_thread2.Abort();tcpClient.Close();AbortThread();}catch{Debug.Log("CloseConnect失败,发生异常");}}void AbortThread(){//EZThreading插件有 自带Destory方法自动检测UNITY程序关闭事件触发,这里什么都不用写}/// <summary>/// 接收到服务器发来的数据的处理方法/// </summary>/// <param name="obj"></param>void ReceiveData(object obj){TempPakeage str = obj as TempPakeage;mytemppakeList.Add(str);if (ReceiveMessageEvent != null)ReceiveMessageEvent(str.command, str.date);}/// <summary>/// 线程启动的方法,初始化连接后要接收服务器发来的token,并更新/// </summary>void CheckToken_UpdateListDataThread(){while (isok){System.Threading.Thread.Sleep(10);try{int count = ListData.Count;if (count > 0){int bytesRead = ListData[0] != null ? ListData[0].Length : 0;if (bytesRead == 0)continue;//如果到这里的continue内部,那么下面的代码不执行,重新到 --》 System.Threading.Thread.Sleep(10);开始byte[] tempbtye = new byte[bytesRead];//解析消息体ListData,,Array.Copy(ListData[0], tempbtye, tempbtye.Length);// 检查tempbtye(理论上里面应该没有0x99,有方法已经处理掉了,但是可能会有)检测还有没有0x99开头的心跳包_0x99:if (tempbtye[0] == 0x99){if (bytesRead > 1){byte[] b = new byte[bytesRead - 1];byte[] t = tempbtye;//把心跳包0x99去掉Array.Copy(t, 1, b, 0, b.Length);ListData[0] = b;tempbtye = b;goto _0x99;}else{   //说明只有1个字节,心跳包包头,无任何意思,那么直接删除ListData.RemoveAt(0);continue;}}//ListData[0]第一个元素的长度 大于2if (bytesRead > 2){//第二段是固定一个字节,最高255,代表了第三段的长度//这样第三段最高可以255*255位,这样表示数据内容的长度基本可以无限大了// int a = tempbtye[1];int part3_Length = tempbtye[1];//tempbtye既是ListData[0]数据,//第一位为command,指令//第二位的数据是第三段的长度//第三段的数据是第四段的长度//第四段是内容数据if (bytesRead > 2 + part3_Length){   //如果收到数据这段数据,大于// int len = 0;int part4_Length = 0;if (s_datatype == SocketDataType.Bytes){byte[] bb = new byte[part3_Length];byte[] part4_LengthBitArray = new byte[part3_Length];//将tempbtye从第三位开始,复制数据到part4_LengthBitArrayArray.Copy(tempbtye, 2, part4_LengthBitArray, 0, part3_Length);//len = ConvertToInt(bb);//获得实际数据的长度,也就是第四部分数据的长度part4_Length = MyGameClientHelper.ConvertToInt(part4_LengthBitArray);}else{   //如果DataType不是DataType.bytes类型,,, 是Json类型//从某个Data中第三位开始截取数据,,获取第四段数据长度的字符串stringString temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length);String part4_Lengthstr = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length);part4_Length = 0;//len = 0;//int part4_Lengthstrlength = 0;try{// len = int.Parse(temp);part4_Length = int.Parse(part4_Lengthstr);if (part4_Length == 0)  //len{   //如果第四段数据的长度为0 ,,,说明发的空消息,,没有第四段数据//如果第二位没有数据,,说明发的是空消息ListData.RemoveAt(0);continue;}}catch{}}try{//如果计算出来的(2位数据位+第三段长度+第四度长度) 比当前ListData[0]长度还大...if ((part4_Length + 2 + part3_Length) > tempbtye.Length){if (ListData.Count > 1){//将第一个数据包删除ListData.RemoveAt(0);//重新读取第一个数据包(第二个数据包变为第一个)内容byte[] temps = new byte[ListData[0].Length];//将 数据表内容 拷贝到 temps中Array.Copy(ListData[0], temps, temps.Length);//新byte数组长度扩充,原数据长度 + (第二个)元素长度byte[] temps2 = new byte[tempbtye.Length + temps.Length];Array.Copy(tempbtye, 0, temps2, 0, tempbtye.Length);//将第一个元素ListData[0]完全从第一个地址开始 ,完全拷贝到 temps2数组中Array.Copy(temps, 0, temps2, tempbtye.Length, temps.Length);//将第二个元素拼接到temps2中,从刚复制数据的最后一位 +1 开始ListData[0] = temps2;//最后将更新数据包里面的 第一个元素为新元素}else{System.Threading.Thread.Sleep(20);}continue;}else if (tempbtye.Length > (part4_Length + 2 + part3_Length)){//如果 数据包长度 比  计算出来的(2位数据位+第三段长度+第四度长度)  还大 //考虑大出的部分int currentAddcount = (part4_Length + 2 + part3_Length);int offset_length = tempbtye.Length - currentAddcount;byte[] temps = new byte[offset_length];//Array.Copy(tempbtye, (part4_Length + 2 + part3_Length), temps, 0, temps.Length);Array.Copy(tempbtye, currentAddcount, temps, 0, temps.Length);//把当前ListData[0]中 后面的数据,复制到 temps数组中...ListData[0] = temps;}else if (tempbtye.Length == (part4_Length + 2 + part3_Length)){   //长度刚好匹配ListData.RemoveAt(0);}}catch (Exception e){if (ErrorMessageEvent != null)ErrorMessageEvent(3, e.StackTrace + "unup001:" + e.Message + "2 + a" + 2 + part3_Length + "---len" + part4_Length + "--tempbtye" + tempbtye.Length);}try{if (s_datatype == SocketDataType.Json){//读取出第四部分数据内容,,string temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2 + part3_Length, part4_Length);TempPakeage str = new TempPakeage();str.command = tempbtye[0];//命令等于第一位 str.date = temp;//服务器发来执行是0xff,说明发送的是token指令if (tempbtye[0] == 0xff){if (temp.IndexOf("token") >= 0)tokan = temp.Split('|')[1];//用单个字符来分隔字符串,并获取第二个元素,,//这里因为服务端发来的token后面跟了一个|字符else if (temp.IndexOf("jump") >= 0){//0xff就是指服务器满了tokan = "连接数量满";if (JumpServerEvent != null)JumpServerEvent(temp.Split('|')[1]);}else{  // 当上面条件都不为真时执行 ,如果虽然指令是0xff,但是不包含token或jumpReceiveData(str);}}else if (ReceiveMessageEvent != null){//如果tempbtye[0] == 0xff 表示token,不等的情况ReceiveData(str);}}//if (DT == DataType.bytes)//{//    byte[] bs = new byte[len - 2 + a];//    Array.Copy(tempbtye, bs, bs.Length);//    temppake str = new temppake();//    str.command = tempbtye[0];//    str.datebit = bs;//    rec(str);//}continue;}catch (Exception e){if (ErrorMessageEvent != null)ErrorMessageEvent(3, e.StackTrace + "unup122:" + e.Message);}}}else{   // //ListData[0]第一个元素的Length 不大于2 ,,  if (tempbtye[0] == 0)ListData.RemoveAt(0);}}}catch (Exception e){if (ErrorMessageEvent != null)ErrorMessageEvent(3, "unup:" + e.Message + "---" + e.StackTrace);try{ListData.RemoveAt(0);}catch { }}}}/// <summary>/// 接收数据到缓冲区的方法/// </summary>/// <param name="obj"></param>void ReceivesThread(  ){while (isok){System.Threading.Thread.Sleep(50);try{//可以用TcpClient的Available属性判断接收缓冲区是否有数据,来决定是否调用Read方法int bytesRead = tcpClient.Client.Available;if (bytesRead > 0){//缓冲区byte[] tempbtye = new byte[bytesRead];try{timeout = DateTime.Now;//从绑定接收数据 Socket 到接收缓冲区中tcpClient.Client.Receive(tempbtye);_0x99:if (tempbtye[0] == 0x99){   //如果缓冲区第一个字符是 0x99心跳包指令timeout = DateTime.Now;//记录现在的时间if (tempbtye.Length > 1){//去掉第一个字节,长度总体减去1个,byte[] b = new byte[bytesRead - 1];try{//复制 Array 中的一系列元素(从指定的源索引开始),//并将它们粘贴到另一 Array 中(从指定的目标索引开始)//原始 Array 为tempbtye,原始Array的初始位置//另外一个 目标 Array , 开始位置为0,长度为b.LengthArray.Copy(tempbtye, 1, b, 0, b.Length);//那么b中的到的就是去掉心跳包指令0x99以后的后面的数据}catch { }tempbtye = b;//反复执行去掉,心跳包,,,goto _0x99;}elsecontinue;//后面的不执行了,回调到 上面的while循环开始 重新执行...}}catch (Exception ee){if (ErrorMessageEvent != null)ErrorMessageEvent(22, ee.Message);}//lock (this)//{//将接收到的 非心跳包数据加入到 ListData中ListData.Add(tempbtye);// }}//线程每隔指定的过期时间秒,判定,如果没有数据发送过来,,,tcpc.Client.Available=0 情况下else{try{TimeSpan ts = DateTime.Now - timeout;if (ts.TotalSeconds > mytimeout){  //判断时间过期IsOnline = false;CloseConnect();//isreceives = false;if (TimeOutEvent != null)TimeOutEvent();if (ErrorMessageEvent != null)ErrorMessageEvent(2, "连接超时,未收到服务器指令");continue;}}catch (Exception ee){if (ErrorMessageEvent != null)ErrorMessageEvent(21, ee.Message);}}}catch (Exception e){if (ErrorMessageEvent != null)ErrorMessageEvent(2, e.Message);}}}}
}

调用生成客户端实例的单例类MainClient

using UnityEngine;
using System.Collections;
using GDGeek;
using MyTcpClient;
using System;
using UnityEngine.SceneManagement;
using WeaveBase;
using MyTcpCommandLibrary;
using UnityEngine.Events;
using MyTcpCommandLibrary.Model;public class MainClient : Singleton<MainClient>
{//public WeaveSocketGameClient weaveSocketGameClient;public WeaveSocketGameClientUseEZThread weaveSocketGameClient;public ServerBackLoginEvent serverBackLoginEvent =new ServerBackLoginEvent();public SetLoginTempModelEvent setLoginTempModelEvent = new SetLoginTempModelEvent();public SetGameScoreTempModelEvent setGameScoreTempModelEvent = new SetGameScoreTempModelEvent();public FirstCheckServerEvent firstCheckServerEvent = new FirstCheckServerEvent();public GameScoreTempModel GameScore;public LoginTempModel loginUserModel;// Use this for initializationvoid Start(){DontDestroyOnLoad(this);setLoginTempModelEvent.AddListener(SetLoginModel);}public string receiveMessage;public void InvokeSetLoginTempModelEvent(LoginTempModel _model){setLoginTempModelEvent.Invoke(_model);}GameScoreTempModel tempGameScore;public void CallSetGameScoreTempModelEvent(GameScoreTempModel gsModel){// StartCoroutine(CallSetGameScoreEvent(gsModel));tempGameScore = gsModel;}IEnumerator CallSetGameScoreEvent(GameScoreTempModel gsModel){yield return new WaitForSeconds(0.5f);setGameScoreTempModelEvent.Invoke(gsModel);}// Update is called once per framevoid Update(){//if (receiveMessage.Length != 0)//{//    receiveMessage = string.Empty;//}if (canLoadSceneFlag){LoadGameScene();canLoadSceneFlag = false;}if (weaveSocketGameClient != null)weaveSocketGameClient.OnTick();if(tempGameScore != null){StartCoroutine(CallSetGameScoreEvent(tempGameScore));tempGameScore = null;}}public void ConnectToServer(string serverIp,int port){try{//  weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json);weaveSocketGameClient = new  WeaveSocketGameClientUseEZThread(SocketDataType.Json);weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent;weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent;weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent;weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent;weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent;//pcp2.AddListenClass(new MyClientFunction());Debug.Log("初始化OK");//bool bb = pcp2.start("61.184.86.126", 10155, false);// bool bb = weaveSocketGameClient.StartConnect("61.184.86.126", 10155, 30, false);bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false);Debug.Log("链接OK");firstCheckServerEvent.Invoke(bb);}catch{firstCheckServerEvent.Invoke(false);}}void CallServerFunc(){try{//weaveSocketGameClient.SendRoot<int>(0x02, "login", 11111, 0);//在加个发送weaveSocketGameClient.tokan = "UnityTokan";weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);//调用服务端方法getnum,是服务端的方法。//这样就可以了,我们试试}catch (Exception e){Debug.Log(e.ToString());}}private void OnTimeOutEvent(){Debug.Log("连接超时");//throw new NotImplementedException();}private void OnReceiveBitEvent(byte command, byte[] data){Debug.Log("收到了Bit数据");// throw new NotImplementedException();}private void OnErrorMessageEvent(int type, string error){Debug.Log("发生了错误");//throw new NotImplementedException();}private void OnReceiveMessageEvent(byte command, string text){// throw new NotImplementedException();Debug.Log("收到了新数据");//throw new NotImplementedException();receiveMessage = "指令:" + command + ".内容:" + text;Debug.Log("原始数据是:" + receiveMessage);try{WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root);}catch{Debug.Log("Json转换对象出错了");}// receiveMessage = "指令:" + command + ".内容:" + text;Debug.Log("收到的信息是:" + receiveMessage);ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command);ICheckServerMessage checkSmsg = factory.CheckServerMessage();checkSmsg.CheckServerMessage(text);}private void OnConnectOkEvent(){Debug.Log("已经连接成功");}private void StopConnect(){if (weaveSocketGameClient != null){weaveSocketGameClient.CloseConnect();weaveSocketGameClient.ConnectOkEvent -= OnConnectOkEvent;weaveSocketGameClient.ReceiveMessageEvent -= OnReceiveMessageEvent;weaveSocketGameClient.ErrorMessageEvent -= OnErrorMessageEvent;weaveSocketGameClient.ReceiveBitEvent -= OnReceiveBitEvent;weaveSocketGameClient.TimeOutEvent -= OnTimeOutEvent;// weaveSocketGameClient = null;}}public  void SendLogin(LoginTempModel user ){try{// weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);StartCoroutine(  WaitSendLogin(user)  );Debug.Log("SendLoginFunc");}catch (Exception e){Debug.Log(e.ToString());}}IEnumerator WaitSendLogin(LoginTempModel user){yield return new WaitForSeconds(0.2f);weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);}public void SendCheckUserScore(){try{LoginTempModel user = loginUserModel;// weaveSocketGameClient.Tokan = "UnityTokan";// weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0);Debug.Log("SendLoginFunc");}catch (Exception e){Debug.Log(e.ToString());}}public void SendNewScoreUpdate(int _score,int _missed){try{GameScoreTempModel gsModel = new GameScoreTempModel(){userName = loginUserModel.userName,missenemy = _missed,score = _score};//LoginTempModel user = loginUserModel;// weaveSocketGameClient.Tokan = "UnityTokan";// weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0);Debug.Log("UpdateScore");}catch (Exception e){Debug.Log(e.ToString());}}public int sceneIndex;public bool canLoadSceneFlag;void LoadGameScene(){SceneManager.LoadScene(1);}public void SetLoadSceneFlag(){canLoadSceneFlag = true;}void OnDestroy(){//SetLoginModelEvent.RemoveListener(SetLoginModel);}private void SetLoginModel(LoginTempModel _model){loginUserModel = _model;}private void OnApplicationQuit(){StopConnect();}}public class SetLoginTempModelEvent : UnityEvent<LoginTempModel> { }public class SetGameScoreTempModelEvent : UnityEvent<GameScoreTempModel> { }public class ServerBackLoginEvent : UnityEvent<bool>{}public class FirstCheckServerEvent : UnityEvent<bool> { }

登陆页面的控制类LoginHandler

using MyTcpCommandLibrary.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class LoginHandler : MonoBehaviour {public InputField input_Username;public InputField input_Password;public InputField input_ServerIP;public InputField input_ServerPort;public Text server_msg_text;public Button login_button;// public LoginModel userModel;// Use this for initializationvoid Start() {MainClient.Instance.serverBackLoginEvent.AddListener(GetServerBackLoginEvent);MainClient.Instance.firstCheckServerEvent.AddListener(firstCheckServerConfigEvent);}private void firstCheckServerConfigEvent(bool connectToServerResult){// throw new NotImplementedException();connectedServerOK = connectToServerResult;}public void SetServerIP_Connected(){string ip = input_ServerIP.text;int port = int.Parse(input_ServerPort.text);if(connectedServerOK ==false)MainClient.Instance.ConnectToServer(ip, port);}private void GetServerBackLoginEvent(bool arg0){//throw new NotImplementedException();server_msg = "登陆失败,账号密码错误...";}public bool connectedServerOK = false;public void Login(){LoginTempModel model = new LoginTempModel(){userName = input_Username.text,password = input_Password.text,//userName = "ssss",//password = "yyyyyy",logintime = System.DateTime.Now.ToString("yyyyMMddHHmmssfff")};// userModel = model;MainClient.Instance.InvokeSetLoginTempModelEvent(model);MainClient.Instance.SendLogin(model);}private string server_msg = "";public void SetServerMsgShow(string serverMsg){server_msg_text.text = serverMsg;}void OnDestroy(){MainClient.Instance.serverBackLoginEvent.RemoveListener(GetServerBackLoginEvent);MainClient.Instance.firstCheckServerEvent.RemoveListener(firstCheckServerConfigEvent);}// Update is called once per framevoid Update () {if( string.IsNullOrEmpty( server_msg) ==false || server_msg.Length >2){SetServerMsgShow(server_msg);login_button.gameObject.SetActive(true);server_msg = "";}}
}

登陆界面图

游戏场景UI数据控制类GameScoreHandler


using UnityEngine;
using System.Collections;using UnityEngine.Events;
using UnityEngine.UI;
using System;
using MyTcpCommandLibrary.Model;public class GameScoreHandler : MonoBehaviour
{public static UpdateScoreEvent updateScoreEvent = new UpdateScoreEvent();public static UpdateLivesEvent updateLivesEvent = new UpdateLivesEvent();public static UpdateMissedEvent updateMissedEvent = new UpdateMissedEvent();public static UnityEvent SendUpdateScoreEvent = new UnityEvent();// public static UnityEvent<GameScoreTempModel> SetGameScoreUI;public Text userNameText;public Text now_scoreText;public Text now_livesText;public Text now_missedText;public Text serverText;public Text last_scoreText;public Text last_missedText;// Use this for initializationvoid Start(){updateScoreEvent.AddListener( OnUpdateScore);updateLivesEvent.AddListener(OnUpdateLives);updateMissedEvent.AddListener(OnUpdateMissed);SendUpdateScoreEvent.AddListener(OnSendUpdateScore);MainClient.Instance.setGameScoreTempModelEvent.AddListener(SetLastData);}private void OnSendUpdateScore(){//throw new NotImplementedException();serverText.text = "积分已发往服务器...";}private void OnUpdateScore(int _score){now_scoreText.text = "积分:" + _score.ToString();}void OnDestory(){updateScoreEvent.RemoveListener(OnUpdateScore);updateLivesEvent.RemoveListener(OnUpdateLives);updateMissedEvent.RemoveListener(OnUpdateMissed);SendUpdateScoreEvent.RemoveListener(OnSendUpdateScore);MainClient.Instance.setGameScoreTempModelEvent.RemoveListener(SetLastData);}private void OnUpdateLives(int _lives){now_livesText.text = "生命:" + _lives.ToString();}private void OnUpdateMissed(int _missed){now_missedText.text = "放走敌人:" + _missed.ToString();}private void OnDestroy(){}public void SetUserNameData(string _uname){userNameText.text = _uname;}public void SetLastData(GameScoreTempModel gsModel){//userNameText.text = "生命:" + gsModel.userName;//last_scoreText.text = "积分:" + gsModel.score.ToString();//last_missedText.text = "放走敌人:" + gsModel.missenemy.ToString();tempScore = gsModel;}public void SetLastDataText(){userNameText.text = "生命:" + tempScore.userName;last_scoreText.text = "积分:" + tempScore.score.ToString();last_missedText.text = "放走敌人:" + tempScore.missenemy.ToString();}public void SetNowDate(int _lives, int _lastScore, int _lastMissed){now_livesText.text ="生命:"+ _lives.ToString();now_scoreText.text = "积分:" + _lastScore.ToString();now_missedText.text = "放走敌人:" + _lastMissed.ToString();}GameScoreTempModel tempScore;// Update is called once per framevoid Update(){if(tempScore != null){SetLastDataText();tempScore = null;}}public void ReloadGameScene(){//跳转场景MainClient.Instance.SetLoadSceneFlag();//发送读取上次分数数据的逻辑MainClient.Instance.SendCheckUserScore();}}
public class UpdateScoreEvent: UnityEvent<int> { }
public class UpdateLivesEvent : UnityEvent<int> { }
public class UpdateMissedEvent : UnityEvent<int> { }

游戏场景界面图

客户端和服务器通信逻辑


启动程序


玩家输入账号密码


点击登陆按钮


调用MainClient里面的ConnectToServer 方法 ,再调用MainClient里面的 SendLogin 方法(有个等待0.2秒)

public void ConnectToServer(string serverIp,int port){try{//  weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json);weaveSocketGameClient = new  WeaveSocketGameClientUseEZThread(SocketDataType.Json);weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent;weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent;weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent;weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent;weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent;//pcp2.AddListenClass(new MyClientFunction());Debug.Log("初始化OK");//bool bb = pcp2.start("61.184.86.126", 10155, false);// bool bb = weaveSocketGameClient.StartConnect("61.184.86.126", 10155, 30, false);bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false);Debug.Log("链接OK");firstCheckServerEvent.Invoke(bb); //Unity内部分发事件告诉其它脚本,服务器已经连接上了,可以进行数据通信了}catch{//Unity内部分发事件告诉其它脚本,服务器连接失败,不允许执行发送账号密码的操作firstCheckServerEvent.Invoke(false);}}

 public  void SendLogin(LoginTempModel user ){try{// weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);StartCoroutine(  WaitSendLogin(user)  );Debug.Log("SendLoginFunc");}catch (Exception e){Debug.Log(e.ToString());}}IEnumerator WaitSendLogin(LoginTempModel user){yield return new WaitForSeconds(0.2f);weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);}

连接服务器(如果成功),继续发送账号密码到服务器的命令


服务器接收账号密码,进行查找数据库操作


调用了MyTcpCommandLibrary项目中的LoginManageCommand类的CheckLogin方法(具体LiteDB操作数据的代码不再细说,源码一看就明白了)

[InstallFun("forever")]  public void CheckLogin(Socket soc, WeaveSession wsession)  {  LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();  //执行查找数据的操作......  bool loginOk = false;  //添加测试账号,如有已经存在数据则return不执行AddSystemData();  loginOk = CheckUserCanLoginIn(get_client_Send_loginModel);  if (loginOk)  {  // 发送有玩家成功登陆服务器事件,用于通知前端更新UserListBox登陆后的用户列表   ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);  }  SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token);  //发送人数给客户端  //参数1,发送给客户端对象,//参数2,发送给客户端对应的方法,//参数3,人数的实例,//参数4,此处无作用,//参数5,客户端此次token  }  

发送查找结果给客户端……


如果客户端接收到服务器发过来的登陆成功消息(跳转到游戏场景)

using UnityEngine;
using System.Collections;
using System;
using WeaveBase;
public class LoginMessage : ICheckServerMessage
{public void CheckServerMessage( string text){// throw new NotImplementedException();WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);Debug.Log("收到的消息是:"+text);if(ws.Request == "ServerBackLoginResult" ){if( ws.GetRoot<bool>() == true){//如果登陆成功,,处理的逻辑......//先更新用户//跳转场景MainClient.Instance.SetLoadSceneFlag();//向发送读取上次分数数据的逻辑MainClient.Instance.SendCheckUserScore();}else{//Unity内部分发登陆失败的消息,不允许跳转场景MainClient.Instance.serverBackLoginEvent.Invoke(false);}}}}

数据处理工厂接收到命令调用LoginMessageFactory,并返回一个具体的ICheckServerMessage接口实现类LoginMessage


调用它的CheckServerMessage方法


如果接收到服务器发来的True,那么跳转场景(并且执行向服务器发送查找登陆用户的上次积分的命令),否则不跳转场景,提示用户账号密码错误


(进入游戏场景)


等待接收服务器发来的历史积分数据,并设置到UI上面来

using UnityEngine;
using System.Collections;
using System;
using WeaveBase;
using MyTcpCommandLibrary.Model;public class GameScoreMessage : ICheckServerMessage
{public void CheckServerMessage(string text){// throw new NotImplementedException();WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);Debug.Log("收到的GameScoreMessage消息是:" + text);if (ws.Request == "ServerSendGameScore"){GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>();if (gsModel != null ){MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel);//unity内部分发事件,传递给UI界面,用于更新数据显示}else{//服务器返回了一个空积分数据,没找到....}}}
}

当玩家的战机生命Lives为0时,向服务器发送本次游戏积分数据,显示一个【再玩一次】按钮


        if ( Lives == 0){// SceneManager.LoadScene(2);//向服务器发送数据 ,,并读取排行数据,,,Debug.Log("要发送的数据是:Score:"+Score +"  Missed:"+ Missed);MainClient.Instance.SendNewScoreUpdate( Score, Missed);yield return new WaitForSeconds(1f);//等待1秒后显示【再玩一次】按钮reloadSceneButton.gameObject.SetActive(true);Missed = 0;}

  public void SendNewScoreUpdate(int _score,int _missed){try{GameScoreTempModel gsModel = new GameScoreTempModel(){userName = loginUserModel.userName,missenemy = _missed,score = _score};//LoginTempModel user = loginUserModel;// weaveSocketGameClient.Tokan = "UnityTokan";// weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0);Debug.Log("UpdateScore");}catch (Exception e){Debug.Log(e.ToString());}}

服务器收到玩家本次游戏积分数据,进行数据库更新操作(根据用户名)


调用了服务端MyTcpCommandLibrary项目中的GameScoreCommand类的UpdateScore方法(具体LiteDB操作数据的代码不再细说,源码一看就明白了)

       [InstallFun("forever")]  public void UpdateScore(Socket soc, WeaveSession wsession)  {  GameScoreTempModel gsModel = wsession.GetRoot<GameScoreTempModel>();  //执行数据更新的操作......  bool updateSocreResult = UpdateUserScore(gsModel.userName, gsModel.score , gsModel.missenemy);  if (updateSocreResult)  {  // 向客户端发送 更新积分成功的信息  SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token);  }  else  {  // 向客户端发送 更新积分失败的信息  SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token);  //发送人数给客户端  //参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token  }  }  

点击【再玩一次】按钮

  public void ReloadGameScene(){//跳转场景MainClient.Instance.SetLoadSceneFlag();//发送读取上次分数数据的逻辑MainClient.Instance.SendCheckUserScore();}

游戏再次开始

其它Unity3d逻辑代码很简单,这里不再细说

WeaveSocket官方QQ群17375149

项目地址:https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows/tree/master/Example

本节到此结束,未完待续

WeaveSocket框架-Unity太空大战游戏-客户端-3相关推荐

  1. 太空大战--游戏ui和战斗管理

    太空大战–游戏UI和战斗管理 创建显示得分的UI界面 在Hierarchy视图中选择Create->UI->Canvas创建一个UI的根节点. 选中创建的Canvas,选择Create-& ...

  2. 对 Unity 太空射击游戏的实践

    写在前面 # 本次 Space Shooter 实践通过实现以下功能达到加深对 U3D 游戏开发的认知. 键盘控制飞船移动; 发射子弹设计目标; 随机生成大量障碍物; 计分; 实现游戏对象的生命周期管 ...

  3. python趣味编程-太空大战

    在上一期我们用Python实现了一个坦克大战的游戏,这一期我们继续使用Python实现一个简单的太空大战游戏,让我们开始今天的旅程吧~ Python中的太空战争游戏免费源代码 这 Python的太空战 ...

  4. 太空大战-第14届蓝桥杯国赛Scratch真题中级组第6题

    [导读]:超平老师的<Scratch蓝桥杯真题解析100讲>已经全部完成,后续会不定期解读蓝桥杯真题,这是Scratch蓝桥杯真题解析第148讲. 太空大战,本题是2023年5月28日上午 ...

  5. 用Unity快速开发太空飞机大战游戏实战经验分享(上)

    用unity动手先来试试一个简单的太空飞机大战吧.看官请继续往下... 最终效果,可控制己方战机,朝目标敌机发射子弹,打飞机~~~!伴随想象,慢慢呈现这个太空飞机大战游戏. 1. 新建打飞机unity ...

  6. 视频教程-Unity经典案例再现《太空大战》-Unity3D

    Unity经典案例再现<太空大战> 专注于VR/游戏研发八年,精通各种常用语言,熟练使用Unity和UE4引擎开发. 张建飞 ¥12.00 立即订阅 扫码下载「CSDN程序员学院APP」, ...

  7. 初学者Unity项目--太空大战

    太空大战算是比较经典的游戏了.这两天在跟着视频自学了一下.能做到的效果就是飞机发出子弹打爆陨石,如果被陨石碰到就死掉.简单的赤果果.界面如下: 现在做个总结:(模型声音之类的是导入的资源包.) 很明显 ...

  8. Unity如何搭建游戏框架

    Unity作为全球最知名的游戏引擎之一,功能已经做的非常完善了,为什么我们还要在开发项目的时候需要搭建游戏框架呢?基于Unity来搭建一个游戏框架,我们又应该如何思考,如何做?今天给大家分享一些Uni ...

  9. 学习 ET(1)- 开源的游戏客户端(基于 unity3d)服务端双端框架

    我: 客户端程序员,15+ 以上 C++ 编码经历, 还算扎实.Unity 编码经历 1年,C# 没有单独学过.真不想离开C++的世界,大形势驱使进入了Unity+C#世界. ET - 开源的游戏客户 ...

  10. unity太空射击源码_引擎入门 | 创建双杆射击游戏(入门 2)

    点击上方"蓝字"关注我们吧! 本期我们继续为大家进行双杆射击游戏的后续教程 学习内容 3.整理资产 4.导入资产 5.安装 Blender 6.导入包 文章末尾可免费获取教程源代码 ...

最新文章

  1. 慢动作频闪怎么解决_Vlog的视频解决方案——索尼A6400
  2. 继清华之后,北邮成立人工智能研究院
  3. Spark配置属性整理(非常全面)
  4. cnpm在ubuntu19.10下面的安装以及vue.js中el的意思
  5. 取多补少C语言,leetcode题目: 数字的补数 的C语言解法
  6. Unreal engine 4 C++ 一些调试用的绘制函数
  7. 欢迎关注我的微信公众账号:Linux技巧(微信号:irefactoring),一起学习Linux知识~~~...
  8. VMware新建虚拟机
  9. 计算机网络和物联网的区别与联系,3.5.2 从网络端系统接入的角度看互联网与物联网的区别与联系...
  10. ie无法下载 无法打开该internet站点.请求的站点不可用或无法找到.请稍后重试
  11. mfc与win32区别
  12. 谈谈Java的学习方法
  13. 首页技术支持常见问题宽带外网IP显示为10、100、172开头,没有公网IP,如何解决?...
  14. 高精度地图:自动驾驶的向导
  15. Linux运维常用知识(1)
  16. 鸟哥Linux私房菜:第七章笔记
  17. signaturenonce php,php微信公众平台开发--接入微信API
  18. 77.4%份额,环信高居SaaS移动端客服市场第一的背后
  19. 从头开始构建,DeepMind新论文用伪代码详解Transformer
  20. android preference 启动activity,Android PreferenceActivity 学习笔记

热门文章

  1. SpringMVC整合activiti Modeler
  2. 操作系统不等于 Linux,六问操作系统新时代 | 1024 程序员节
  3. SpringBoot2.x系列教程84--SpringBoot中整合日志功能
  4. 2022年成考(专升本)考试政治练习题及答案
  5. 【王木头学科学|深度学习】3.神经网络是什么?如何直接理解它的能力极限?它是如何无线逼近真理的
  6. 简明现代魔法 php,PHP生成强密码
  7. 计算机围棋涉及知识,围棋知识介绍
  8. NLP-文本摘要:Rouge评测方法【Rouge-1、Rouge-2、Rouge-L、Rouge-W、Rouge-S】
  9. Android 7.1.1源码下载
  10. 指针生成网络(Pointer-Generator Networks)的实现