一个简单 小型的C#Socket网络通信库 聊天室示例(六)
这里就讲下GameRoot这个类了,业务逻辑,UI管理,收发消息 都在这里了=。=
先上代码吧:
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using UnityEngine;
using KGSocket;
using ChatNetData;
using UnityEngine.UI;
using System.IO;
using System;
public class GameRoot : MonoBehaviour
{
public KGSocketClient<ChatNetSession, ChatDatas> socketClient = new KGSocketClient<ChatNetSession, ChatDatas>();
public Queue<ChatDatas> ChatQue = new Queue<ChatDatas>();
private static readonly string obj = "lock";
public LoginPanel loginPanel;
public ChatPanel chatPanel;
public Text ErrorTxt;
public byte[] HeadData;
private void Awake()
{
loginPanel.gameObject.SetActive(true);
chatPanel.gameObject.SetActive(false);
}
void Start()
{
socketClient.StartCreate("127.0.0.1", 8895);
InItClickEvent();
}
// Update is called once per frame
void Update()
{
if (ChatQue.Count > 0)
{
lock (obj)
{
//出列 处理
ProcessNetData(ChatQue.Dequeue());
}
}
}
/// <summary>
/// 接收事件存入队列
/// </summary>
/// <param name="info"></param>
public void AddNetData(ChatDatas info)
{
lock (obj)
{
ChatQue.Enqueue(info);
}
}
/// <summary>
/// 处理接收的数据
/// </summary>
/// <param name="info"></param>
public void ProcessNetData(ChatDatas info)
{
//先判断是否有错误
if ((ErrorInfo)(info.Err) != ErrorInfo.None)
{
switch ((ErrorInfo)(info.Err))
{
case ErrorInfo.NameRepeatsErr:
StartDelayTxt("用户名重复请更换");
loginPanel.LoginBtn.interactable = true;
break;
}
return;
}
//然后判断收到的指令 做处理
switch ((CMD)(info.Cmd))
{
case CMD.None:
break;
case CMD.RspLogin:
loginPanel.gameObject.SetActive(false);
chatPanel.gameObject.SetActive(true);
chatPanel.HeadImg.LoadImage(info.HeadData);
chatPanel.PlayerNameTxt.text = info.PlayerName;
// StartCoroutine(DownloadImage(dialog.FileName, v => loginPanel.PlayerHead.texture = v));
break;
case CMD.RspChatInfo:
Debug.Log(info.PlayerName);
chatPanel.SpawnDialogUI(info.PlayerName, info.Chatdata.chat, info.HeadData.ByteToTexture(), info.Chatdata.Islocal);
break;
}
}
/// <summary>
/// 按钮绑定事件
/// </summary>
public void InItClickEvent()
{
//接收事件
socketClient.Client.OnReciveDataEvent += AddNetData;
//登录按钮
loginPanel.LoginBtn.onClick.AddListener(() =>
{
if (loginPanel.PlayerHead.texture.name== "unselected"|| loginPanel.NameInput.text=="")
{
StartDelayTxt("未选择头像或者名字为空 不能登录");
}
else
{
loginPanel.LoginBtn.interactable = false;
socketClient.Client.SendData(new ChatDatas
{
Cmd = (int)(CMD.ReqLogin),
PlayerName = loginPanel.NameInput.text,
HeadData = this.HeadData
});
}
});
loginPanel.SelectHeadBtn.onClick.AddListener(() =>
{
OpenFile();
});
// 发送消息按钮
chatPanel.SendChatBtn.onClick.AddListener(() =>
{
if (chatPanel.chatInput.text == "")
{
StartDelayTxt("发送的内容不能为空");
}
else
{
ChatDatas chat = new ChatDatas
{
Cmd = (int)(CMD.ReqChatInfo),
Chatdata = new SendChat() { chat = chatPanel.chatInput.text },
};
socketClient.Client.SendData(chat);
chatPanel.chatInput.text = "";
}
});
socketClient.SetLog((v, l) =>
{
Debug.Log(v + "Level:" + l);
});
}
private void OnDestroy()
{
socketClient.Client.mSocket.Close();
}
#region 工具
/// <summary>
/// 这个是打开选择文件的
/// </summary>
public void OpenFile()
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "PNG图片|*.png|JPG图片|*.jpg"; //过滤文件类型
dialog.InitialDirectory = UnityEngine.Application.dataPath; //定义打开的默认文件夹位置,可以在显示对话框之前设置好各种属性
if (dialog.ShowDialog() == DialogResult.OK)
{
HeadData = dialog.FileName.GetPictureBytes();
StartCoroutine(DownloadImage(dialog.FileName, v => loginPanel.PlayerHead.texture = v));
}
}
//加载路径图片
IEnumerator DownloadImage(string url, Action<Texture2D> action)
{
WWW www = new WWW(url);
yield return www;
action(www.texture);
}
/// <summary>
/// 提示错误信息文字
/// </summary>
public void StartDelayTxt(string info)
{
ErrorTxt.text = info;
StopAllCoroutines();
StartCoroutine(DelayTxt());
}
IEnumerator DelayTxt()
{
ErrorTxt.gameObject.SetActive(true);
yield return new WaitForSeconds(2);
ErrorTxt.gameObject.SetActive(false);
}
#endregion
}
这里还要添加从服务端那边生成出来的两个dll KGSocket 这个就是之前通信库的 和ChatNetData 这个是两端共用的 数据类库
一开始 会连接服务器 socketClient.StartCreate("127.0.0.1", 8895); 当然这里得定义好类KGSocketClient<ChatNetSession, ChatDatas> socketClient ,接着 全部按钮事件和别的事件初始化绑定都在InItClickEvent这里了,
接收服务器消息的事件,处理消息数据
KGSocketClient里面我写了两个 一个是回调函数** OnReciveData(T data) 在自己类调的,还有一个是回调事件Action<T> OnReciveDataEvent 给外部用的,这边图省事直接用事件OnReciveDataEvent** 了 socketClient.Client.OnReciveDataEvent += AddNetData; 所以接收消息处理在AddNetData 上 然后AddNetData 接收到会天添加到ChatQue 队列里面 在Updata里每帧判断是否有任务存在里面 如果有就就行出列 在ProcessNetData 进行数据处理 在ProcessNetData 里面会根据接收到的数据,先判断有没有错误指令Err再进行判断任务指令CMD进行对应的处理 这里可以看下代码就行了
登录按钮事件
这里会先判断 头像和名字有没有输入如果没有直接返回错误信息 不会发消息给服务器,如果都输入了直接发消息给服务器socketClient.Client.SendData(这里就是自己定义的两端都通用数据类型),CMD必须要填准确。服务器是根据CMD来进行对应的操作的
选择头像图片按钮事件
在OpenFile()这里
需要用到 System.Windows.Forms ——****Windows 的应用程序的类的OpenFileDialog 这里要using System.Windows.Forms 了 注意的是 u3d里面默认没引用这个dll的需要去u3d文件夹搜索System.Windows.Forms.dll这个文件 如图
,然后把它拖进来u3d
这里打包时候还要注意的是u3d默认环境不支持打包这个dll的所以还要设置 如图
6.png
然后就可以调用这个选择文件了 效果就是这样
7.png这里说一下代码
OpenFileDialog.Filter 就是定义选择文件的类型 我这里就写了两个图片的,你们喜欢可以自行增加** "显示在窗口的名称|.后缀名|JPG图片|.jpg" **格式就这样
OpenFileDialog.InitialDirectory 就是定义初始打开文件的位置
if (dialog.ShowDialog() == DialogResult.OK) 判断是否打开完成了 然后dialog.FileName 获取该文件的路径 字符 然后就可以进行转化byte[]数据了 用的拓展工具类的GetPictureBytes
服务器打印事件
在KGSocketClient里面所有打印事件都在KGSocketClient.SetLog 自行添加就好
[mw_shl_code=csharp,false]socketClient.SetLog((v, l) =>
{
Debug.Log(v + "Level:" + l);
});[/mw_shl_code]
发送按钮事件
和登录按钮差不多做法的
提醒错误消息的
StartDelayTxt(string info) 都在这了
还有个ChatNetSession类
这里直接继承抽象类KGNetSession<ChatDatas> 就好 没有添加什么 ,服务端那边倒是放了些缓存在里面= =懒得弄另外的缓存类了
好了整个过程了
https://github.com/LKaiGuo/KGScriptGenerator 喜欢的给我点个星星啊
u3d萌新QQ群844087555 欢迎进来灌水=。=