C#斗地主网络版源码:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/06/1497673.html
本文是对C#网络版斗地主的总结。
系列文章:
网络部分实现:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/07/1497968.html
地主权限的传递:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/07/1498097.html
出牌权限的传递:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/08/1498369.html
首先服务器使用一个随机数来随即选出默认地主。然后发送信息给选出来的玩家。玩家接收到信息后显示两个按钮“叫地主”,“不叫”。如果选择不叫,则把可以叫地主的权限发送给另外一个玩家,如果另外两个玩家都不要的话,就执行Restart()方法重新发牌。
叫地主权限的传递顺序如下图所示:
具体实现方法:
服务器得到一个1-3的随机数,1代表服务器是默认地主(默认地主就是随机选择的第一个有权限叫地主的玩家),2代表client1是默认地主,3代表client2是默认地主。只有服务器端能够选择地主,所以该方法在server类中
public void SendOrder(int Num)
{
switch (Num)
{
case 1:
DConsole.player1.areYouLandLord = true; //把叫地主权限给自己
break;
case 2:
this.SendDataForClient(“AreYouLandLord“, 1); //传递叫地主权限给client1
break;
case 3:
this.SendDataForClient(“AreYouLandLord“, 2); //传递叫地主权限给client2
break;
}
}
客户端的循环接收数据程序会分析服务端发送过来的数据,在client类:
(代码比较长,所以只贴出和地主权限传递有关的一部分)
public void AcceptServerData()
{
NetworkStream Ns = client.GetStream();
string str = “”;
while (true)
{
byte[] bytes = new byte[108];
Ns.Read(bytes, 0, 108);
str = Encoding.Default.GetString(bytes);
(省略一部分)
if (str.StartsWith(“AreYouLandLord“)) //如果服务器向客户端发送该消息,则客户端获取叫地主权限
{
DConsole.player1.areYouLandLord = true; //timer控件检测到该属性值为true时显示出叫地主和不叫按钮
continue;
}
if (str.StartsWith(“LandLordPokers“)) //获取服务器发送给客户端的地主的3张牌,收到这三张牌后地主权限的传递就结束了
{
PokerGroup pokers = new PokerGroup();
str = str.Replace(“LandLordPokers“, “”);
byte[] bytePg = Encoding.Default.GetBytes(str);
pokers.GetPokerGroup(bytePg);
DConsole.LandLordPokers = pokers;//把接收到的地主牌保存起来
DConsole.player1.SelectLandLordEnd();//该方法在窗口中央显示出地主牌,然后判断自己是不是地主,如果是地主就将地主牌添加到自己的牌组.该方法的具体代码请看下文
continue;
}
if (str.StartsWith(“ClientIsLandLord“)) //另外一个客户端是地主
{
DConsole.lblClient2Name.Text += “(地主)“;
DConsole.lblClient2Name.ForeColor = System.Drawing.Color.Red;
DConsole.PaintClient(20);
continue;
}
if (str.StartsWith(“ServerIsLandLord“)) //服务器是地主
{
DConsole.lblClient1Name.Text += “(地主)“;
DConsole.lblClient1Name.ForeColor = System.Drawing.Color.Red;
DConsole.PaintServer(20);
continue;
}
(后面省略)
}
}
player1.areYouLandLord为true后,timer控件会检测到,然后把叫地主和不叫按钮显示出来。
叫地主按钮的click事件:
this.player1.isLandLord = true; //本地玩家为地主
this.player1.haveOrder = true; //获得出牌权限,下篇文章讲到出牌权限的传递
this.player1.isBiggest = true; //出的牌是否为最大的,主要用于当你出的牌其他两家都不要时,你自己不能不要,只能出牌,下篇文章会讲到的
this.player1.areYouLandLord = false;//设置该值为false
this.btnNeedLandLord.Visible = false;
this.btnNotLandLord.Visible = false; //隐藏叫地主和不叫按钮
if (this.server != null) //当玩家为服务器时
{
this.player1.SelectLandLordEnd();//该方法在窗口中央显示出地主牌,然后判断自己是不是地主,如果是地主就将地主牌添加到自己的牌组.该方法的具体代码请看下文
this.server.SendDataForClient(“LandLordPokers“, DConsole.LandLordPokers, 1); //把地主的三张牌发送给client1,因为不管谁是地主,客户端都需要获得地主的牌并且显示出来
Thread.Sleep(100);
this.server.SendDataForClient(“LandLordPokers“, DConsole.LandLordPokers, 2);//同上,把数据发送个client2
Thread.Sleep(100);
this.server.SendDataForClient(“ServerIsLandLord“, 1);//通知client1,服务器是地主
Thread.Sleep(100);
this.server.SendDataForClient(“ServerIsLandLord“, 2);//通知client2,服务器是地主
Thread.Sleep(100);
}
if (this.client != null) //当玩家为客户端时
{
this.client.SendDataForServer(“IamLandLord“); //发送信息给服务器,服务器可以识别是哪个客户端叫了地主,服务器如何处理请看下文的server类代码
Thread.Sleep(300);
}
当玩家单击“不叫”按钮时。如果玩家是服务器,如第一张图所示,程序会向他的下家发送选择地主的权限,当LandLordNum为3时,服务器就是最后一个玩家,如果他也不叫地主的话,就只能重新发牌了。
如果玩家是客户端的话,直接向server端发送“AreYouLandLord”来表明自己不要地主。
Server端会判断是client1还是client2发送的消息,然后做出不同的响应
下面是“不叫“按钮的click事件处理程序
在Player类中,player1.SelectLandLordEnd的具体代码如下:
public void SelectLandLordEnd()
{
DConsole.PaintLandLord(true); //传递true给该方法,在窗口中央显示地主三张牌的具体点数
if (this.isLandLord) //如果自己是地主的话
{
foreach (Poker poker in DConsole.LandLordPokers) //把这三张牌添加到自己的牌组中
{
this.pokers.Add(poker);
}
this.sort(); //重新排序
this.Paint(); //重新显示自己的牌
}
}
地主的权限传递就这么多了,可能写的比较乱,但是并不复杂,相信大家仔细多看几遍应该能够明白的.。如果那里有错误的话欢迎在下面留言栏反馈。谢谢!
下面是server类里面的监听客户端消息的程序:
(由于篇幅所限,这里只贴出与地主权限传递有关的代码)
public void AccpetClient1Data() //监听客户端1的消息
{
NetworkStream Ns1 = client1.GetStream();
string str1 = “”;
while (true)
{
PokerGroup pg = new PokerGroup();
byte[] bytes1 = new byte[108];
Ns1.Read(bytes1, 0, 108);
str1 = Encoding.Default.GetString(bytes1);
(省略部分)
if (str1.StartsWith(“AreYouLandLord“))
{
if (DConsole.LandLordNum == 1) //如果默认地主为服务器,那么根据文章开头的权限传递顺序图,server-client2-client1,client1为最后一个玩家,所以需要和牌重新来过
{
DConsole.Restart();
continue;
}
DConsole.player1.areYouLandLord = true; //当默认地主不是服务器时,设置服务器的叫地主权限为true,当timer控件读取到该值时,服务器的叫地主和不叫按钮马上就会显示出来.
continue;
}
if (str1.StartsWith(“IamLandLord“)) //客户端1为地主
{
DConsole.lblClient1Name.Text += “(地主)“;
DConsole.lblClient1Name.ForeColor = System.Drawing.Color.Red;
SendDataForClient(“ClientIsLandLord“, 2); //通知客户端2,客户端1为地主
Thread.Sleep(sleep);
DConsole.PaintClient(20, 1);
SendDataForClient(“LandLordPokers“, DConsole.LandLordPokers, 1); //地主已选出,把牌发送给所有玩家
Thread.Sleep(sleep);
SendDataForClient(“LandLordPokers“, DConsole.LandLordPokers, 2);//地主已选出,把牌发送给所有玩家
DConsole.player1.SelectLandLordEnd(); //该方法的具体代码请看下文
continue;
}
}
}
/// <summary>
/// 循环接收客户端2的请求数据
/// </summary>
public void AccpetClient2Data()
{
NetworkStream Ns2 = client2.GetStream();
string str1 = “”;
while (true)
{
PokerGroup pg = new PokerGroup();
byte[] bytes2 = new byte[108];
Ns2.Read(bytes2, 0, 108);
str1 = Encoding.Default.GetString(bytes2);
(省略部分)
if (str1.StartsWith(“AreYouLandLord“)) //客户端2不要地主
{
if (DConsole.LandLordNum == 2) //如果默认地主为客户端1,那么根据文章开头的权限传递顺序图,client1-server-client2,client2为最后一个玩家,所以需要和牌重新来过
{
DConsole.Restart();
continue;
}
SendDataForClient(“AreYouLandLord“, 1); //如果默认地主不是客户端1的话,按照顺序把叫地主权限传递给client1,client1的处理程序上文已经列出
continue;
}
if (str1.StartsWith(“IamLandLord“) ) //客户端2为地主
{
DConsole.lblClient2Name.Text += “(地主)“;
DConsole.lblClient2Name.ForeColor = System.Drawing.Color.Red;
SendDataForClient(“LandLordPokers“, DConsole.LandLordPokers, 1);
SendDataForClient(“LandLordPokers“, DConsole.LandLordPokers, 2);
SendDataForClient(“ClientIsLandLord“, 1);
DConsole.PaintClient(20, 2);
DConsole.player1.SelectLandLordEnd();
continue;
}
}
}
private void btnNotLandLord_Click(object sender, EventArgs e)
{
this.player1.areYouLandLord = false;
this.player1.isLandLord = false;
this.btnNeedLandLord.Visible = false;
this.btnNotLandLord.Visible = false;
if (this.server != null) //玩家是服务端
{
if (DConsole.LandLordNum == 3) 如果client2是默认地主,根据权限传递顺序client2–client1–server,server为最后玩家,如果server不叫地主,只能和牌重来
{
DConsole.Restart();
return;
}
this.server.SendDataForClient(“AreYouLandLord“, 2); //如果client2不是默认地主,就把权限传递给client2
}
if (this.client != null) //如果玩家是客户端
{
this.client.SendDataForServer(“AreYouLandLord“);//告诉服务器自己不叫
}
}