源码在上一篇文章: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
出牌顺序如上图所示。
出牌权限可以用一个bool值表示
在Player类中,有一个属性:haveOrder表示玩家是否有权限出牌。
还需要考虑到一点,当一个玩家出牌后,其他玩家都要不起(pass),该玩家不能自己“要不起”自己,所以还需要一个bool类型的属性“IsBiggest”。
该属性表示自己出的牌最大。怎样保证该值的有效性呢?换句话说,最大的只能有一个。所以,每当自己出牌的时候,只要自己的牌比别人的牌大,就把该值设置为true。当该值为true时,向其他玩家发送信息表明自己的牌比你们的大,其他玩家收到信息后,把自己的IsBiggest属性设置为false;如此一来,就实现了出牌权限的正确传递。
具体实现方法如下:
本文需要Player类中的一些代码:
public bool haveOrder
{
get
{
return _haveOrder;
}
set
{
_haveOrder = value;
}
}
private bool _isBiggest;
public bool isBiggest //
{
get
{
return _isBiggest;
}
set
{
if (value)//给IsBiggest赋值true时
{
if (DConsole.client != null) //当玩家为客户端时
{
DConsole.client.SendDataForServer("IamIsBiggest");//服务器这边是怎么处理的呢?请看下文.
_isBiggest = value;
}
if (DConsole.server != null)//如果玩家为服务器
{
DConsole.server.SendDataForClient("NoBiggest", 1);
DConsole.server.SendDataForClient("NoBiggest", 2);//告诉客户端,你不是Biggest,客户端如何处理?请看下文
_isBiggest = value;
}
}
else
{
_isBiggest = value;
}
}
}
public bool lead()//出牌方法
{
DConsole.leadPokers = leadPokers;
this.leadPokers.Clear();
foreach (int selectPoker in this.selectPokers) //迭代循环把已选中的牌添加到leadPokers
{
this.leadPokers.Add(this.pokers[selectPoker]);
}//以上代码是将选中的牌构造成一个PokerGroup对象
if (DConsole.IsRules(this.leadPokers))//验证选中的牌是否符合游戏规则,关于规则在以后的文章中详细讲解
{
if (DConsole.player1.isBiggest || DConsole.leadPokers > DConsole.leadedPokerGroups[DConsole.leadedPokerGroups.Count-1]) //玩家能出牌的两种情况是1、自己上轮出的牌是最大的,别人都要不起。2、自己本轮出的牌比别人的大。
{
if (DConsole.leadPokers.type == PokerGroupType.炸弹)//当牌组的类型为炸弹时,翻倍
{
DConsole.multiple *= 2;
}
if (DConsole.leadPokers.type == PokerGroupType.双王) //当牌组的类型为双王时,翻三倍
{
DConsole.multiple *= 3;
}
DConsole.player1.isBiggest = true;//只要自己的牌出出去了,就假设自己是最大的,一旦自己的牌被别人管上,就会被设置为false,具体请看下文
this.BakPoker(); //备份现有pokers,下次出牌时需要用到
foreach (int selectPoker in this.selectPokers) //在pokers里移除已经出过的牌
{
this.pokers.Remove(this.bakPokers[selectPoker]);
}
this.selectPokers.Clear(); //清空已选牌
return true;
}
else
{
this.leadPokers.Clear();
return false; //牌组比别人小就返回false
}
}
else
{
this.leadPokers.Clear();
return false; //不符合规则就返回false
}
}
haveOrder(出牌权限)传递的具体实现:
在服务器选择地主时,把出牌权限一并传给地主,所以出牌是由地主开始的。这里我先假设地主为服务器。
服务器在叫地主后,出了本局第一组牌,下面看一下出牌按钮的处理程序:
{
if (player1.lead())//尝试出牌,该方法的代码见上文,如果出牌成功,执行以下代码
{
this.btnLead.Visible = false;
this.btnPass.Visible = false;//隐藏出牌和不要按钮
if (this.server != null) //当玩家为服务器时
{
server.SendDataForClient("SPokerCount" + Convert.ToString(this.player1.pokers.Count), 1); //发送自己牌的剩余张数给client1
Thread.Sleep(100);//延迟100毫秒
server.SendDataForClient("SPokerCount" + Convert.ToString(this.player1.pokers.Count), 2);发送自己牌的剩余张数给client2
Thread.Sleep(100);
server.SendDataForClient("server", DConsole.leadPokers, 1);//发送自己出的牌组给client1
Thread.Sleep(100);
server.SendDataForClient("server", DConsole.leadPokers, 2);//发送自己出的牌组给client2
Thread.Sleep(100);
if (this.player1.pokers.Count == 0 && DConsole.IsStart) //当server端牌的张数为0并且游戏已经开始时
{
DConsole.Winer = 1; //胜利者为1,即server,这里是计分系统,很简单,不赘述
DConsole.Restart();//重新开始游戏
}
else
{
server.SendDataForClient("Order", 2); //这里就是传递权限的关键代码,当server端出牌并且牌没有出完时,传递出牌权限给server端的下家,根据权限传递顺序,server-client2-clinet1,所以这里把出牌权限传递给client2
}
DConsole.player1.haveOrder = false; //自己的出牌权限已经消失
}
if (this.client != null) //当玩家为客户端时
{
client.SendDataForServer("PokerCount" + Convert.ToString(this.player1.pokers.Count)); //发送客户端牌的剩余张数给服务器,服务器会处理并转发给另一个客户端
Thread.Sleep(500);
client.SendDataForServer("client", DConsole.leadPokers);//发送客户端出牌牌组给服务器,服务接收到该消息后,就知道客户端1或者客户端2已出牌,如果该消息是客户端1发出的,根据权限传递顺序client2-clinet1-server,服务器会获得出牌权限,如果该消息是客户端2发出的,服务器会发送消息给客户端1使客户端1拥有出牌权限
Thread.Sleep(100);
this.player1.haveOrder = false; //自己的出牌权限消失
}
player1.g.Clear(this.BackColor);
player1.Paint();
DConsole.PaintPlayer1LeadPoker();
}
else
{
DConsole.Write("[系统消息]:您出的牌不符合规则!");
}
}
来看看server类中有关出牌权限传递的相关处理程序:
/// 循环接收客户端1的请求数据
/// </summary>
public void AccpetClient1Data()
{
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);
//(省略N行)
if (str1.StartsWith("client")) //收到客户端1的client消息,该消息表示客户端1出的牌
{
SendDataForClient(str1, 2);
Thread.Sleep(sleep);
str1 = str1.Replace("client", "");
pg.GetPokerGroup(Encoding.Default.GetBytes(str1));
DConsole.leadedPokerGroups.Add(pg); //这里在add之前会对该牌组进行验证和排序
DConsole.PaintPlayer2LeadPoker(pg);
DConsole.WriteLeadedPokers();
if (!DConsole.IsRestart)
{
DConsole.player1.haveOrder = true; //client1出牌后归server出牌,前提是没有Restart,Restart后出牌权限消失,根据权限传递顺序client2-clinet1-server,这里接收到的是client1的出牌,说明轮到server出牌了.
}
else
{
DConsole.IsRestart = false;//当检测到已经Restart时,复位Restart使它还原为false
}
continue;
}
//Client放弃出牌,权限交给服务器
if (str1.StartsWith("Pass"))
{
DConsole.gPlayer2LeadPoker.Clear(DConsole.backColor);
DConsole.gPlayer2LeadPoker.DrawString("不要", new System.Drawing.Font("宋体", 20), System.Drawing.Brushes.Red,5,5);
DConsole.player1.haveOrder = true;
SendDataForClient("ClientPass", 2); //告诉客户端2,客户端1pass了
continue;
}
if (str1.StartsWith("IamIsBiggest"))//客户端1说他的牌是最大的,所以要把自己的IsBiggest设置为false,因为最大的牌只能有一个
{
DConsole.player1.isBiggest = false;
this.SendDataForClient("NoBiggest", 2); //同时要转发给client2,让client2把自己的IsBiggest属性设置为false
continue;
}
//(省略N行)
}
}
/// <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);
(省略N行)
if (str1.StartsWith("client"))//收到客户端2的client消息,该消息表示客户端2出的牌
{
SendDataForClient(str1, 1);
Thread.Sleep(sleep);
str1 = str1.Replace("client"
全部评论
-
10-27 六六分期app的软件客服如何联系?(六六分期
-
11-06 亲亲特价:怎么删除回收站图标
-
11-06 济南大学虚拟社区:鲁大师节能降温的具体办
-
11-06 xlueops.exe:无线网络安装向导
-
11-06 女斗合众国:win7系统cf与主机连接不稳定怎
-
11-06 ipz-185:win7系统vcf文件怎么打开
-
11-06 傻哥蹦迪:win10系统s4怎么打开usb调试
-
11-06 八神浩树gtaste:回收站清空了怎么恢复
-
11-06 校园至尊魔王小说:win7系统浏览网页时字体
-
11-06 女斗合众国:win10系统访问共享文件夹提示请
-
11-06 雨酷仙境:设置win7系统转移临时文件夹腾出
-
11-06 阿穆纳伊之杖:win7系统开始菜单在右边还原
-
11-06 甘尔葛分析师:计谋网站seo关键词暴涨有什
-
11-06 蔡贵霖: 计谋网站seo关键词暴涨有什么秘密
-
11-06 博益网首页:ao3网页版进入不了解决方法
-
11-06 漏斗子专栏: 网站数据分析小白易懂精华篇
-
11-06 颾狐蝶蜋:系统资源不足无法完成请求的服务
-
11-06 国光中学校歌:提交网站到alexa查询详细步骤
-
11-06 西安有情天:静态网页和动态网页的区别
-
11-06 红木雅尚斋:外部链接构造对网站的好处
-
11-06 前官礼遇:防止域名劫持–增强域安全性的10
-
11-06 密传二转答案: 中文分词算法有哪些
-
11-06 金泉家园邮编:百度快照劫持的表现及应对方
-
2022-11-06
剪的笔顺,诠释剪的笔画,认识剪的部首
-
六六分期app的软件客服如何联系?(六六分期
2023-10-27
-
florent37/ViewAnimator: A fluent Android
2022-08-15
-
florent37/Shrine-MaterialDesign2: implem
2022-08-17
-
CVE-2020-36276
2022-09-23
-
SimpleSoftwareIO/simple-sms: Send and re
2022-08-13
请发表评论