Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
在線(xiàn)演示地址:Silverlight+WCF 新手實(shí)例 象棋 在線(xiàn)演示
?
上上一節(jié),就是二十八節(jié):Silverlight+WCF 新手實(shí)例 象棋 該誰(shuí)下棋-A下B停(二十八)
?
我們實(shí)現(xiàn)了“開(kāi)始”游戲后,對(duì)棋子的限制,A下B停
這節(jié),我們要實(shí)現(xiàn):B下A停,[同時(shí),傳遞棋步,對(duì)方收到棋步,要反轉(zhuǎn)棋步坐標(biāo),自動(dòng)移動(dòng)棋子]
所以呢,這節(jié)我們要實(shí)現(xiàn)的東西是比上上一節(jié)相對(duì)多一點(diǎn)。
?
少?gòu)U話(huà),開(kāi)始了:
按流程來(lái)了,A移動(dòng)棋子之后,要干點(diǎn)什么事呢?
//-------這是一個(gè)AB同樣的循環(huán)流程-----
1:自己不能再動(dòng)了,IsCanMove=false;
2:要記錄移動(dòng)坐標(biāo)
3:傳遞坐標(biāo)給對(duì)方
4:對(duì)方要接收坐標(biāo)->反轉(zhuǎn)坐標(biāo)[對(duì)方的坐標(biāo)對(duì)自己來(lái)說(shuō),肯定是相反的啦,自己把頭反過(guò)來(lái)看下棋盤(pán)就有點(diǎn)清楚了]
5:對(duì)方系統(tǒng)自動(dòng)移動(dòng)棋子
6:對(duì)方的IsCanMove=true
7:然后到對(duì)方下棋了。
8:對(duì)方下棋之后呢?Go to 1
//-----又回到開(kāi)始,不斷的循環(huán)------
我們先來(lái)增加一個(gè)用于傳遞棋步類(lèi),既然是傳遞的,當(dāng)然得在WCF端新建了,回到和Player一樣位置[就是DataContract文件夾下了]:
添加文件類(lèi)名:MoveStep.cs
namespace ?GameService{
???? /// ? <summary>
???? /// ?WCF?傳遞的棋步?by?路過(guò)秋天
???? /// ? http://cyq1162.cnblogs.com
???? /// ? </summary>
???? public ? class ?MoveStep
????{
????}
}
?
當(dāng)了棋步傳遞使者,自然得屬性加身了,看看加了什么屬性:
ID:這個(gè)用于標(biāo)識(shí)是第幾步,好像沒(méi)怎么用到
Name:名稱(chēng),是馬還是炮
ColorValue:什么顏色的
下面四個(gè)一看就知,為什么不用Point傳遞,和那個(gè)ColorValue一樣,WCF的Point和Silverlight客戶(hù)端的名稱(chēng)空間不一樣[馬走一下]
FromX
FromY
ToX
ToY
于是一個(gè)一個(gè)的敲完就像下面這樣了:
using ?System.Runtime.Serialization;
namespace ?GameService {
???? /// ? <summary>
???? /// ?WCF?傳遞的棋步?by?路過(guò)秋天
???? /// ? http://cyq1162.cnblogs.com
???? /// ? </summary>
???? public ? class ?MoveStep
????{
???????? /// ? <summary>
???????? /// ?棋的步數(shù)
???????? /// ? </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>
???????? /// ?棋的移動(dòng)X位置
???????? /// ? </summary>
????????[DataMember]
???????? public ? double ?ToX
????????{
???????????? get ;
???????????? set ;
????????}
???????? /// ? <summary>
???????? /// ?棋的移動(dòng)X位置
???????? /// ? </summary>
????????[DataMember]
???????? public ? double ?ToY
????????{
???????????? get ;
???????????? set ;
????????}
???????? /// ? <summary>
???????? /// ?棋的名稱(chēng)
???????? /// ? </summary>
????????[DataMember]
???????? public ? string ?Name
????????{
???????????? get ;
???????????? set ;
????????}
???????? /// ? <summary>
???????? /// ?棋的移顏色值
???????? /// ? </summary>
????????[DataMember]
???????? public ? int ?ColorValue
????????{
???????????? get ;
???????????? set ;
????????}
????}
}
?
我們習(xí)慣了一直都傳遞Player,所以,為Player加個(gè)屬性了:
namespace ?GameService{
???? /// ? <summary>
???? /// ?游戲玩家?by?路過(guò)秋天
???? /// ? </summary>
????[DataContract]
???? public ? class ?Player
????{
???????? // ...省略其它屬性...
????????[DataMember]
???????? public ?MoveStep?Step
????????{
???????????? get ;
???????????? set ;
????????}
???????
????}
}
?
同時(shí)啊,同時(shí)啊,剛剛想起來(lái)-_-...,我們要為房間添加一個(gè)棋子列表,記錄每步棋步,不然剛進(jìn)房間的人看西北風(fēng)的啊。
同時(shí)添加了構(gòu)造函數(shù),初始化一下List,不然Null魂就會(huì)老跟著你。
namespace ?GameService{
????[DataContract]
???? public ? class ?Room
????{
???????? public ?Room()
????????{
????????????StepList? = ? new ?List < MoveStep > ();
????????}
???????? /// ? <summary>
???????? /// ?房間的棋譜
???????? /// ? </summary>
????????[DataMember]
???????? public ?List < MoveStep > ?StepList
????????{
???????????? get ;
???????????? set ;
????????}
???????? // ...省略下面N個(gè)屬性...
??????}
}
?
?
OK,傳遞使者和兩個(gè)XX都有了,那我們要在WCF端建立傳遞和接收的接口了,這下我們只要傳遞Player來(lái)來(lái)去去的就行了:
IService.cs添加接口:
namespace ?GameService
{
????[ServiceContract(CallbackContract? = ? typeof (ICallBack))] // 頭頂上這里寫(xiě)明了回調(diào)是ICallBack
???? public ? interface ?IService
????{
??????? // ...省略上面N個(gè)接口...
????????[OperationContract(IsOneWay? = ? true )]
???????? void ?MoveStep(Player?player);
????}
}
?
ICallBack.cs添加接口:
namespace ?GameService{
???? interface ?ICallBack
????{
???????? // ...省略上面N個(gè)接口...
????????[OperationContract(IsOneWay? = ? true )]
???????? void ?NotifyMoveStep(Player?player); // 通知接收棋步
????}
}
?
OK,接著我們一如既往的實(shí)現(xiàn)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);
????????}
?
那個(gè)Notify.Game我們上節(jié)都有的了,我們回到Notify里補(bǔ)一個(gè)Switch里的Case GameType.Move的方法就行了:
? internal ? static ? void ?Game(Player?player,?GameType?type)????????{
???????????? switch ?(type)
????????????{
???????????????? case ?GameType.Start: // 通知對(duì)方玩家開(kāi)始游戲
???????????????????? // ...上上節(jié)實(shí)現(xiàn)了...
???????????????????? break ;
???????????????? case ?GameType.Move: // 通知移動(dòng)了,房間內(nèi)人手一份
???????????????????? foreach ?(KeyValuePair < Guid,?Player > ?item? in ?Service.playerList[player.RoomID])
????????????????????{
???????????????????????item.Value.CallBack.NotifyMoveStep(player);
????????????????????}
???????????????????? break ;
???????????????? case ?GameType.End:
???????????????????? break ;
????????????}
????????}
?
OK,到此,服務(wù)端完成了,編繹,更新引用:
接著我們回到客戶(hù)端,要開(kāi)始發(fā)送和接收了:
哪里加發(fā)送呢?我們棋步在哪里移動(dòng),就在哪里發(fā)送了
哪里移動(dòng)呢?想啦啦找啦啦:棋子移動(dòng)類(lèi)ChessAction里的MoveTo方法,我們要在里面添加一個(gè)移動(dòng)后觸發(fā)的事件
可是怎么觸發(fā)?單獨(dú)的類(lèi)里,是拿不到App.Client對(duì)象,更別說(shuō)傳遞了到WCF了,于是,大哥啊,代理快出來(lái):
還記得以前Silverlight+WCF 新手實(shí)例 象棋 主界面-控件消息傳遞(二十六),不記得回去看看了。
?
我們?cè)贑hessAction里添加一個(gè)代理事件:
看,我們定義代理事件之后只增加一句代碼,在移動(dòng)后直接調(diào)用,至于怎么實(shí)現(xiàn)的,我們?nèi)焕?#xff0c;反正有人幫我干這事。
? /// ? <summary>???? /// ?棋子動(dòng)作類(lèi)?by?路過(guò)秋天
???? /// ? </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里,我們要實(shí)現(xiàn)做下代理人:
public ?Chess()????????{
??????????? // ..省略N行...
????????????chess.Action.HelpMoveStepEvent? += ? new ?ChessNewInstance.ChessAction.HelpMoveStep(Action_HelpMoveStepEvent);
????????????App.chess? = ?chess; // 為全局對(duì)象賦值
????????}
???????? 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 ;
????????}
?
設(shè)置完雜七雜八的參數(shù)后,把Step放到Player身上,就傳遞到服務(wù)端了,然后設(shè)置一下IsCanMove=false;
?
發(fā)送棋步就搞完了,接下來(lái)要接收棋步了,不過(guò)在接收棋上之前,我們要先完成一個(gè)函數(shù),反轉(zhuǎn)坐標(biāo):
我們回到Chess.cs象棋類(lèi)里,添加方法,"馬走一步",太簡(jiǎn)單了:
? /// ? <summary>???????? /// ?反轉(zhuǎn)棋子坐標(biāo)
???????? /// ? </summary>
???????? public ?Point?ReverseArray(Point?point)
????????{
????????????point.X? = ? 8 ? - ?point.X;
????????????point.Y? = ? 9 ? - ?point.Y;
???????????? return ?point;
????????}
?
別急,我們還要添加一個(gè)自動(dòng)移動(dòng)的方法:
回到ChessAction.cs里:
需要解釋代碼么?不需要吧
解釋:既然是系統(tǒng)自動(dòng)移動(dòng),就不用判斷什么規(guī)則了,直接把棋子移過(guò)去,如果移動(dòng)到的另一個(gè)點(diǎn)有棋子,就移掉,然后設(shè)置一下坐標(biāo)。
? /// ? <summary>???????? /// ?系統(tǒng)自動(dòng)移動(dòng)棋子
???????? /// ? </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();
????????????????}
????????????}
????????}
?
?
好了,可以接收了,要實(shí)現(xiàn)了,眼睛睜大點(diǎn),回到Chess.xaml.cs:
? public ? partial ? class ?Chess?:?UserControl????{
????????ChessNewInstance.Chess?chess; // 這里我們同時(shí)把它提到全局對(duì)象
???????? public ?Chess()
????????{
??????????? // ...省略N行...
????????????App.client.NotifyMoveStepReceived? += ? new ?EventHandler < NotifyMoveStepReceivedEventArgs > (client_NotifyMoveStepReceived);
????????????App.chess? = ?chess; // 為全局對(duì)象賦值
??????????
????????}
???????? 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);
???????????????? // 轉(zhuǎn)換坐標(biāo)
???????????????? if ?(e.player.ColorValue? == ? 2 ? || ?App.player.ColorValue? != ? 3 ) // 旁觀(guān)者?黑色棋子
????????????????{
????????????????????from? = ?chess.ReverseArray(from);
????????????????????to? = ?chess.ReverseArray(to);
????????????????}
????????????????chess.Action.AutoMoveTo(from,?to);
???????????????? if ?(App.player.ColorValue? != ? 3 ) // 下棋者
????????????????{
????????????????????chess.IsCanMove? = ? true ;
????????????????}
????????????}
????????}
???????? // ....省略N行...
????}
?
看清楚,就是轉(zhuǎn)換坐標(biāo),然后移動(dòng)棋子,設(shè)置一下IsCanMove。
OKOKOK,代碼終于全部寫(xiě)完了,可以F5運(yùn)行看效果了:
“馬再走一步”,上面代碼棋子沒(méi)有自動(dòng)移動(dòng),又要調(diào)試了,不截圖先:
斷點(diǎn)一調(diào)試,發(fā)現(xiàn)接收的點(diǎn)都是一樣的,一步步回去查,終于發(fā)現(xiàn)在MoveTo方法里添加的一行事件位置不對(duì):
看有位置的那兩行,看清楚了。
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,現(xiàn)在可以F5看效果了,截圖:
?
OK,本節(jié)到此,打完收工!
順?lè)曛芪?#xff0c;打包源碼:第六階段源碼:點(diǎn)擊下載
?
?
轉(zhuǎn)載于:https://my.oschina.net/secyaher/blog/274172
總結(jié)
以上是生活随笔為你收集整理的Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: AOP、注解实现日志收集
- 下一篇: WCF的CommunicationObj