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

在线演示地址: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,本节到此,打完收工!

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

 

版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:

http://www.cnblogs.com/cyq1162/archive/2010/07/30/1788879.html

时间: 2024-07-29 01:56:48

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

Silverlight+WCF 新手实例 象棋 该谁下棋-A下B停(二十八)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   上一节,我们实现了"开始"游戏,并互相通知可以开始游戏了:可是我们并没有对棋子进行限制,双方都可以随时的下: 所以,接下来我们要实现对棋子的限制,A下B停,B下A停,同时,要传递棋步,对方收到棋步,要反转棋步坐标,还得自动移动棋子.   说了这么多,我们从哪里开始下手呢?其实我也想了很久...... 让我们回到Chess象棋类,于是添加一个属性IsCanMove //象棋类 by 路过秋天public clas

Silverlight+WCF 新手实例 象棋 主界面-事件区-游戏开始(二十七)

本专题出产简单原由: 一开始的初衷,只是想写个简单的单机BS人机对战版的,开始还下了点AI算法看看的: 但是写到最后,都写成了通讯版本的对战了,只因中间不小心看到了WCF的相关内容,顺便加了进来; 最后就定局了,反正新手实例,能加多点内容就加多点了. 关于原始初衷,后期再补上了.       好了,先上几个附加索引: 1:Silverlight+WCF 新手实例 象棋 在线演示 2:Silverlight+WCF 简单部署问题集 3:Silverlight4 ListBox bug 4:Silv

Silverlight+WCF 新手实例 象棋 棋手颜色(二十九)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   在上一节Silverlight+WCF 新手实例 象棋 该谁下棋-A下B停(二十八),我们在最后聊天对话中看到,双方棋手用的竟然都是红色,这个...... 这节,我们来让双方使用不同的颜色下棋:   我们通过什么来决定棋手的颜色?其实,Player玩家属性里,不就有一个ColorValue么,有了这个,一切就好办了. 我们回到Chess象棋类里,增加一个属性,玩家颜色,同时,扩展一下构造函数,增加传参:  /// <su

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

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   在Silverlight+WCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)中,我们完成下棋双方的棋谱显示,这节,我们为观众增加棋子列表: 观众进入房间后,第一时间当然也要获取棋步列表了,不然进来干麻呢?你当这是聊天室啊,光聊天不看棋.   首先,当然是要在服务端添加一个获取棋步列表的接口方法了: WCF服务端,IService.cs:  /// <summary>     /// 服务端方法接口 by 路过秋天

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

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   本节完后,同时会更新Silverlight+WCF 新手实例 象棋 专题索引,并顺路提供第八阶段源码   在Silverlight+WCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)节中,我们完成了下棋双方的棋谱传递 在Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)节中,我们完成了观棋者获取棋谱列表 在本节中,我们要进行最一步了,棋谱回放: 首先,当用户进入列表后,获取完棋谱信息之

Silverlight+WCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   这节,我们要实现棋谱列界面布局和棋谱的获取,先上一张久远的图片: 看清楚了,到本节为止,除了第三区棋谱区,其它的区域我们都已完成了,所以,我们抓紧时间,赶紧吧:   好了,先布局,和以往一样:   1:界面拖一个Border到Index.xaml,到第三区的位置,设置好宽和高[212*602]: <UserControl ...省略...   d:DesignHeight="620" d:DesignWi

Silverlight+WCF 新手实例 象棋 主界面-棋盘区(二十二)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   这节我们要布局Index.xaml界面. 首先,我们定义一下全局的宽和高:1000*620[数字差不多就行了] 一堆代码,都是自动生成的,只是改了两个数字,不说大伙也知道改啥数字了. <UserControl x:Class="NewChessProject.Index"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen

Silverlight+WCF 新手实例 象棋 介绍III(二十三)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   虽然有在线演示,不过还是要写一个介绍,因为并没有实时更新到在线演示 说是介绍,其实就是阶段进度报告,现在看一下最近的更新吧: 先来总体截一下图看看变化吧: 1.登陆: 增加了初始作者文字显示[没用户时默认文字],和在当前线用户数显示. 我开了三个浏览器窗口才截到这图. 2:房间: 这里从QQ象棋里弄了两张背景图过来,换了一下之前的房间背景,如果是游戏对战中,桌面背景就变成了: 3:增加倒计时子窗口实现,替换掉了Messa

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

上上一节,我们对棋子的下半盘棋子做了所有的规则限制,因为我们下棋的总是用下半盘的棋子来下,总没人用上半盘棋来下那么高境界的吧. 不过这节简单追加点代码,让那些企图高境界的人士可以临时性的自己和自己下. 好了,要为上半盘棋子也做限制,所以我们要知道棋子是归属于上半盘还是下半盘的,这里,我们为棋子类Chessman增加一个属性,IsUp,是否上半盘棋,反之就下半盘了.初始为该属性赋值也相当的简单:  /// <summary>         /// 棋子默认在上半盘/反之在下半盘