Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)
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停(三十)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AOP、注解实现日志收集
- 下一篇: WCF的CommunicationObj