基于TCP的网络游戏黑白棋系列(三):游戏大厅

上一节我们讲到了客户端发送Login命令后,服务器返回欢迎信息,完成了一个简单的数据传输。这一节我们来完成游戏大厅的基本功能,我们首先思考一下游戏大厅的基本功能:

1 提供可供对弈的游戏桌,游戏大厅可供多桌玩家同时游戏,为了考虑游戏大厅服务器的负载能力,应该设置一个人数的上限和桌数的上限。实际上前面提到的功能抽象出来就是一些数据的状态集合。

2 当玩家登入大厅,应该直观的显示当前大厅的就座情况,方便玩家选择。此处应该考虑大厅的直观显示。

3 当玩家选择某一位置就坐,游戏大厅的相应状态数据应发生更改,任何玩家都能看到大厅的就座情况的变化,方便做出选择。比如a选择坐在第一桌的黑方位置,则b应该看到该位置不可落坐,只能选择其他位置就坐。

尽量从面向对象的角度考虑,我们应当把游戏大厅,游戏桌,玩家看做对象。建议大家使用面向对象的方法去思考,个人感觉服务器客户端通信的网络程序主要涉及通信协议(就是我们前面提到的命令,参数1,参数2等等)的分析,设计不好的话到最后你会发现逻辑复杂到难以控制的程度。

下面我们分别看一下这几个对象(有删减,具体请看源代码)

 

 1  // 游戏大厅
 2  public  FormServer
 3  {
 4       // basilwang 2008-09-06 
 5       // new to this version myGame2
 6       // 游戏桌集合
 7       private  GameTable[] gameTable;
 8       // 玩家集合
 9      List < User >  userList  =   new  List < User > ();
10       // 游戏桌上限
11       private   int  maxTables;
12       // 玩家上限
13       private   int  maxUsers;
14       // 上一节列出的帮助类
15       private  Service service;
16  }
17  // 游戏桌
18  class  GameTable
19  {
20           private   const   int  None  =   - 1 // 无棋子
21           private   const   int  Black  =   0 // 黑白棋子
22           private   const   int  White  =   1 // 白色棋子
23           private   int [,] grid  =   new   int [ 8 8 ];    // 8*8的方格
24           public  Player[] gamePlayer;
25           public  GameTable()
26          {
27              gamePlayer  =   new  Player[ 2 ];
28              gamePlayer[ 0 =   new  Player();
29              gamePlayer[ 1 =   new  Player();
30          }
31          
32   }
33  class  Player
34  {
35           // 是否开始
36       public   bool  started;
37       // 己方棋子个数
38       public   int  grade;
39       // 是否落座
40       public   bool  someone;
41       public  Player()
42      {
43          someone  =   false ;
44          started  =   false ;
45          grade  =   0 ;
46      }
47  }

 

当服务器程序启动的时候,需要初始化游戏大厅的数据;而当客户端登录到游戏大厅后,按照前面列出的逻辑,我们需要把游戏大厅的状态在客户端直观的显示出来。那怎么才能得到游戏大厅的状态数据呢?没错,也是利用的客户端服务器之间的通讯。

当客户端向服务器发送Login命令后,服务器处理完毕后,返回Tables命令返回状态数据

 

 1  private   void  ReceiveData( object  obj)
 2  {
 3       // 省略接受客户端协议代码
 4      
 5       // 拆分接受到的协议      格式:  命令,参数1,参数2 .
 6       string [] splitString  =  receiveString.Split( ' , ' );
 7       string  sendString  =   "" ;
 8       switch  (splitString[ 0 ])
 9      {
10       case   " Login " :
11          user.userName  =   string .Format( " [{0}--{1}] " , splitString[ 1 ], client.Client.RemoteEndPoint);
12           // 向客户端发送协议   
13           // 格式 : Tables,参数1
14           // 参数1为游戏大厅的游戏桌就座情况
15          sendString  =   " Tables, "   +   this .GetOnlineString();        
16          service.SendToOne(user, sendString);        
17           break ;
18       default :
19           break ;
20      }
21   }
22    // 返回如0100010101的字符串  奇数位表示游戏桌黑方的就座情况,偶数位相反,游戏桌按序号排列连接
23    private   string  GetOnlineString()
24  {
25       string  str  =   "" ;
26       for  ( int  i  =   0 ; i  <  gameTable.Length; i ++ )
27      {
28       for  ( int  j  =   0 ; j  <   2 ; j ++ )
29      {
30          str  +=  gameTable[i].gamePlayer[j].someone  ==   true   ?   " 1 "  :  " 0 " ;
31      }
32      }
33       return  str;
34  }

 

客户端接受到Tables命令协议进行分析,直观显示游戏大厅的就座情况,这里为了简单,采用了动态生成若干组checkbox控件添加到Panel的方法,比较简单但能够说明问题。checkbox选中表明已有玩家就座,如果未选中表明可以在此处落座。

这部分代码就不列出来了,可以看一下原程序。

如果玩家选择在某一位置落座,将出发CheckBox的CheckedChanged事件,并向服务器发送SitDown命令

 

 1  void  checkBox_CheckedChanged( object  sender, EventArgs e)
 2  {
 3              CheckBox checkbox  =  (CheckBox)sender;
 4               if  (checkbox.Checked)
 5              {
 6               // 动态生成的CheckBox命名规则为checkXXXXYYYY, 第5-8位为桌号,不足0补齐;第9-12位为黑方或白方,不足0补齐
 7                   int  i  =   int .Parse(checkbox.Name.Substring( 5 4 ));
 8                   int  j  =   int .Parse(checkbox.Name.Substring( 9 4 ));
 9                  side  =  j;
10           // 格式 SitDown,参数1,参数2
11           // 参数1 桌号
12           // 参数2 黑方或白方
13                  service.SendToServer( string .Format( " SitDown,{0},{1} " , i, j));
14              }
15   }

 

服务器分析SitDown命令

 1  private   void  ReceiveData( object  obj)
 2  {
 3           // 省略接受客户端协议代码
 4      
 5           // 拆分接受到的协议      格式:  命令,参数1,参数2 .
 6           string [] splitString  =  receiveString.Split( ' , ' );
 7       string  sendString  =   "" ;
 8       int  tableIndex  =   - 1 ;   // 桌号
 9       int  side  =   - 1 ;         // 座位号
10       int  anotherSide  =   - 1 // 对方座位号
11 
12       switch  (splitString[ 0 ])
13      {
14           case   " Login " :
15           // 省略部分
16           break ;
17           case   " SitDown " :
18          tableIndex  =   int .Parse(splitString[ 1 ]);
19          side  =   int .Parse(splitString[ 2 ]);
20          gameTable[tableIndex].gamePlayer[side].user  =  user;
21          gameTable[tableIndex].gamePlayer[side].someone  =   true ;
22          service.SetListBox( string .Format(
23               " {0}在第{1}桌第{2}座入座 " , user.userName, tableIndex  +   1 , side  +   1 ));
24           // 得到对家座位号
25          anotherSide  =  (side  +   1 %   2 ;
26           // 判断对方是否有人
27           if  (gameTable[tableIndex].gamePlayer[anotherSide].someone)
28          {
29               // 先告诉该用户对家已经入座
30               // 发送格式:SitDown,座位号,用户名
31              sendString  =   string .Format( " SitDown,{0},{1} " , anotherSide,
32              gameTable[tableIndex].gamePlayer[anotherSide].user.userName);
33              service.SendToOne(user, sendString);
34          }
35           // 同时告诉两个用户该用户入座(也可能对方无人)
36           // 发送格式:SitDown,座位号,用户名
37          sendString  =   string .Format( " SitDown,{0},{1} " , side, user.userName);
38          service.SendToBoth(gameTable[tableIndex], sendString);
39           // 重新将游戏室各桌情况发送给所有用户
40          service.SendToAll(userList,  " Tables, "   +   this .GetOnlineString());
41           break ;
42           default :
43           break ;
44      }
45   }
46 

 

到这里,我们把游戏大厅的简单逻辑都处理了,下一节将介绍客户端棋盘的呈现。

源代码下载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值