發布日期: 1/24/2005 | 更新日期: 1/24/2005
John Kennedy
Microsoft Corporation
下載 Road07102002-code.exe。
本頁內容
與生活中的許多事情一樣,有時要學習某些知識的唯一方式就是親自去嘗試。當然,也有一些很顯著的例外。我可不建議通過這種方式去學習外科手術(哈哈),但是對於學習智慧型裝置擴充 (SDE) 和用 C# 編寫適用於 Pocket PC 的程式,這絕對是一個很好的方式。
誠然,我們會越來越多地接觸到 Microsoft .NET Compact Framework,不管是在本專欄還是在實際的開發環節中,這一點不容置疑。更加不容置疑的是,C# 是 .NET Compact Framework 用得最多的一種語言。用 C# 開發了一些程式之後,我對它的易用性、靈活性和優雅得體有著越來越深的印象。當然,當前發行的 Beta 版在某些地方還存在著所謂的操作“欠佳”的情況,但這不久就會得到解決。我堅信,一旦您繼續瞭解一些新概念,您就會真正地喜歡使用 C# 和 .NET Compact Framework。
紙牌遊戲
我們以前在本專欄中討論過 XML Web 服務,但有些讀者希望我能夠使用智慧型裝置擴充來建立其他一些串連性不大的編程項目。並不是每個軟體都需要串連到 Internet,因此這個新平台中有些很強大的功能往往會被忽視。
所以在本月的專欄中,我們將演練一下如何開發一個適用於 Pocket PC 的更加傳統的應用程式 — 實際上是一個遊戲,它採用 C# 編寫並使用 .NET Compact Framework。使用 C# 進行開發與使用 eMbedded Visual C++ 進行開發之間存在著一些很明顯的差異,對於在編寫這個程式時所碰到的一些很明顯的問題,我希望拿出來與大家分享一下。
所要討論的遊戲非常簡單。一箇舊版本的紙牌匹配遊戲 — Pelmanism。然而,要闡明一些重要的區別和方法還是很複雜的,所以即使您認為它很容易,也不妨試試。如果您要載入並試玩,可以下載原始碼。
這個遊戲的設計十分簡單,正如您在以下螢幕中所看到的。(這些照片是我的團隊(即 Visual C++ 小組)的所有成員。您可能會認為,現在當我找他們要求拍照時,他們會更加謹慎了。當然,我更願意使用 Drew Barrymore 的照片,但有著嚴格的流程……)。螢幕上有十六張紙牌,玩家通過點擊指示筆來“翻轉它們”。如果紙牌相匹配,它們就會從螢幕中消失。我將留給讀者一個練習 — 添加代碼以便統計翻轉次數、儲存成績等等。是的,這表明我在偷懶。不過要知道,我也忙乎了一天呢!第一個人在問我花多少時間在 Xbox 上玩 Halo 時懷著一種很鄙夷的目光。
圖 1. 您知道,我被 Xbox 團隊逼著討論這張圖的許可權。當然,實際上這是個謊言。
返回頁首
圖形和 SDE
C# 程式與 eMbedded Visual C++ 的工作方式有著很大的不同,它從 Visual Basic 繼承了表單 的概念。從技術角度看,改變並不大,但我希望能夠引起您的注意。您可能也知道,表單其實就是一個頁面,您可以在其中添加控制項、顯示文本、從中接收螢幕點擊訊息等等。當我們在 Visual Studio .NET 中建立一個預設項目時,系統會自動為我們提供一個預設表單。
圖 2. 一個空白表單,準備讓我們展現自己的想象力和才幹。
您可以發現,表單的左邊是一組控制項,我們可以將它們拖放到表單中,也就是拖放到我們的程式中。與使用 eMbedded Visual C++ 工具箱相比,您會發現,編輯器中控制項的可視化外觀與因此而建立的原始碼之間的聯絡更加緊密。試試一些控制項並觀察代碼。Visual Studio 保持跟蹤的方式給人的印象很深。
一句話警告原始碼中有些地方不要手動變更。由於某種原因我忽視了這個告誡,當我在設計器中調整表單時就丟失了代碼,所以要謹記。
可以在表單中添加的一個控制項是 PictureBox,這是一個顯示映像的控制項。我打算對遊戲所顯示的每張紙牌都使用一個 PictureBox。它與最初採用 C++ 編寫這個程式的方式有所不同。如果用 C++ 建立,我就需要建立視窗(現在我們稱之為表單)並獲得 HDC(顯示上下文控制代碼),然後使用 BitBlt 將一大堆圖形資料變為實際的圖形。這次,我打算使用十六個 PictureBox 控制項,並使用它們的方法來定義它們顯示什麼映像。您將會看到,這種方式是相當得體的。
當然,知道我們要顯示十六張紙牌,您可能會試著將十六個 PictureBox 拖到表單中,然後調整它們的大小並將它們排列整齊。這是個好主意,但通過編程方式處理每個控制項很快就會變成一項很瑣碎的事情。更好的做法是建立一組 PictureBox,然後使用索引對它們進行處理,一會兒您將看到,我就是這樣做的。所以,儘管設計器十分有用,但我們並不一定要使用它來添加 PictureBox 控制項。
讓我們來簡單地看一些原始碼。C# 程式在大部分地方很像 C++ 程式。比如函數、if() 語句、do/while 和大量圓括弧。然而,也有一些細微(而非很顯著)的區別。
舉一些基本的例子,比如很好而又老舊的 #define 語句。我如何向您說明呢?它已經過時了。當然,它也沒有完全過時,只是做了點更改。在 C# 程式中,#define 只能用於建立標識符。您不能使用它來建立常量,比如 #define X_WIDTH 100。
瞭解這一點之後,我們再看一些數組聲明。需要二維整數數組嗎?不要再認為是 int grid[4][4];,而應該是 int[,] grid = new int[4,4] ; 。
瞭解此資訊之後,您應該能夠明白遊戲開頭的這段代碼有何用處:
圖 3. 通過編程方式建立控制項很容易,而且它們在編輯器中顯示了所有方法以提示您下一步做什麼。
這段代碼聲明了一些數組:一個用於儲存玩紙牌時用到的 9 張不同的映像,一個用於儲存可能存有紙牌的 16 個位置中的紙牌類型,一個用於儲存 PictureBox 控制項本身。
然後,我們按相同的方式處理所有這些 PictureBox 對象,建立它們、將它們添加到表單中,並調整它們的大小和位置。請注意應用於每個對象的方法和屬性(例如 Location)如何通過句點與對象分開。Visual Studio 整合式開發環境 (IDE) 非常智能,一旦您鍵入句點,它就會彈出一個列表,其中包含您可以對這個對象執行的所有正確操作。這隻是一個方面,說明了 C# 讓人感到編寫代碼是一件很愉快的事。
如果您也和我一樣,您就會喜歡在程式中添加 MessageBox 調用,以便隨時瞭解發生的事情。使用智慧型裝置擴充也可以擁有這樣的能力:只需使用以下文法:
Messagebox.Show("Hello");
當然還有更多的選項,有關完整的列表,請參閱線上說明。
考慮映像
想知道當我們玩紙牌時如何載入以顯示一些映像嗎?我也很想知道,因為 .NET Compact Framework 缺少 .NET Framework 的一些功能,連我首選的方法都沒有。不過它仍然十分簡單,如果您在通讀樣本原始碼時稍加註意,就會發現它與 Image 對象有點關係。
下面是另一段代碼。這是一個函數,通過調用它,可以從磁碟(其實是記憶體,只要您明白我的意思)載入映像,並將前面聲明的映像數組中的元素分配給它。
圖 4. 從記憶體中載入映像非常容易。
.bmp 檔案是我在一個塗鴉程式中建立的映像集合,並預先對它進行縮放以適合 PictureBox 控制項的大小。我習慣於使用 .bmp 格式,不過該控制項也支援其他常見的檔案格式。
我相信您已經很熟悉 try/catch 異常處理了,它是一種可選方式,不過建議您養成使用它的習慣。如果映像載入失敗,就會執行 catch() { } 中的代碼。這明顯能使代碼更加健壯可靠,不過如果能多做些事情(而不只是警告使用者程式將要終止),那就更有用了。
如果您使用小巧的 Pocket PC 模擬器(它附帶智慧型裝置擴充)來試運行這個樣本程式,您可能不知道如何將 .bmp 影像檔從開發用的電腦移到類比的 Pocket PC 中。讓我告訴你吧,因為這個過程與早期的 Pocket PC 開發工具相比有了一些更改 — 您一猜就知道我對它有很深的印象。
將檔案複製到模擬器
1. |
啟動模擬器(如果尚未啟動)。 |
2. |
從 Start 菜單中,選擇 Settings,然後選擇 System 選項卡。 |
3. |
單擊 About,然後單擊 DeviceID 標籤。 |
4. |
將裝置名稱從 Pocket_PC 改成其他的名稱。 圖 5. 更改裝置 ID,否則當模擬器與案頭電腦通訊時會報錯。 |
5. |
現在啟動 Pocket PC 上的檔案瀏覽器程式。 |
6. |
點擊網際網路共用表徵圖。該表徵圖位於螢幕底部的最右邊。 |
7. |
輸入通過 LAN 訪問您的電腦時所需的詳細資料。 |
8. |
瀏覽至案頭電腦上的共用資料夾,然後選擇要複製的檔案。 |
9. |
點擊 Pocket PC 上的檔案並按住不放。 注 模擬器存在一個 bug,您可能需要按住滑鼠鍵 30 秒鐘才會看到紅點以及隨後的快顯功能表。 |
10. |
複製檔案,返回到 Pocket PC 自己的目錄下並粘貼。 圖 6. 瀏覽至案頭電腦上的共用資料夾,然後複製檔案並將其粘貼到您的(類比的)Pocket PC。 |
這就是所有的步驟。
鄭重宣布,這就是這個小程式的全部內容了。當然,我還添加了一些菜單,使用表單設計器,要多簡單就有多簡單。有一件事令我考慮了許久,那就是如何處理使用者的指示筆點擊操作。
我對 Visual C++ 程式的理論分析是這樣的:佔據整個螢幕並接受滑鼠按下的訊息,解出 X 和 Y 座標,然後算出使用者點擊的紙牌。在這種情況下,每張紙牌都是一個控制項,而每個控制項都會單獨地響應滑鼠按下的訊息。我無法包含那種具有全域性質的“點擊螢幕並獲得訊息”代碼。
然而,為每個控制項指定處理常式是很簡單的。這就是原始碼的第一個代碼塊中的行:
this.pictureBox[x,y].Click += new System.EventHandler(this.UserTapsScreen);
您可以看到,我對每個控制項都添加了相同的函數 (UserTapsScreen)。這明顯有個疑問,那就是“在該函數中,我如何知道訊息由哪個控制項發出?”以下就是實現這一點的原始碼:
private void UserTapsScreen(object sender, System.EventArgs e) { int cardx = -1; int cardy = -1; // Find the card that send the message for (int x=0; x<4; x++) for (int y=0; y<4; y++) if (sender.Equals(pictureBox[x,y])) { cardx = x; cardy = y; y=4;x=4; }...
請注意,這段代碼使用了傳遞給 UserTapsScreen 函數的 sender 參數的一個屬性,以及它的 Equals 方法。
返回頁首
聲音效果
一個遊戲要是沒有聲音效果那就毫無價值。這就是我們下個月要介紹的內容。同時,請下載原始碼並試玩一下。如果您有任何問題,請隨時給我寄送電子郵件。但是,如果您是專門發送垃圾郵件的公司,打算一天要給我發送十二次電子郵件來向我提供一些衣著、電子和色情資訊,那就另當別論了!
John Kennedy 白天是 Visual C++ 小組的技術作家/編程人員;而夜晚,他享受著 Pocket PC 開發人員的秘密生活。
Larry Roof 創立了 larryroof.com,這是一家專門從事移動項目諮詢和 eMbedded Visual Basic、智慧型裝置擴充和 SQL Server CE 方面培訓的公司。
轉到原英文頁面