客户端界面
客户端实现注册
客户端对注册结果的处理
创建脚本获取UI界面元素
创建 LoginView.cs 获取UI界面中的组件以及添加上事件
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LoginView : MonoBehaviour
{
public static LoginView Instance;
[Header("login组件")]
public InputField l_username;
public InputField l_password;
public Button l_loginBtn;
public Button l_registerBtn;
[Header("Register组件")]
public GameObject registerView;
public InputField r_username;
public InputField r_password;
public InputField r_email;
public Button r_registerBtn;
public Button r_closeBtn;
[Header("TipsItem组件")]
public GameObject _tipsObj;//缓存
public GameObject tipsItem;
public GameObject chatObj;
void Start()
{
Instance = this;
Init();
}
private void Init()
{
//获取组件
//登录界面组件获取
l_username = transform.Find("UsernameInput").GetComponent<InputField>();
l_password = transform.Find("PasswordInput").GetComponent<InputField>();
l_loginBtn = transform.Find("LoginBtn").GetComponent<Button>();
l_registerBtn = transform.Find("RegisterBtn").GetComponent<Button>();
//注册界面组件获取
registerView = transform.Find("Register").gameObject;
r_username = transform.Find("Register/View/UsernameInput").GetComponent<InputField>();
r_password = transform.Find("Register/View/PasswordInput").GetComponent<InputField>();
r_email = transform.Find("Register/View/EmailInput").GetComponent<InputField>();
r_registerBtn = transform.Find("Register/View/RegisterBtn").GetComponent<Button>();
r_closeBtn = transform.Find("Register/View/CloseBtn").GetComponent<Button>();
//UI提示
tipsItem = transform.Find("TipsItem").gameObject;
//添加事件
l_loginBtn.onClick.AddListener(LoginBtnClick);
l_registerBtn.onClick.AddListener(RegisterBtn1Click);
r_registerBtn.onClick.AddListener(RegisterBtn2Click);
r_closeBtn.onClick.AddListener(CloseBtnClick);
}
void LoginBtnClick()
{
}
void RegisterBtn1Click()
{
}
void RegisterBtn2Click()
{
}
void CloseBtnClick()
{
}
void Tips(string str)
{
if(_tipsObj != null)
{
Destroy(_tipsObj);
}
//克隆提示物体
_tipsObj = Instantiate(tipsItem, transform);
//修改提示显示文本
Text content = _tipsObj.GetComponentInChildren<Text>();
content.text = str;
//显示文本
_tipsObj.SetActive(true);
//使物体存在1.5秒后删除
Destroy(_tipsObj, 1.5f);
}
}
创建 ChatView.cs 获取UI界面中的组件以及添加上事件
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChatView : MonoBehaviour
{
public Button closeBtn;
void Start()
{
//获取组件
closeBtn = transform.Find("Popup_Dark/Menu Icon").GetComponent<Button>();
//添加事件
closeBtn.onClick.AddListener(LogoutHandle);
}
private void LogoutHandle()
{
}
}
创建json对象
创建 Module.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public partial class Module
{
//客户端向服务端发送的数据对象
public class RegisterMsgC2S
{
public string username;
public string email;
public string password;
}
//服务端向客户端发送的数据对象
public class RegisterMsgS2C
{
public string username;
public string email;
public string password;
public int result;//0:注册成功 1:账号已被注册
}
}
修改 MsgManager.cs 将switch中添加结果方法
创建一个Action 用于处理注册返回结果
public Action<Module.RegisterMsgS2C> registerHandle;
switch (id)
{
case 1001://注册请求结果
MsgHelper.RegisterMsgHandler(body);
break;
case 1002://登录请求结果
MsgHelper.LoginMsgHandler(body);
break;
case 1003://聊天请求结果
MsgHelper.ChatMsgHandler(body);
break;
case 1004://退出登录
MsgHelper.LogoutMsgHandler(body);
break;
default:
Debug.Log("其他ID,还没有该业务逻辑!!!");
break;
}
在MsgHelper.cs中现实 MsgManager.cs 中的业务处理方法
在 MsgHelper.cs 中实现方法
/// <summary>
/// 处理注册(结果)业务
/// </summary>
/// <param name="data"></param>
public static void RegisterMsgHandler(byte[] data)
{
//将接收到的数据进行格式转化
var str =Encoding.UTF8.GetString(data);
//将数据反序列化
var result = JsonHelper.ToObject<Module.RegisterMsgS2C>(str);
//触发回调函数
Client.Instance.msgManager.registerHandle?.Invoke(result);
}
/// <summary>
/// 处理登录(结果)业务
/// </summary>
/// <param name="data"></param>
public static void LoginMsgHandler(byte[] data)
{
}
/// <summary>
/// 处理聊天(转发)业务
/// </summary>
/// <param name="data"></param>
public static void ChatMsgHandler(byte[] data)
{
}
/// <summary>
/// 处理退出登录业务
/// </summary>
/// <param name="data"></param>
public static void LogoutMsgHandler(byte[] data)
{
}
}
注册 Action
修改 LoginView.cs,在Init 方法中对Action 进行注册
private void Init()
{
//获取组件
l_username = transform.Find("UsernameInput").GetComponent<InputField>();
l_password = transform.Find("PasswordInput").GetComponent<InputField>();
l_loginBtn = transform.Find("LoginBtn").GetComponent<Button>();
l_registerBtn = transform.Find("RegisterBtn").GetComponent<Button>();
registerView = transform.Find("Register").gameObject;
r_username = transform.Find("Register/View/UsernameInput").GetComponent<InputField>();
r_password = transform.Find("Register/View/PasswordInput").GetComponent<InputField>();
r_email = transform.Find("Register/View/EmailInput").GetComponent<InputField>();
r_registerBtn = transform.Find("Register/View/RegisterBtn").GetComponent<Button>();
r_closeBtn = transform.Find("Register/View/CloseBtn").GetComponent<Button>();
tipsItem = transform.Find("TipsItem").gameObject;
//添加事件
l_loginBtn.onClick.AddListener(LoginBtnClick);
l_registerBtn.onClick.AddListener(RegisterBtn1Click);
r_registerBtn.onClick.AddListener(RegisterBtn2Click);
r_closeBtn.onClick.AddListener(CloseBtnClick);
//处理登录注册结果
Client.Instance.msgManager.registerHandle += RegisterHandle;
}
private void RegisterHandle(Module.RegisterMsgS2C c)
{
if (c.result == 0)
{
Tips("注册成功");
Debug.Log("注册成功");
registerView.SetActive(false);
l_username.text = c.username;
l_password.text = c.password;
}
else
{
Tips("帐号已存在");
}
}
客户端对注册消息进行发送
修改LoginView.cs,完成两个按钮的事件
/// <summary>
/// 打开注册界面
/// </summary>
void RegisterBtn1Click()
{
registerView.SetActive(true);
}
/// <summary>
/// 发送注册消息
/// </summary>
void RegisterBtn2Click()
{
//判断输入
if (string.IsNullOrEmpty(r_username.text))
{
Tips("请输入账号!!!");
return;
}
if (string.IsNullOrEmpty(r_email.text))
{
Tips("请输入邮箱!!!");
return;
}
if (string.IsNullOrEmpty(r_password.text))
{
Tips("请输入密码!!!");
return;
}
//获取输入信息
string username = r_username.text;
string password = r_password.text;
string email = r_email.text;
//发送注册消息
MsgHelper.SendRegisterMsg(username, email, password);
}
/// <summary>
/// 关闭注册界面
/// </summary>
void CloseBtnClick()
{
registerView.SetActive(false);
}
在MsgHelper.cs中实现注册消息的发送
/// <summary>
/// 封装消息进行发送
/// </summary>
/// <param name="id">消息ID</param>
/// <param name="json">消息</param>
private static void SendToService(int id, string json)
{
//将消息数据封装打包成:包体大小+包体ID+包体
byte[] send_buffer = MsgHelper.MsgEncoding(id, json);
//发送消息
Client.Instance.Send(send_buffer);
}
/// <summary>
/// 发送注册消息给服务器
/// </summary>
/// <param name="username"></param>
/// <param name="email"></param>
/// <param name="pwd"></param>
public static void SendRegisterMsg(string username, string email, string pwd)
{
//实例化对象
Module.RegisterMsgC2S msg = new Module.RegisterMsgC2S();
msg.username = username;
msg.email = email;
msg.password = pwd;
//将对象序列化
var str = JsonHelper.ToJson(msg);
Debug.Log(str);
//发送消息
SendToService(1001, str);
}
服务端对注册结果的处理
创建账号数据库(简单起见这里采用类的方式将账号缓存)
创建三个脚本
OnlinePlayer.cs:记录当前是否登录
PlayerData.cs:账号数据
PlayerInfo.cs:账号信息
using Service.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Service.Player
{
internal class OnlinePlayer
{
//当前是否在线
public bool isOnline;
//当前账户名
public string username;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Service.Player
{
internal class PlayerData
{
//创建单例
public static PlayerData Instance;
//初始化
public PlayerData()
{
Instance = this;
players = new List<PlayerInfo>();
//缓存一个账号
PlayerInfo player = new PlayerInfo();
player.username = "asd";
player.email = "123@qq.com";
player.password = "123";
players.Add(player);
}
public List<PlayerInfo> players;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Service.Player
{
internal class PlayerInfo
{
public string username;
public string email;
public string password;
}
}
创建json对象
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Service.Modules
{
internal class Module
{
public class RegisterMsgC2S
{
public string username;
public string email;
public string password;
}
public class RegisterMsgS2C
{
public string username;
public string email;
public string password;
public int result;//0:注册成功 1:账号已被注册
}
}
}
修改 MsgManager.cs 将switch中添加结果方法
switch (id)
{
case 1001://注册请求
MsgHelper.RegisterMsgHandler(body, RegisterHandler);
break;
case 1002://登录业务
MsgHelper.LoginMsgHandler(body, LoginHandler);
break;
case 1003://聊天请求
MsgHelper.ChatMsgHandler(body);
break;
case 1004://退出请求
MsgHelper.LogoutMsgHandler(body, LogoutHandler);
break;
default:
client.SendToService(10000,"服务端还没有该业务!!!");
break;
}
在MsgHelper.cs中现实 MsgManager.cs 中的业务处理方法
/// <summary>
/// 处理注册业务
/// </summary>
/// <param name="data"></param>
public static void RegisterMsgHandler(byte[] data, Action<Module.RegisterMsgC2S> action)
{
//将接收到的数据进行格式转化
string str = Encoding.UTF8.GetString(data);
//将数据反序列化
var msg = JsonHelper.ToObject<Module.RegisterMsgC2S>(str);
//触发回调函数
action?.Invoke(msg);
}
/// <summary>
/// 处理登录业务
/// </summary>
/// <param name="data"></param>
public static void LoginMsgHandler(byte[] data,Action<Module.LoginMsgC2S> aciton)
{
}
/// <summary>
/// 处理聊天业务
/// </summary>
/// <param name="data"></param>
public static void ChatMsgHandler(byte[] data)
{
}
/// <summary>
/// 处理退出业务
/// </summary>
/// <param name="data"></param>
/// <param name="aciton"></param>
public static void LogoutMsgHandler(byte[] data, Action<Module.LogoutMsgC2S> aciton)
{
}
在MsgManager.cs中实现回调函数
public void RegisterHandler(Module.RegisterMsgC2S msg)
{
//查找缓存账号中是否存在
foreach (var info in PlayerData.Instance.players)
{
if (msg.username == info.username)
{
//账号已存在,注册失败
MsgHelper.SendRegisterMsg(client, info, 1);
return;
}
}
//不存在,开始注册
PlayerInfo player =new PlayerInfo();
player.username = msg.username;
player.password = msg.password;
player.email = msg.email;
PlayerData.Instance.players.Add(player);
//发送注册成功消息
MsgHelper.SendRegisterMsg(client, player, 0);
}
服务端对注册结果消息的发送
在MsgHelper.cs中实现发送方法
/// <summary>
/// 发送注册结果消息
/// </summary>
/// <param name="client">客户端</param>
/// <param name="info">注册用户信息</param>
/// <param name="result">注册结果</param>
public static void SendRegisterMsg(Client client, PlayerInfo info ,int result)
{
//创建json对象
Module.RegisterMsgS2C registerObj = new Module.RegisterMsgS2C();
registerObj.username = info.username;
registerObj.password = info.password;
registerObj.email = info.email;
registerObj.result = result;
//将json对象序列化
string json = JsonHelper.ToJson(registerObj);
//发送消息
client.SendToService(1001, json);
}
客户端实现登录与退出
客户端对登录的处理
创建json对象
public partial class Module
{
public class LoginMsgC2S
{
public string username;
public string password;
}
public class LoginMsgS2C
{
public string username;
public string password;
public int result;//0:登录成功 1:登录失败
}
public class LogoutMsgC2S
{
public string username;
public string password;
}
public class LogoutMsgS2C
{
public int type;//0:自主下线 1:被人挤掉线
}
}
在MsgHelper.cs中现实 MsgManager.cs 中的业务处理方法
创建 Action 用于处理返回结果
public Action<Module.RegisterMsgS2C> registerHandle;
public Action<Module.LoginMsgS2C> loginHandle;
public Action<string> logoutHandle;
/// <summary>
/// 处理登录(结果)业务
/// </summary>
/// <param name="data"></param>
public static void LoginMsgHandler(byte[] data)
{
//数据转化
var str = Encoding.UTF8.GetString(data);
var result = JsonHelper.ToObject<Module.LoginMsgS2C>(str);
//触发回调
Client.Instance.msgManager.loginHandle?.Invoke(result);
}
/// <summary>
/// 处理退出登录业务
/// </summary>
/// <param name="data"></param>
public static void LogoutMsgHandler(byte[] data)
{
//数据转化
var str = Encoding.UTF8.GetString(data);
var result = JsonHelper.ToObject<Module.LogoutMsgS2C>(str);
//触发回调 1:被他人挤掉线
if (result.type == 1)
{
string tips = "在其他地方登录!!!";
Client.Instance.msgManager.logoutHandle?.Invoke(tips);
}
}
注册 Action
修改 LoginView.cs,在Init 方法中对Action 进行注册
private void Init()
{
//获取组件
l_username = transform.Find("UsernameInput").GetComponent<InputField>();
l_password = transform.Find("PasswordInput").GetComponent<InputField>();
l_loginBtn = transform.Find("LoginBtn").GetComponent<Button>();
l_registerBtn = transform.Find("RegisterBtn").GetComponent<Button>();
registerView = transform.Find("Register").gameObject;
r_username = transform.Find("Register/View/UsernameInput").GetComponent<InputField>();
r_password = transform.Find("Register/View/PasswordInput").GetComponent<InputField>();
r_email = transform.Find("Register/View/EmailInput").GetComponent<InputField>();
r_registerBtn = transform.Find("Register/View/RegisterBtn").GetComponent<Button>();
r_closeBtn = transform.Find("Register/View/CloseBtn").GetComponent<Button>();
tipsItem = transform.Find("TipsItem").gameObject;
//添加事件
l_loginBtn.onClick.AddListener(LoginBtnClick);
l_registerBtn.onClick.AddListener(RegisterBtn1Click);
r_registerBtn.onClick.AddListener(RegisterBtn2Click);
r_closeBtn.onClick.AddListener(CloseBtnClick);
//处理登录注册结果
Client.Instance.msgManager.loginHandle += LoginHandle;
Client.Instance.msgManager.registerHandle += RegisterHandle;
Client.Instance.msgManager.logoutHandle += LogoutHandle;
}
实现回调函数
private void LogoutHandle(string tips)
{
Tips(tips);
//关闭聊天
if (chatObj != null)
Destroy(chatObj);
//显示登录
gameObject.SetActive(true);
l_username.text = "";
l_password.text = "";
}
private void LoginHandle(Module.LoginMsgS2C c)
{
if(c.result == 0)
{
PlayerData.Instance.LoginMsgS2C = c;
Tips("登录成功");
Debug.Log("登录成功");
this.gameObject.SetActive(false);
var chatView = Resources.Load<GameObject>("ChatView");
chatObj = Instantiate(chatView);
chatObj.AddComponent<ChatView>();
}
else
{
PlayerData.Instance.LoginMsgS2C = null;
Tips("帐号或者密码错误");
}
}
客户端登录与登出消息的发送
实现登录登出按钮
LoginView.cs 登录按钮
void LoginBtnClick()
{
//判断输入
if (string.IsNullOrEmpty(l_username.text))
{
Tips("请输入账号!!!");
return;
}
if (string.IsNullOrEmpty(l_password.text))
{
Tips("请输入密码!!!");
return;
}
//向服务端发送登录
string username = l_username.text;
string password = l_password.text;
MsgHelper.SendLoginMsg(username, password);
}
ChatView.cs登出按钮
private void LogoutHandle()
{
//当前是否登录
if(PlayerData.Instance.LoginMsgS2C != null)
{
//发送登出消息
MsgHelper.SendLogoutMsg(PlayerData.Instance.LoginMsgS2C.username, PlayerData.Instance.LoginMsgS2C.password);
//还原
PlayerData.Instance.LoginMsgS2C = null;
}
}
创建 PlayerData.cs 记录当前登录账号的信息
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerData
{
private static PlayerData instance = new PlayerData();
public static PlayerData Instance => instance;
public Module.LoginMsgS2C LoginMsgS2C;
}
在MsgHelper.cs中实现登录登出消息发送
public static void SendLoginMsg(string username, string pwd)
{
//实例化对象
Module.LoginMsgC2S msg = new Module.LoginMsgC2S();
msg.username = username;
msg.password = pwd;
//将对象序列化
var str = JsonHelper.ToJson(msg);
Debug.Log(str);
//发送消息
SendToService(1002, str);
}
public static void SendLogoutMsg(string username, string pwd)
{
string tips = "自主下线!!!";
//触发退出的回调
Client.Instance.msgManager.logoutHandle?.Invoke(tips);
//实例化对象
Module.LogoutMsgC2S msg = new Module.LogoutMsgC2S();
msg.username = username;
msg.password = pwd;
//将对象序列化
var str = JsonHelper.ToJson(msg);
Debug.Log(str);
//发送消息
SendToService(1004, str);
}
服务端对登录登出消息的处理
创建json对象
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Service.Modules
{
internal class Module
{
public class RegisterMsgC2S
{
public string username;
public string email;
public string password;
}
public class RegisterMsgS2C
{
public string username;
public string email;
public string password;
public int result;//0:注册成功 1:账号已被注册
}
public class LoginMsgC2S
{
public string username;
public string password;
}
public class LoginMsgS2C
{
public string username;
public string password;
public int result;//0:登录成功 1:登录失败
}
public class ChatMsgC2S
{
public string player;
public string msg;
public int type;
}
public class ChatMsgS2C
{
public string player;
public string msg;
public int type;
}
public class LogoutMsgC2S
{
public string username;
public string password;
}
public class LogoutMsgS2C
{
public int type;//0:自己下线 1:被人挤掉线
}
}
}
实现回调函数
public void LoginHandler(Module.LoginMsgC2S msg)
{
//查找账号
foreach (var info in PlayerData.Instance.players)
{
if (msg.username == info.username)
{
//账号已存在,判断密码是否正确
if (msg.password == info.password)
{
//判断账号是否有账号已登录
foreach (var onlineInfo in ClientManager.Instance.Clients)
{
//当前已有帐号登录,将上一个账号下线,在登录
if (onlineInfo.playerInfo.username == info.username )
{
//将已登录的账号标记为下线状态
onlineInfo.playerInfo.username = "";
onlineInfo.playerInfo.isOnline = false;
//通知已登录的客端下线
MsgHelper.SendLogoutMsg(onlineInfo, 1);
break;
}
}
//标记客户端在线
client.playerInfo.username = msg.username;
client.playerInfo.isOnline = true;
//向客户端发送登录成功
MsgHelper.SendLoginMsg(client, msg, 0);
}
else
{
//密码错误,发送登录失败消息
MsgHelper.SendLoginMsg(client, msg, 1);
}
return;
}
}
//账号不存在,发送登录失败消息
MsgHelper.SendLoginMsg(client, msg, 1);
}
public void LogoutHandler(Module.LogoutMsgC2S msg)
{
//查找已登录的账号
foreach (var onlineInfo in ClientManager.Instance.Clients)
{
if (onlineInfo.playerInfo.username == msg.username)
{
//标记下线
client.playerInfo.username = "";
client.playerInfo.isOnline = false;
//发送自主下线成功
MsgHelper.SendLogoutMsg(client, 0);
return;
}
}
MsgHelper.SendLogoutMsg(client, 0);
}
在MsgHelp.cs中实现处理方法
/// <summary>
/// 处理登录业务
/// </summary>
/// <param name="data"></param>
public static void LoginMsgHandler(byte[] data,Action<Module.LoginMsgC2S> aciton)
{
//数据转化
var str = Encoding.UTF8.GetString(data);
var msg = JsonHelper.ToObject<Module.LoginMsgC2S>(str);
//触发回调
aciton?.Invoke(msg);
}
/// <summary>
/// 处理退出业务
/// </summary>
/// <param name="data"></param>
/// <param name="aciton"></param>
public static void LogoutMsgHandler(byte[] data, Action<Module.LogoutMsgC2S> aciton)
{
//数据转化
var str = Encoding.UTF8.GetString(data);
var msg = JsonHelper.ToObject<Module.LogoutMsgC2S>(str);
//触发回调
aciton?.Invoke(msg);
}
服务端对登录登出结果消息的发送
public static void SendLoginMsg(Client client, Module.LoginMsgC2S msg, int result)
{
//实例化对象
Module.LoginMsgS2C registerObj = new Module.LoginMsgS2C();
registerObj.username = msg.username;
registerObj.password = msg.password;
registerObj.result = result;
//序列化
string json = JsonHelper.ToJson(registerObj);
//发送消息
client.SendToService(1002, json);
}
public static void SendLogoutMsg(Client client,int result)
{
//实例化对象
Module.LogoutMsgS2C msg = new Module.LogoutMsgS2C();
msg.type = result;
//序列化
string json = JsonHelper.ToJson(msg);
//发送消息
client.SendToService(1004, json);
}
最终效果
Unity-网络编程 笔记3 效果视频
当前项目源码
链接:https://pan.baidu.com/s/1wZE4JAeFjWx6thMRx5D4Dg?pwd=e9vs
提取码:e9vs