34.消息面板的显示
首先的话,我们创建我们的MessagePanel脚本,这里我们提供了创建,显示,隐藏三个方法,并且的话我们这个面板脚本的控制是交给Uimanager进行管理的
publicclassMessagePanel : BasePanel {
private Texttext;
privatefloat showTime = 1f;
publicoverridevoid OnEnter()
{ //这个是用来创建消息面板的
base.OnEnter();
text = this.GetComponent<Text>();
text.enabled = false;
uiMng.InjectMsg(this);
}
publicvoid ShowMessage(string data)
{
text.text = data;
//将alpha值重新设置为1
text.enabled = true;
text.color = Color.white;
//一秒种后隐藏这个方法
Invoke("HideMessage", showTime);
}
publicvoid HideMessage()
{
//这个是用来修改text的Alpha值使得它的显示为隐藏
text.CrossFadeAlpha(0, 1, false);
}
}
因为所有的Ui面板都是用UiManager进行管理的,因此我们提供在父类提供一个方法来获取到Uimanager
public UIManager UIManager
{
//提供一个set方法可以进行赋值
set { uiMng= value; }
}
然后在这个实例化面板的方法里,当我们获得到对应的面板的时候,就会对它进行赋值,让UiManager进行管理
privateBasePanel GetPanel(UIPanelType panelType)
{
if(panelDict == null)
{
panelDict = new Dictionary<UIPanelType,BasePanel>();
}
//BasePanel panel;
//panelDict.TryGetValue(panelType, outpanel);//TODO
BasePanel panel = panelDict.TryGet(panelType);
if (panel== null)
{
//如果找不到,那么就找这个面板的prefab的路径,然后去根据prefab去实例化面板
//stringpath;
//panelPathDict.TryGetValue(panelType,out path);
string path = panelPathDict.TryGet(panelType);
GameObject instPanel =GameObject.Instantiate(Resources.Load(path)) as GameObject;
instPanel.transform.SetParent(CanvasTransform,false);
//实例化对应面板后我们要给这个面板提供UiManager这个值
instPanel.GetComponent<BasePanel>().UIManager = this;
panelDict.Add(panelType,instPanel.GetComponent<BasePanel>());
return instPanel.GetComponent<BasePanel>();
}
然后我们在UIManager里提供两个方法,来引用和操控我们的MessagePanel
publicvoid ShowMessage(string msg)
{
if(messagePanel == null)
{
Debug.Log("无法显示该面板");
return;
}
messagePanel.ShowMessage(msg);
}
privatevoid HideMessage()
{
messagePanel.HideMessage();
}
publicvoidInjectMsg(MessagePanel messagePanel)
{
//当面板被创建的时候,注入这个Panel
messagePanel = this.messagePanel;
}
如果其他的模块也想要用这个提示错误信息的话,我们只要在GameFacade里提供这样一个接口方法来调用Uimanager里的ShowMessage即可
publicvoid ShowMessage(string msg)
{
uIManager.ShowMessage(msg);
}
35.这里我们来开发我们的UI界面
这里实现的是点击登录弹出登录框,这个的话,首先,我们用UIManager来创建出我们的消息面板和登录面板
publicoverridevoid OnInit()
{
base.OnInit();
PushPanel(UIPanelType.Start);
PushPanel(UIPanelType.Message);
}
然后的话,我们修改我们的StartPanel,给登录注册上点击创建登录页面的按钮
publicclassStartPanel : BasePanel {
private ButtonloginButton;
privateAnimator btnAnimator;
publicoverridevoid OnEnter()
{
base.OnEnter();
gameObject.SetActive(true);
loginButton = transform.Find("LoginButton").GetComponent<Button>();
btnAnimator = transform.Find("LoginButton").GetComponent<Animator>();
loginButton.onClick.AddListener(OnClick);
}
publicvoid OnClick()
{
uiMng.PushPanel(UIPanelType.Login);
}
然后给我们的登录页面添加一个关闭功能即可,这里我们使用DoTween控制页面的切换
publicclassLoginPanel : BasePanel {
private ButtoncloseButton;
// Use this for initialization
publicoverridevoid OnEnter()
{
base.OnEnter();
gameObject.SetActive(true);
transform.DOScale(1, 0.4f);
transform.DOLocalMove( new Vector3(35,0,0), 0.4f);
closeButton = transform.Find("Exit").GetComponent<Button>();
closeButton.onClick.AddListener(OnCloseClick);
}
public void OnCloseClick()
{
uiMng.PopPanel();
transform.DOScale(0, 0.4f);
//transform.DOLocalMove(new Vector3(1000,0, 0), 0.4f).OnComplete(()=>uiMng.PopPanel());
}
publicoverridevoid OnExit()
{
base.OnExit();
gameObject.SetActive(false);
}
}
36.创建两个数据表用来管理我们的信息
一个用户表,包含id,用户名,密码
一个战机表,包含id,用户id,总局数,胜利局数
这里我们创建这样两个数据表,战绩表的用户id,作为用户表id的外键相关联
37.登录面板检测你是否输入了用户名或者密码
首先,我们获得一下两个输出域
userIf = transform.Find("userName/InputField").GetComponent<InputField>();
passwordIf = transform.Find("password/InputField").GetComponent<InputField>();
然后我们注册一下登录按钮
loginButton = transform.Find("LoginButton").GetComponent<Button>();
loginButton.onClick.AddListener(OnLoginClick);
根据输出域判断消息并且决定消息面板显示什么信息
publicvoid OnLoginClick()
{
string msg = "";
if (string.IsNullOrEmpty(userIf.text))
{
msg += "用户名为空";
}
if (string.IsNullOrEmpty(passwordIf.text))
{
msg += "密码为空";
}
if (msg !=null)
{
uiMng.ShowMessage(msg);
return;
}
Debug.Log(msg + "登录按钮被点击了");
}
1. 修改让requestCode指定对应的ActionCode
这里我们要知道,我们是通过RequestCode来找到对应的Controller,通过ActionCode区别Request
1. 首先的话,我们修改BaseRequest,子类继承的时候都要修改他们的值
publicclassBaseRequest : MonoBehaviour {
protectedRequestCode requestCode = RequestCode.None;
protected ActionCodeactionCode = ActionCode.None;
2. 修改RequestManager,我们是通过RequestCode获得对应的ActionCode
publicclassBaseRequest : MonoBehaviour {
protected RequestCoderequestCode = RequestCode.None;
protectedActionCode actionCode = ActionCode.None;
3. 修改GameFacade中对应的获得Request的方法
publicvoid AddRequest(ActionCode actionCode,BaseRequestbaseRequest)
{
requestManager.AddRequest(actionCode,baseRequest);
}
publicvoid RemoveRequest(ActionCode actionCode)
{
requestManager.RemoveRequest(actionCode);
}
publicvoid HandleResponse(ActionCode actionCode, string data)
{
requestManager.HandleResponse(actionCode, data);
}
4. 修改服务器端的各种RequestCode,这里的话只要根据报错改就可以了,还是很简单的,目的就是每个RequestCode用ActionCode区分
2. 客户端向服务器端发起登录请求
首先,我们要给RequestCode和ActionCode提供几个code
publicenumRequestCode
{
None,
User
}
publicenumActionCode
{
None,
Login,
Regist
}
然后我们重新生成一下,把dll放到plugins下,这个一般是提前设计好,因为是案例,所以会将框架修改一下
这里的话我们做的是客户端发送登录请求,于是我们创建一个LoginRequest
void Start()
{
//指定好LoginRequest中的requestCode和actionCode
requestCode = RequestCode.User;
actionCode = ActionCode.Login;
}
publicvoid SendRequest(string username,string password)
{
string data =username + "," +password;
base.SendRequest(data);
}
指定好它对应的requestCode和ActionCode,然后调用ClientManager里的SendMessage方法,这个方法的调用我们通过GameFacade作为中介,而GameFacade的持有,我们放在父类BaseRequest,这里还要修改一下GameFacade,使它持有一下ClientManager里的SendMessage,这里代码就不贴了,和之前的一样
protectedGameFacade gameFacade;
publicvirtualvoid Awake()
{
GameFacade._instance.AddRequest(actionCode, this);
gameFacade = GameFacade._instance;
}
3. 添加用户的Dao层和Model层来进行校验
在Model层里我们给它提供用户属性
namespace游戏服务器.Model
{
classUser
{
//这里我们设置它的几个属性
public User(int id,string username,string password)
{
this.id = id;
this.username =username;
this.password =password;
}
publicint id { get; set; }
publicstring username { get; set; }
publicstring password { get; set; }
}
}
在Dao层的话,我们提供它的解析方法
using System;
usingSystem.Collections.Generic;
using System.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingMySql.Data.MySqlClient;
using游戏服务器.Model;
namespace游戏服务器.Dao
{
classUserDao
{
//提供校验方法,一个model对应一个Dao
public UserVerifyUser(MySqlConnection conn,string username,string password)
{
MySqlCommand cmd = new MySqlCommand("select * from user where username=@username andpassword=@password", conn);
//插值作为连接查询
MySqlDataReader mySqlDataReader = null;
try
{
mySqlDataReader =cmd.ExecuteReader();
cmd.Parameters.AddWithValue("username",username);
cmd.Parameters.AddWithValue("password",password);
if (mySqlDataReader.Read())
{
int id = mySqlDataReader.GetInt32("id");
User user = new User(id, username,password);
return user;
}
else
{
returnnull;
}
}
catch(Exception e)
{
Console.WriteLine("读取用户信息出现异常" + e);
}
finally
{
mySqlDataReader.Close();
}
returnnull;
}
}
创建后我们在Controller层进行控制Dao层方法的调用即可
4. 让服务器端对我们的客户端登录请求做出响应
首先我们在Common类里提供一个枚举类型的方法判断是否正确返回信息
publicenumReturnCode
{
Success,
Fail
}
然后我们回到我们的UserController里判断我们是否登录成功
首先我们要用spilt方法分割用户名和密码,再用上一节写的方法判断是不是正确的用户名和密码,再返回对应的判断即可,这里要获取conn,要给Client提供一个构造方法获取,这里的话就不写了
publicstring Login(string data,Clientclient,Sever server)
{
string[] str = data.Split(',');
User user =userDao.VerifyUser(client.MysqlConn, str[0], str[1]);
if (user == null)
{
return ((int)(ReturnCode.Fail)).ToString();
}
else
{
return ((int)(ReturnCode.Success)).ToString();
}
}
5. 客户端响应服务器做出的回应
这里我们回到unity客户端,这里的话,服务器发送了信息,需要客户端做出响应,我们在LoginRequest对它做出响应,将服务器返回的ReturnCode进行转型,然后调用LoginPanel对UI进行反应
publicoverridevoid OnResponse(string data)
{
ReturnCode returnCode = (ReturnCode)(int.Parse(data));
loginPanel.OnResponse(returnCode);
}
这里的OnResponse,会对你的returnCode进行反应,当然前提是连接了数据库
publicvoidOnResponse(ReturnCode returnCode )
{
if(returnCode == ReturnCode.Success)
{
//判断登录成功,进入房间列表
}
else
{
uiMng.ShowMessage("登录失败,用户名或者密码不正确");
}
}
6. 测试登录效果
在测试登录效果的时候,不得不说,我碰到了很多的障碍,这也是之前没有debug的原因,这里讲述一下
1. 在loginRequest中调用MessagePanel下的ShowMessage时,因为是异步调用,所以无法修改,解决办法嘛,就是调用Unity自带的Update方法进行传值,
publicvoid Update()
{
//因为这个BasePanel是继承自MonBehaviour,所以我们能调用Update方法
if(message != null)
{
ShowMessage(message);
message = null;
}
}
publicvoid ShowMessage(string data)
{
//将alpha值重新设置为1
text.enabled = true;
text.text = data;
text.CrossFadeAlpha(1, 0.2f, false);
//一秒种后隐藏这个方法
Invoke("HideMessage", showTime);
}
publicvoid ShowMessageSync(string msg)
{
//异步调用显示信息的方法,因为想要修改unity组件是不能直接修改
message = msg;
1. }
2. 这个是之前的代码问题,我在client里面回调信息时候,写错了clientSocket的传值方式
我把clientSocket=this.clientSocket写成了this.clientSocket=clientSocket,不得不说,这一块造成了很大的困扰,因为Bug很隐晦,看了很久,所幸最后还是找出来了,这里提示了我修改的重要性,当然也因此重温了一遍服务器和客户端的信息派发机制
3. 接下来就很简单了,我们手动给数据库添加一条用户名密码做校验就行,当然记得select数据的时候要先注入值再查询,之前这一块没有做出来,导致Bug,这里也标记一下
4. 那么到这里,我们的登录功能也就算完成了
7. 注册页面的一些Ui调整
这里的话比较简单,就是一个弹出页面的操作,我就贴一下代码了
publicclassRegistPanel : BasePanel {
private ButtoncloseButton;
publicoverridevoid OnEnter()
{
base.OnEnter();
this.gameObject.SetActive(true);
transform.DOScale(1, 0.4f);
closeButton = transform.Find("Exit").GetComponent<Button>();
closeButton.onClick.AddListener(OnCloseButtonClick);
}
publicvoidOnCloseButtonClick()
{
transform.DOScale(0, 0.4f);
uiMng.PopPanel();
}
publicoverridevoid OnExit()
{
base.OnExit();
this.gameObject.SetActive(false);
}
}
8. 发送信息到服务器端
这里的话我们创建一个RegisterRequest来处理注册的请求
也是持有我们的注册页面,然后发送请求,根据ReturnCode判断是否正确
publicclassRegisterRequest : BaseRequest {
privateRegistPanel registPanel;
publicoverridevoid Awake()
{
//指定好LoginRequest中的requestCode和actionCode
requestCode = RequestCode.User;
actionCode = ActionCode.Regist;
registPanel = GetComponent<RegistPanel>();
base.Awake();
}
publicvoid SendRequest(string username, string password)
{
string data =username + "," +password;
base.SendRequest(data);
}
publicoverridevoid OnResponse(string data)
{
ReturnCode returnCode = (ReturnCode)(int.Parse(data));
}
然后我们修改一下我们的RegisterPanel做注册校验和发送数据
publicvoid Start()
{
userInfo = transform.Find("userName/InputField/Text").GetComponent<Text>();
passwordInfo = transform.Find("password/InputField/Text").GetComponent<Text>();
rePasswordInfo = transform.Find("RePassword/InputField/Text").GetComponent<Text>();
registerRequest = this.GetComponent<RegisterRequest>();
}
publicoverridevoid OnEnter()
{
base.OnEnter();
this.gameObject.SetActive(true);
transform.DOScale(1, 0.4f);
closeButton = transform.Find("Exit").GetComponent<Button>();
closeButton.onClick.AddListener(OnCloseButtonClick);
registerButton = transform.Find("RegeistButton").GetComponent<Button>();
registerButton.onClick.AddListener(OnRegisterClick);
}
publicvoidOnCloseButtonClick()
{
transform.DOScale(0, 0.4f);
uiMng.PopPanel();
}
publicvoid OnRegisterClick()
{
string msg = "";
if (string.IsNullOrEmpty(userInfo.text)){
msg += "用户名不能为空";
}
if (string.IsNullOrEmpty(passwordInfo.text))
{
msg += "/n密码不能为空";
}
if(passwordInfo.text != rePasswordInfo.text)
{
msg += "密码和重复密码不一致";
}
if (msg !=null)
{
uiMng.ShowMessage(msg);
}
//进行注册请求发送信息到服务器端
registerRequest.SendRequest(userInfo.text, passwordInfo.text);
}
publicoverridevoid OnExit()
{
base.OnExit();
this.gameObject.SetActive(false);
}
}
9. 使服务器对于客户端的注册请求做响应
这里的话,当我们想要对客户端的注册做出响应,这里牵扯到的Controller和Dao就是UserController和UserDao了,一个负责调用Dao里的方法进行检验和注册,一个来书写注册方法</