在本節中,我們要進行最一步了,棋譜回放:
首先,當使用者進入清單後,擷取完棋譜資訊之後,第一個動作,就是要把棋譜按順序播放一下,這樣,使用者看到棋局就是雙方正在下的棋局了,之後,就跟下棋一樣,一步步接收棋步,然後一步步的自動移動就行了。
我們播放哪裡的棋譜呢的?
界面上顯示的listbox顯然是不能用來循環讀取的,畢竟那顯示的是格式化後的字元串,從字元串解析回棋步是不現實的;
一開始擷取的清單不是可以循環?那也隻有一部分,之後棋手雙方下的呢?
是以,說了這麼多,其實不就是想找多個變量來存棋譜清單麼,于是,我們在app.xaml.cs全局又添加一個全局變量了:

public partial class app : application
{
//...省略n行代碼...
public static list<gameservice.movestep> steplist = new list<gameservice.movestep>();//棋譜
public static bool chessmanualplaying = false;//棋譜正回放中
//...省略n行代碼...
public app()
{
//...省略n行代碼...
}
}

這裡又順路添加了一個全局屬性,用于設定棋譜是不是正在回放中,後面我們會用到[很後哦]。
ok,全局棋譜存貯變量有了,我們就得為它增加棋譜資料了,我們會在兩個地方添加棋譜,
1:一個是使用者下棋時傳遞時的棋譜:
我們進入chess.xaml.cs,找到收到棋譜通知的代碼,隻需要添加一行,第一行,把棋步添加一下就行了:

void client_notifymovestepreceived(object sender, notifymovestepreceivedeventargs e)
app.steplist.add(e.player.step);//隻需要一行
if (app.player.id != e.player.id)//非自己
{
//...省略n行...
}
helpsetchessmanualevent(e.player.step);

2:進入頁面時擷取的棋譜清單讀取到棋譜區時:
我們進入chessmanual.xaml.cs,找到擷取棋譜清單的代碼,同樣隻需要一行:

void client_getmovesteplistcompleted(object sender, gameservice.getmovesteplistcompletedeventargs e)
//擷取完棋譜後,這裡循環調用添加就可以了
if (e.result != null && e.result.count > 0)
app.steplist = e.result;//這裡隻需要一行代碼
foreach (gameservice.movestep step in e.result)
{
lbchessmanual.items.add(step.id + ":" + step.name);
}

ok,我們對全局棋譜的傳值,兩行代碼就搞定了,于是在播放棋譜時,理論上我們循環全局的steplist就行了:
我們先産生一個方法,用于播放一個棋步,就是傳進一個棋步,然後自動播放:

void automove(gameservice.movestep step)
point from = new point(step.fromx, step.fromy);
point to = new point(step.tox, step.toy);
if (app.player.colorvalue + step.colorvalue == 3 || (step.colorvalue == 2 && app.player.colorvalue == 3))//旁觀者 黑色棋子
from = app.chess.reversearray(from);
to = app.chess.reversearray(to);
app.chess.action.automoveto(from, to);

這個方法其實有點簡單,隻要調用aotomoveto就搞完了,唯一的複雜點,就是判斷要不要反轉坐标了。
[兩種情況:如果是下棋者,棋步是對手的,要反轉坐标;觀衆預設是紅色的,收到黑色棋步,也要反轉坐标]
好了,有了單步的方法,我們for一下step裡,然後循環傳值就ok了?no,如果這樣循環,棋步刷的一下就沒了,還看啥回放?
是以,我們需要定間隔播放了,是以,我們需要先産生間隔的秒數,我們通過滑動塊來設定文本框的數字:
我們設定一下滑動塊的屬性[預設值為0,最大值為9,最小滑動為0.5,最大滑動為1]:
我們同時添加滑動事件:
而我們滑動時隻需要一行代碼,為文本框指派就行了:
private void slplayerinternal_valuechanged(object sender, routedpropertychangedeventargs<double> e)
txtvalue.text = e.newvalue.tostring();
我們增加一個方法,叫playstep,用于循環播放棋步:
private void playstep()
{
//待實作
好了,接着我們輕按兩下一下“回放”按鈕,裡面調用一下這個playstep就行了:
private void btnplay_click(object sender, routedeventargs e)
{
playstep();
預設我們加載完棋步清單後,也要定位棋步,是以也調用一下playstep:

void client_getmovesteplistcompleted(object sender, gameservice.getmovesteplistcompletedeventargs e)
playstep();//加完後馬上調用播放棋步,預設0秒,是以刷一下就播放完了

于是,所有的重點隻剩下怎麼實作這個playstep了。
我們每一步棋步都需要間隔n秒走一步,一開始我竟然用線程的sleep來操作,結果是,程式卡住了,直接播放完了才能動,那個汗-_-!
于是,n久之後,非線程阻塞的timer出來了,讓它定時每n秒走一步就行了:
全局定義一下timer先,順路加上移動的索引:

public partial class chessmanual : usercontrol
system.windows.threading.dispatchertimer timer;//定義timer
int movestepindex = 0;//移動到第幾步了
//...下面省略n行...

接着初始化timer及事件:

public partial class chessmanual : usercontrol
public chessmanual()
//...省略n行...
timer = new system.windows.threading.dispatchertimer();
timer.tick += new eventhandler(timer_tick);
void timer_tick(object sender, eventargs e)
//待實作
}

我們這裡沒有初始化timer的間隔時間,是因為把間隔時間設定放到playstep函數裡了,說到playstep,我們可以實作它了:

if (app.steplist.count > 0)
//播放前複位棋子
app.chess.reset();
timer.interval = timespan.fromseconds(slplayerinternal.value);
timer.start();

我們隻用了小小幾行代碼,其實就是設定一下時間,然後讓timer它start起來就完事了,于是重心又一步轉移到timer的tick事件裡了:

void timer_tick(object sender, eventargs e)
gameservice.movestep step = app.steplist[movestepindex];//擷取棋步
lbchessmanual.selectedindex = movestepindex;//定位棋步索引
lbchessmanual.updatelayout();//需要更新下布局
lbchessmanual.scrollintoview(lbchessmanual.selecteditem);//滾動到先中的項
automove(step);//移動棋步
movestepindex++;//索引加1
if (movestepindex == app.steplist.count)//判斷棋步結束沒有
movestepindex = 0;//重置索引
timer.stop();//停止timer

這裡每一步都有注釋,相信不會看不懂的了。ok,至此,我們是可以f5看效果了:
1:目前正在下棋,下到一半中:
2:觀衆進來了,擷取完棋步,并播放了一次,定位到最後一步:
3:設定為2秒,點“回放”,自動播放了第一步:
4:回放走到第二步:
5:回放走到最後一步了:
ok,到此,我們的棋譜回放功能基本完成了,隻是有一些細節,我們是需要另外處理了:
1:下棋者在下棋過程,要不要開放“回放”功能,如果開放,需要注意什麼?
2:觀衆在回放過程中,突然又傳來一個棋步,需要注意什麼?
這兩個小細節,下節處理,本系列到這裡,所有基礎區的功能都基本完成了差不多了,那本系列是不是也接近尾聲了?
版權聲明:本文原創發表于部落格園,作者為路過秋天,原文連結:
http://www.cnblogs.com/cyq1162/archive/2010/08/09/1795873.html
<a href="http://files.cnblogs.com/cyq1162/chessnewinstance_part8.rar"></a>