這是“使用 C# 開發智能手機軟體:推箱子”
系列文章的第二十二篇。在這篇文章中,介紹 Window/MainForm.Replay.cs 來源程式檔案。這個來源程式檔案是 MainForm
類的一部分,該類繼承自 System.Windows.Forms.Form 類,表示推箱子的主表單。而本篇文章講述的是推箱子“回放”過程,如所示:
我們先看看 MainForm.Designer.cs 來源程式檔案(該檔案是由 Visual Studio 2005 IDE 自動產生的)中和“回放”相關的部分:
namespace Skyiv.Ben.PushBox.Window
{
partial class MainForm
{
// 注意:省略了很多代碼,僅保留和 miReplayOrLand 相關的部分。
private void InitializeComponent()
{
this.miReplayOrLand = new System.Windows.Forms.MenuItem();
this.mnuMain.MenuItems.Add(this.miReplayOrLand);
this.miReplayOrLand.Text = "回放";
this.miReplayOrLand.Click += new System.EventHandler(this.miReplayOrLand_Click);
}
private System.Windows.Forms.MenuItem miReplayOrLand;
}
}
上述代碼片斷展示了在推箱子遊戲的主表單上點擊“回放”時發生的事件:
this.miReplayOrLand.Click += new System.EventHandler(this.miReplayOrLand_Click);
也就是說如果以前使用“錄影”功能儲存過通關步驟的話,可以通過“回放”功能將該通關步驟重新播放出來。這是由下面的 MainForm.Replay.cs 來源程式代碼實現的:
1 using System;
2 using System.Drawing;
3 using System.Threading;
4 using Skyiv.Ben.PushBox.Common;
5
6 namespace Skyiv.Ben.PushBox.Window
7 {
8 partial class MainForm
9 {
10 Rectangle workerThreadInvalidRectangle;
11 bool workerThreadIsStop;
12
13 private void miReplayOrLand_Click(object sender, EventArgs e)
14 {
15 if (env.IsDesign)
16 {
17 env.Pen = Block.Land;
18 UpdateStatus();
19 }
20 else
21 {
22 env.IsReplay = true;
23 workerThreadIsStop = false;
24 UpdateStatus();
25 ThreadPool.QueueUserWorkItem(WorkerThreadReplay, env.GetSteps());
26 }
27 }
28
29 /// <summary>
30 /// 回放通關步驟,使用後台背景工作執行緒
31 /// </summary>
32 /// <param name="steps">通關步驟</param>
33 private void WorkerThreadReplay(object steps)
34 {
35 try
36 {
37 foreach (char c in (string)steps)
38 {
39 if (workerThreadIsStop) break;
40 if (env.ReplayDelay > 0) Thread.Sleep(env.ReplayDelay);
41 Step step = c;
42 if (!env.StepIt(step.Direct, step.IsStop, out workerThreadInvalidRectangle)) break;
43 Invoke(new EventHandler(WorkerThreadUpdateStatus));
44 }
45 }
46 finally
47 {
48 env.IsReplay = false;
49 Invoke(new EventHandler(WorkerThreadUpdateStatus));
50 }
51 }
52
53 /// <summary>
54 /// 更新主表單狀態
55 /// </summary>
56 /// <param name="sender">事件來源</param>
57 /// <param name="e">不包含任何事件數目據的事件參數</param>
58 void WorkerThreadUpdateStatus(object sender, EventArgs e)
59 {
60 Invalidate(workerThreadInvalidRectangle);
61 UpdateStatus();
62 }
63 }
64 }
65
66
幾點說明:
- 因為“回放”是一個長時間的過程,為了防止使用者介面失去響應,所以使用了多線程技術,在後台背景工作執行緒進行回放。也說是將回放通關步驟的 WorkerThreadReplay 方法加入到線程池中去:ThreadPool.QueueUserWorkItem(WorkerThreadReplay, env.GetSteps());
- workerThreadInvalidRectangle 欄位(Rectangle 類型)表明“回放”時主表單需要更新的矩形地區。該值是由 Env 類的 StepIt 方法設定。
- workerThreadIsStop 欄位(bool 類型)指示是否停止回放,初始值為 false。當使用者按“停止”按鈕時,該欄位被設定為 true,從而停止回放。
- miReplayOrLand_Click 方法響應使用者的“回放”請求,啟動後台“回放”線程。
- WorkerThreadReplay 方法在後台線程執行實際的“回放”動作,她實際上是對已經儲存的通關步驟的每一步調用 Env 類的 StepIt 方法來進行“回放”,並通過 Invoke 調用 WorkerThreadUpdateStatus 方法更新主表單狀態。
- WorkerThreadUpdateStatus 方法負責更新主表單狀態。
- 如果在智能手機上進行“回放”,就是不使用後台線程,使用者介面也不會失去響應,不知是什麼原因。
上一篇:使用 C# 開發智能手機軟體:推箱子(二十一)
下一篇:使用 C# 開發智能手機軟體:推箱子(二十三)
返回目錄