2019独角兽企业重金招聘Python工程师标准>>>

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示

上上一节,就是二十八节:Silverlight+WCF 新手实例 象棋 该谁下棋-A下B停(二十八)

我们实现了“开始”游戏后,对棋子的限制,A下B停

这节,我们要实现:B下A停,[同时,传递棋步,对方收到棋步,要反转棋步坐标,自动移动棋子]

所以呢,这节我们要实现的东西是比上上一节相对多一点。

少废话,开始了:

按流程来了,A移动棋子之后,要干点什么事呢?

//-------这是一个AB同样的循环流程-----

1:自己不能再动了,IsCanMove=false;

2:要记录移动坐标

3:传递坐标给对方

4:对方要接收坐标->反转坐标[对方的坐标对自己来说,肯定是相反的啦,自己把头反过来看下棋盘就有点清楚了]

5:对方系统自动移动棋子

6:对方的IsCanMove=true

7:然后到对方下棋了。

8:对方下棋之后呢?Go to 1

//-----又回到开始,不断的循环------

我们先来增加一个用于传递棋步类,既然是传递的,当然得在WCF端新建了,回到和Player一样位置[就是DataContract文件夹下了]:

添加文件类名:MoveStep.cs

namespace  GameService
{
     ///   <summary>
     ///  WCF 传递的棋步 by 路过秋天
     ///   http://cyq1162.cnblogs.com
     ///   </summary>
     public   class  MoveStep
    {

}
}

当了棋步传递使者,自然得属性加身了,看看加了什么属性:

ID:这个用于标识是第几步,好像没怎么用到

Name:名称,是马还是炮

ColorValue:什么颜色的

下面四个一看就知,为什么不用Point传递,和那个ColorValue一样,WCF的Point和Silverlight客户端的名称空间不一样[马走一下]

FromX

FromY

ToX

ToY

于是一个一个的敲完就像下面这样了:


using  System.Runtime.Serialization;
namespace  GameService
{
     ///   <summary>
     ///  WCF 传递的棋步 by 路过秋天
     ///   http://cyq1162.cnblogs.com
     ///   </summary>
     public   class  MoveStep
    {
         ///   <summary>
         ///  棋的步数
         ///   </summary>
        [DataMember]
         public   int  ID
        {
             get ;
             set ;
        }
         ///   <summary>
         ///  棋的原始X位置
         ///   </summary>
        [DataMember]
         public   double  FromX
        {
             get ;
             set ;
        }
         ///   <summary>
         ///  棋的原始Y位置
         ///   </summary>
        [DataMember]
         public   double  FromY
        {
             get ;
             set ;
        }
         ///   <summary>
         ///  棋的移动X位置
         ///   </summary>
        [DataMember]
         public   double  ToX
        {
             get ;
             set ;
        }
         ///   <summary>
         ///  棋的移动X位置
         ///   </summary>
        [DataMember]
         public   double  ToY
        {
             get ;
             set ;
        }
         ///   <summary>
         ///  棋的名称
         ///   </summary>
        [DataMember]
         public   string  Name
        {
             get ;
             set ;
        }
         ///   <summary>
         ///  棋的移颜色值
         ///   </summary>
        [DataMember]
         public   int  ColorValue
        {
             get ;
             set ;
        }
    }
}

我们习惯了一直都传递Player,所以,为Player加个属性了:

namespace  GameService
{
     ///   <summary>
     ///  游戏玩家 by 路过秋天
     ///   </summary>
    [DataContract]
     public   class  Player
    {
         // ...省略其它属性...
        [DataMember]
         public  MoveStep Step
        {
             get ;
             set ;
        }
       
    }
}

同时啊,同时啊,刚刚想起来-_-...,我们要为房间添加一个棋子列表,记录每步棋步,不然刚进房间的人看西北风的啊。

同时添加了构造函数,初始化一下List,不然Null魂就会老跟着你。

namespace  GameService
{
    [DataContract]
     public   class  Room
    {
         public  Room()
        {
            StepList  =   new  List < MoveStep > ();
        }
         ///   <summary>
         ///  房间的棋谱
         ///   </summary>
        [DataMember]
         public  List < MoveStep >  StepList
        {
             get ;
             set ;
        }
         // ...省略下面N个属性...
      }
}

OK,传递使者和两个XX都有了,那我们要在WCF端建立传递和接收的接口了,这下我们只要传递Player来来去去的就行了:

IService.cs添加接口:


namespace  GameService
{
    [ServiceContract(CallbackContract  =   typeof (ICallBack))] // 头顶上这里写明了回调是ICallBack
     public   interface  IService
    {
        // ...省略上面N个接口...
        [OperationContract(IsOneWay  =   true )]
         void  MoveStep(Player player);

}
}

ICallBack.cs添加接口:

namespace  GameService
{
     interface  ICallBack
    {
         // ...省略上面N个接口...
        [OperationContract(IsOneWay  =   true )]
         void  NotifyMoveStep(Player player); // 通知接收棋步
    }
}

OK,接着我们一如既往的实现MoveStep接口方法

Service.svc.cs,轻轻松松就完工,四行代码搞定。

  public   void  MoveStep(Player player)
        {
            Room room  =  roomList[player.RoomID];
            player.Step.ID  =  room.StepList.Count  +   1 ;
            room.StepList.Add(player.Step);
            Notify.Game(player, GameType.Move);
        }

那个Notify.Game我们上节都有的了,我们回到Notify里补一个Switch里的Case GameType.Move的方法就行了:

  internal   static   void  Game(Player player, GameType type)
        {
             switch  (type)
            {
                 case  GameType.Start: // 通知对方玩家开始游戏
                     // ...上上节实现了...
                     break ;
                 case  GameType.Move: // 通知移动了,房间内人手一份
                     foreach  (KeyValuePair < Guid, Player >  item  in  Service.playerList[player.RoomID])
                    {
                       item.Value.CallBack.NotifyMoveStep(player);
                    }
                     break ;
                 case  GameType.End:
                     break ;
            }
        }

OK,到此,服务端完成了,编绎,更新引用:

接着我们回到客户端,要开始发送和接收了:

哪里加发送呢?我们棋步在哪里移动,就在哪里发送了

哪里移动呢?想啦啦找啦啦:棋子移动类ChessAction里的MoveTo方法,我们要在里面添加一个移动后触发的事件

可是怎么触发?单独的类里,是拿不到App.Client对象,更别说传递了到WCF了,于是,大哥啊,代理快出来:

还记得以前Silverlight+WCF 新手实例 象棋 主界面-控件消息传递(二十六),不记得回去看看了。

我们在ChessAction里添加一个代理事件:

看,我们定义代理事件之后只增加一句代码,在移动后直接调用,至于怎么实现的,我们全不理,反正有人帮我干这事。

  ///   <summary>
     ///  棋子动作类 by 路过秋天
     ///   </summary>
     public   class  ChessAction
    {
         public   delegate   void  HelpMoveStep(Chessman chessman, Point movePoint);
         public   event  HelpMoveStep HelpMoveStepEvent;
       
        
         public   bool  MoveTo(Chessman chessman, Point moveTo)
        {
             if  (Rule.IsCanMove(chessman, moveTo))
            {
                chessman.ReadyMove  =   false ;
                chessman.chessman.Background  =   null ;
                PlayMove(chessman, moveTo);
                chessman.MovePoint  =  moveTo;
                HelpMoveStepEvent(chessman, moveTo); // 这里增加一句
                 return   true ;
            }
             return   false ;
        }
          // ... 其它省略N多...
 }

OK,我们回到Chess.xaml.cs里,我们要实现做下代理人:

public  Chess()
        {
            // ..省略N行...
            chess.Action.HelpMoveStepEvent  +=   new  ChessNewInstance.ChessAction.HelpMoveStep(Action_HelpMoveStepEvent);
            App.chess  =  chess; // 为全局对象赋值
        }

void  Action_HelpMoveStepEvent(ChessNewInstance.Chessman chessman, Point moveTo)
        {
            MoveStep step  =   new  MoveStep();
            step.FromX  =  chessman.MovePoint.X;
            step.FromY  =  chessman.MovePoint.Y;
            step.ToX  =  moveTo.X;
            step.ToY  =  moveTo.Y;
            step.ColorValue  =  chessman.Color  ==  Colors.Red  ?   1  :  2 ;
            step.Name  =  chessman.Name;
            App.player.Step  =  step; // 附加棋步
            App.client.MoveStepAsync(App.player);
            chess.IsCanMove  =   false ;
        }

设置完杂七杂八的参数后,把Step放到Player身上,就传递到服务端了,然后设置一下IsCanMove=false;

发送棋步就搞完了,接下来要接收棋步了,不过在接收棋上之前,我们要先完成一个函数,反转坐标:

我们回到Chess.cs象棋类里,添加方法,"马走一步",太简单了:

  ///   <summary>
         ///  反转棋子坐标
         ///   </summary>
         public  Point ReverseArray(Point point)
        {
            point.X  =   8   -  point.X;
            point.Y  =   9   -  point.Y;
             return  point;
        }

别急,我们还要添加一个自动移动的方法:

回到ChessAction.cs里:

需要解释代码么?不需要吧

解释:既然是系统自动移动,就不用判断什么规则了,直接把棋子移过去,如果移动到的另一个点有棋子,就移掉,然后设置一下坐标。

  ///   <summary>
         ///  系统自动移动棋子
         ///   </summary>
         public   void  AutoMoveTo(Point from, Point to)
        {
            Chessman chessman  =  Parent.FindChessman(from);
            Chessman eatchessman  =  Parent.FindChessman(to);
             if  (chessman  !=   null )
            {
                PlayMove(chessman, to);
                chessman.MovePoint  =  to;
                 if  (eatchessman  !=   null )
                {
                    eatchessman.GoToDead();
                }
            }
        }

好了,可以接收了,要实现了,眼睛睁大点,回到Chess.xaml.cs:

  public   partial   class  Chess : UserControl
    {
        ChessNewInstance.Chess chess; // 这里我们同时把它提到全局对象
         public  Chess()
        {
            // ...省略N行...
            App.client.NotifyMoveStepReceived  +=   new  EventHandler < NotifyMoveStepReceivedEventArgs > (client_NotifyMoveStepReceived);
            App.chess  =  chess; // 为全局对象赋值

}

void  client_NotifyMoveStepReceived( object  sender, NotifyMoveStepReceivedEventArgs e)
        {
             if  (App.player.ID  !=  e.player.ID) // 非自己
            {
                GameService.MoveStep step  =  e.player.Step;
                Point from  =   new  Point(step.FromX, step.FromY);
                Point to  =   new  Point(step.ToX, step.ToY);
                 // 转换坐标
                 if  (e.player.ColorValue  ==   2   ||  App.player.ColorValue  !=   3 ) // 旁观者 黑色棋子
                {
                    from  =  chess.ReverseArray(from);
                    to  =  chess.ReverseArray(to);
                }
                chess.Action.AutoMoveTo(from, to);
                 if  (App.player.ColorValue  !=   3 ) // 下棋者
                {
                    chess.IsCanMove  =   true ;
                }
            }
        }
         // ....省略N行...
    }

看清楚,就是转换坐标,然后移动棋子,设置一下IsCanMove。

OKOKOK,代码终于全部写完了,可以F5运行看效果了:

“马再走一步”,上面代码棋子没有自动移动,又要调试了,不截图先:

断点一调试,发现接收的点都是一样的,一步步回去查,终于发现在MoveTo方法里添加的一行事件位置不对:

看有位置的那两行,看清楚了。

public   bool  MoveTo(Chessman chessman, Point moveTo)
        {
             if  (Rule.IsCanMove(chessman, moveTo))
            {
                chessman.ReadyMove  =   false ;
                chessman.chessman.Background  =   null ;
                PlayMove(chessman, moveTo);
                HelpMoveStepEvent(chessman, moveTo); // 这一行要在上
                chessman.MovePoint  =  moveTo; // 这一行要在下
                
                 return   true ;
            }
             return   false ;
        }

OK,现在可以F5看效果了,截图:

OK,本节到此,打完收工!

顺逢周五,打包源码:第六阶段源码:点击下载

转载于:https://my.oschina.net/secyaher/blog/274172

Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)相关推荐

  1. Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)

    2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界 ...

  2. Silverlight+WCF 新手实例 象棋 主界面-事件区-返回退出(三十三)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 还是那张图: 本节实现返回大厅和退出系统: 一:返回大厅,其实很简单的说,就是转向房间列表了. 可是,转向前也有很多事情要处理的 ...

  3. Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放-结局(四十)

    在线演示地址: Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放(三十九)中,我们实现了用户的棋谱回放,在文章的下面,我们 ...

  4. Silverlight+WCF 新手实例 象棋 棋子移动-规则[附加上半盘限制](十)

    上上一节,我们对棋子的下半盘棋子做了所有的规则限制,因为我们下棋的总是用下半盘的棋子来下,总没人用上半盘棋来下那么高境界的吧. 不过这节简单追加点代码,让那些企图高境界的人士可以临时性的自己和自己下. ...

  5. Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放(三十九)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 本节完后,同时会更新Silverlight+WCF 新手实例 象棋 专题索引,并顺路提供第八阶段源码 在Silverlight+ ...

  6. Silverlight+WCF 新手实例 象棋 主界面-实时聊天区(二十五)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三) 本节连着Silverlight+WC ...

  7. Silverlight+WCF 新手实例 象棋 主界面-事件区-求和认输(三十二)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 事隔几篇,我们又回到事件区,继续其它两个按钮事件,来张图吧: 在Silverlight+WCF 新手实例 象棋 主界面-事件区- ...

  8. Silverlight+WCF 新手实例 象棋 棋盘(二)

    2019独角兽企业重金招聘Python工程师标准>>> 1.先新建一个和棋子相关的类库 打开VS2010后->新建->项目->Silverlight类库,名称就定为 ...

  9. Silverlight+WCF 新手实例 象棋 棋子(三)

    2019独角兽企业重金招聘Python工程师标准>>> 棋盘上有棋子,棋子应该还有一些属性,按原始冲动新建一个棋子类. 上google翻译下棋子E文叫什么,查到了叫Chessman, ...

最新文章

  1. RDKit | RDKit处理graph-化合物的邻接矩阵、距离矩阵和维纳指数
  2. node debug包
  3. 关于未达账项的账务处理
  4. 公司这个月要同时完成好多项目!!!
  5. Mysql数据库的高可用
  6. 点击图片添加文件在Chrome中使用的兼容问题
  7. 【Spring笔记】使用javaconfig配置
  8. 作为字节跳动的研发面试官,有些话我不得不说!
  9. 测试用例设计方法有哪些?
  10. abb机器人指令手册_ABB机器人CCLink 配置
  11. 如果楼市崩盘,我们怎么活?
  12. 收费版ESX 与免费版ESXi的区别
  13. 微信开发者工具之页面跳转
  14. java pv uv 统计_shell统计pv和uv、独立ip的方法
  15. 抽丝拨茧——EventBus源码解析
  16. java密码框转字符串_实现汉字的凯撒密码(内容包括:去掉字符串中的转义字符、汉字的unicode转换)...
  17. geek_2013年How-To Geek的节日礼物指南:一定要装满东西
  18. 3DLC系列:A/B 网格应用实践
  19. html省市多级联动下拉框,基于javascript实现全国省市二级联动下拉选择菜单
  20. [RK3399][Android7.1] Display中的VOP模块介绍

热门文章

  1. leetcode算法题--螺旋矩阵
  2. OVS vswitchd启动(三十九)
  3. linux内核网络协议栈--数据包的网卡驱动收发包过程(二十五)
  4. C/C++中存储类型
  5. python生成验证码
  6. wchar_t*,wchar_t,wchat_t数组,char,char*,char数组,std::string,std::wstring,CString....转换
  7. c语言常见50题 及答案(递归 循环 以及常见题目)
  8. C语言-线性表基本操作之单链表
  9. 多线程和Socket——在线聊天室
  10. FCKeditor在线文本编辑器初级应用