博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)
阅读量:6282 次
发布时间:2019-06-22

本文共 6811 字,大约阅读时间需要 22 分钟。

在线演示地址:

 

上上一节,就是二十八节:

 

我们实现了“开始”游戏后,对棋子的限制,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

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

ExpandedBlockStart.gif
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加个属性了:

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

 

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

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

ExpandedBlockStart.gif
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添加接口:

ExpandedBlockStart.gif
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,轻轻松松就完工,四行代码搞定。

ExpandedBlockStart.gif
 
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的方法就行了:

ExpandedBlockStart.gif
 
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了,于是,大哥啊,代理快出来:

还记得以前,不记得回去看看了。

 

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

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

ExpandedBlockStart.gif
 
///
 
<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里,我们要实现做下代理人:

ExpandedBlockStart.gif
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象棋类里,添加方法,"马走一步",太简单了:

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

 

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

回到ChessAction.cs里:

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

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

ExpandedBlockStart.gif
 
///
 
<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:

ExpandedBlockStart.gif
 
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方法里添加的一行事件位置不对:

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

ExpandedBlockStart.gif
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

你可能感兴趣的文章
js + swoole 实现websocket
查看>>
pm2 for linux
查看>>
centos7如何安装sshpass
查看>>
IntelliJ IDEA搭建SpringBoot应用完成的一个小Demo(一)
查看>>
大话数据结构--第一章数据结构绪论
查看>>
腾讯将两大自研项目送给Linux基金会
查看>>
圣诞专场回顾 | “K8S Sail!”系列技术沙龙深圳站
查看>>
高并发服务器-连接池的设计
查看>>
Docker容器端口配置
查看>>
守护进程
查看>>
Java 集合系列02之 Collection架构
查看>>
Java 代码 编译和执行过程
查看>>
Centos7通过yum安装Jenkins
查看>>
SylixOS 调试方法详解(二)——SylixOS 代码覆盖率检查
查看>>
linux命令下导出导入.sql文件
查看>>
Ehcache持久化小插曲
查看>>
转载001:使用vscode,新建.vue文件,tab自动生成vue代码模板
查看>>
springboot+mybatis 整合时扫描任意路径下的xxx.xml文件
查看>>
企业IT架构转型,你准备好接招了吗?
查看>>
HBase基本操作-shell使用
查看>>