• 斗地主项目总结


    一、运行流程

      开始界面

      1. 点击开始游戏按钮,执行 PlayPanel 类 startClick 函数,

    1 /// <summary>
    2 /// 开始游戏按钮响应函数
    3 /// </summary>
    4 private void startClick()
    5 {
    6     Dispatch(AreaCode.UI, UIEvent.START_PANEL_ACTIVE, true);      
    7 }

      该函数向 UI 层发送 START_PANEL_ACTIVE 事件,传输消息 true。

      然后是 StartPanel 类 Execute 函数,

     1 public override void Execute(int eventCode, object message)
     2 {
     3     switch (eventCode)
     4     {
     5         case UIEvent.START_PANEL_ACTIVE:
     6             setPanelActive((bool)message);
     7             break;
     8         default:
     9             break;
    10     }
    11 }

      该函数接收消息,调用 setPanelActive 函数显示开始游戏面板。

      点击注册账号按钮流程类似。

      登录界面:

      2. 点击登录按钮,执行 StartPanel 类 loginClick 函数,

     1 /// <summary>
     2 /// 登录按钮的点击事件处理
     3 /// </summary>
     4 private void loginClick()
     5 {
     6     // 若用户名输入为空
     7     if (string.IsNullOrEmpty(inputAccount.text))
     8     {
     9         promptMsg.Change("用户名输入为空", Color.red);
    10         Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
    11         return;
    12     }  
    13     // 若密码输入为空
    14     if (string.IsNullOrEmpty(inputPassword.text))      
    15     {
    16         promptMsg.Change("密码输入为空", Color.red);
    17         Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
    18         return;
    19     }
    20     // 若密码输入不是4到16位
    21     if(inputPassword.text.Length < 4
    22         || inputPassword.text.Length > 16)
    23     {
    24         promptMsg.Change("密码输入不是4到16位", Color.red);
    25         Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
    26         return;
    27     }
    28 
    29     //需要和服务器交互了
    30     AccountDto dto = new AccountDto(inputAccount.text, inputPassword.text);
    31     socketMsg.Change(OpCode.ACCOUNT, AccountCode.LOGIN, dto);
    32     Dispatch(AreaCode.NET, 0, socketMsg);
    33 }
    loginClick

      该函数先验证输入是否符合规定,若不符合,则输出相应消息;若符合,则与服务器交互。

      输出相应消息实现,自定义消息类 PromptMsg,

     1 /// <summary>
     2 /// 提示窗口
     3 /// </summary>
     4 class PromptMsg
     5 {
     6     public string text;
     7     public Color color;
     8 
     9     public PromptMsg()
    10     {
    11 
    12     }
    13 
    14     public PromptMsg(string text, Color color)
    15     {
    16         this.text = text;
    17         this.color = color;
    18     }
    19 
    20     /// <summary>
    21     /// 改变属性,防止多次 new 
    22     /// </summary>
    23     /// <param name="text"></param>
    24     /// <param name="color"></param>
    25     public void Change(string text, Color color)
    26     {
    27         this.text = text;
    28         this.color = color;
    29     }
    30 }
    PromptMsg

       然后向 UI 层发送 PROMPT_MSG 事件,

      然后是 PromptPanel 类 Execute 函数接收消息,

     1 public override void Execute(int eventCode, object message)
     2 {
     3     switch (eventCode)
     4     {
     5         case UIEvent.PROMPT_MSG:                    // 提示信息
     6             PromptMsg msg = message as PromptMsg;
     7             PromptMessage(msg.text, msg.color);
     8             break;
     9         default:
    10             break;
    11     }
    12 }
    Execute

      通过 PromptMessage 函数显示提醒效果,

     1 /// <summary>
     2 /// 提示消息
     3 /// </summary>
     4 /// <param name="text">显示文字</param>
     5 /// <param name="color">显示颜色</param>
     6 private void PromptMessage(string text, Color color)
     7 {
     8     txt.text = text;
     9     txt.color = color;
    10     cg.alpha = 0;
    11     StartCoroutine(PromptAnim());       // 播放动画
    12 }
    PromptMessage

      从上面两个事件流程可得出 UI 事件的一般流程为:

      首先为每个面板创建一个脚本来控制该面板,之后再 Awake 函数里使用 Bind 函数注册事件码,

    1 void Awake()
    2 {
    3     Bind(UIEvent.START_PANEL_ACTIVE);           // 注册事件码
    4 }

       然后添加 Execute 函数来接收外界发送的事件,

    1 public override void Execute(int eventCode, object message)
    2 {
    3     switch (eventCode)
    4     {
    5         default:
    6             break;
    7     }
    8 }

      那么当我们需要实现某一事件的时候,只需要调用 Dispatch 函数来发送想发送的消息即可。

    1 /// <summary>
    2 /// 开始游戏按钮响应函数
    3 /// </summary>
    4 private void startClick()
    5 {
    6     Dispatch(AreaCode.UI, UIEvent.START_PANEL_ACTIVE, true);      
    7 }

       那么,如何与服务器交互呢?

      首先也需要自定义消息类 AccountDto(服务器端生成),

    1 [Serializable]
    2 public class AccountDto
    3 {
    4     public string Account;
    5     public string Password;
    6 
    7     public AccountDto();
    8     public AccountDto(string acc, string pwd);
    9 }

      和实际传输的信息类 SocketMsg,

     1 /// <summary>
     2 /// 网络消息
     3 ///     作用:发送的时候 都要发送这个类
     4 /// </summary>
     5 public class SocketMsg
     6 {
     7     /// <summary>
     8     /// 操作码
     9     /// </summary>
    10     public int OpCode { get; set; }
    11 
    12     /// <summary>
    13     /// 子操作
    14     /// </summary>
    15     public int SubCode { get; set; }
    16 
    17     /// <summary>
    18     /// 参数
    19     /// </summary>
    20     public object Value { get; set; }
    21 
    22     public SocketMsg()
    23     {
    24 
    25     }
    26 
    27     public SocketMsg(int opCode, int subCode, object value)
    28     {
    29         this.OpCode = opCode;
    30         this.SubCode = subCode;
    31         this.Value = value;
    32     }
    33 
    34     public void Change(int opCode, int subCode, object value)
    35     {
    36         this.OpCode = opCode;
    37         this.SubCode = subCode;
    38         this.Value = value;
    39     }
    40 }
    SocketMsg

       接下来是把发送消息这个事件和发送的内容使用 Dispatch 派发出去

       NetManager 类中的 Execute 函数接收事件,并向服务器发送信息,

     1 public override void Execute(int eventCode, object message)
     2 {
     3     switch (eventCode)
     4     {
     5         case 0:             // 发送消息
     6             client.Send(message as SocketMsg);
     7             break;
     8         default:
     9             break;
    10     }
    11 }

      这时候服务器已经收到消息了, 服务器端 NetMsgCenter 类 OnReceive 函数接收到消息,并执行相应的逻辑,

     1 public void OnReceive(ClientPeer client, SocketMsg msg)
     2 {
     3     switch (msg.OpCode)
     4     {
     5         case OpCode.ACCOUNT:
     6             account.OnReceive(client, msg.SubCode, msg.Value);
     7             break;
     8         case OpCode.USER:
     9             user.OnReceive(client, msg.SubCode, msg.Value);
    10             break;
    11         case OpCode.MATCH:
    12             match.OnReceive(client, msg.SubCode, msg.Value);
    13             break;
    14         case OpCode.CHAT:
    15             chat.OnReceive(client, msg.SubCode, msg.Value);
    16             break;
    17         case OpCode.FIGHT:
    18             fight.OnReceive(client, msg.SubCode, msg.Value);
    19             break;
    20         default:
    21             break;
    22     }
    23 }
    OnReceive

      我们发送的消息的 OpCode 为 ACCOUNT,所以会调用 account.OnReceive 函数,

     1 public void OnReceive(ClientPeer client, int subCode, object value)
     2 {
     3     switch (subCode)
     4     {
     5         case AccountCode.REGIST_CREQ:
     6             {
     7                 AccountDto dto = value as AccountDto;
     8                 //Console.WriteLine(dto.Account);
     9                 //Console.WriteLine(dto.Password);
    10                 regist(client, dto.Account, dto.Password);
    11             }
    12             break;
    13         case AccountCode.LOGIN:
    14             {
    15                 AccountDto dto = value as AccountDto;
    16                 //Console.WriteLine(dto.Account);
    17                 //Console.WriteLine(dto.Password);
    18                 login(client, dto.Account, dto.Password);
    19             }
    20             break;
    21         default:
    22             break;
    23     }
    24 }
    OnReceive

       我们发送的消息的 subCode 为 LOGIN,所以会调用 login 函数,

     1 /// <summary>
     2 /// 登录
     3 /// </summary>
     4 /// <param name="client"></param>
     5 /// <param name="account"></param>
     6 /// <param name="password"></param>
     7 private void login(ClientPeer client, string account, string password)
     8 {
     9     SingleExecute.Instance.Execute(() =>                    // 单线程
    10     {
    11         if (!accountCache.IsExist(account))
    12         {
    13             //表示账号不存在
    14             //client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, "账号不存在");
    15             client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, -1);
    16             return;
    17         }
    18 
    19         if (accountCache.IsOnline(account))
    20         {
    21             //表示账号在线
    22             //client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, "账号在线");
    23             client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, -2);
    24             return;
    25         }
    26 
    27         if (!accountCache.IsMatch(account, password))
    28         {
    29             //表示账号密码不匹配
    30             //client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, "账号密码不匹配");
    31             client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, -3);
    32             return;
    33         }
    34 
    35         //登陆成功
    36         accountCache.Online(client, account);
    37         //client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, "登陆成功");
    38         client.Send(OpCode.ACCOUNT, AccountCode.LOGIN, 0);
    39     });
    40 }
    login

      该函数验证账号密码,并向客户端发送相应的消息,

      那么客户端已经收到回复了,客户端 NetManager 类 ProcessSocketMsg 函数会处理该消息,

     1 private void ProcessSocketMsg(SocketMsg msg)
     2 {
     3     switch (msg.OpCode)
     4     {
     5         case OpCode.ACCOUNT :
     6             accountHandler.OnReceive(msg.SubCode, msg.Value);
     7             break;
     8         case OpCode.USER:
     9             userHandler.OnReceive(msg.SubCode, msg.Value);
    10             break;
    11         case OpCode.MATCH:
    12             matchHandler.OnReceive(msg.SubCode, msg.Value);
    13             break;
    14         default:
    15             break;
    16     }
    17 }
    ProcessSocketMsg

       然后根据接收到的消息会调用 AccountHandler 类的 OnReceive 函数,

     1 public override void OnReceive(int subCode, object message)
     2 {
     3     switch (subCode)
     4     {
     5         case AccountCode.LOGIN:                 // 登录
     6             LoginResponce((int)message);
     7             break;
     8         case AccountCode.REGIST_SRES:           // 注册
     9             RegistResponce((int)message);
    10             break;
    11         default:
    12             break;
    13     }
    14 }

      根据 sunCode 会调用 LoginResponce 函数,

     1 // 处理登录信息
     2 private void LoginResponce(int value)
     3 {
     4     switch (value)
     5     {
     6         case 0:
     7             //promptMsg.Change("登录成功", Color.green);
     8             //Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
     9             // 跳到下一个场景
    10             LoadSceneMsg msg = new LoadSceneMsg(1,
    11                 delegate()          // 匿名委托
    12                 {
    13                     // 加载游戏信息
    14                     SocketMsg socketMsg = new SocketMsg(OpCode.USER, UserCode.GET_INFO_CREQ, null);
    15                     Dispatch(AreaCode.NET, 0, socketMsg);
    16                     Debug.Log("场景加载完成!");
    17                 }
    18                 );
    19             Dispatch(AreaCode.SCENE, SceneEvent.LOAD_SCENE, msg);
    20             break;
    21         case -1:
    22             promptMsg.Change("账号不存在", Color.red);
    23             Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
    24             break;
    25         case -2:
    26             promptMsg.Change("账号在线", Color.red);
    27             Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
    28             break;
    29         case -3:
    30             promptMsg.Change("账号密码不匹配", Color.red);
    31             Dispatch(AreaCode.UI, UIEvent.PROMPT_MSG, promptMsg);
    32             break;
    33         default:
    34             break;
    35     }
    LoginResponce

      该函数根据接收到的消息给出相应提示信息。

      这就是一个相对完整的客户端服务器交互。

  • 相关阅读:
    Handler一般处理程序的应用--随机图片生成
    一个内外网部署sharepoint的配置
    不使用SQL Server Management Studio备份数据库的方法
    根据模板生成网页
    一个简单的将Oracle生产库定期备份到备份库的方法
    c#序列化与反序列化
    The Java Reliable Multicast Service:A Reliable Multicast Library
    Video capture using JMF
    转:关于Jxta的Advertisement
    Practical JXTA II
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/unity3d16.html
Copyright © 2020-2023  润新知