Net Framework智能版開發移動遊戲

來源:互聯網
上載者:User

         Microsoft .NET Compact Framework 是完整的Microsoft.NET Framework的一個子集。 Microsoft? .NET Compact Framework適用於資源受到限制的裝置,這種裝置一般只有很小的顯示螢幕和記憶體,通過這種方法,開發人員將使用很多完整性大幅降低的函數取得增強效能。

  .NET Compact Framework的優點,包括用於Pocket PC及其他Windows CE.NET裝置的簡單二進位配置,提高了開發人員的生產效率並且縮短了開發時間。

  在本文中,我將討論編寫面向小型裝置的遊戲的關鍵技術,並且說明怎樣使用.NET Compact Framework來很容易的處理它們。我將討論一些進階效能調節技術,協助你把遊戲推到極致。 總而言之,你將看到使用.NET Compact Framework開發和最佳化你的遊戲是多麼容易的一件事。

  本文假定讀者已經熟悉.NET Compact Framework並對遊戲開發有一定的瞭解。

  全螢幕遊戲表單

  通常在遊戲應用程式中,肯定特別想要使用裝置的全螢幕顯示。一個佔滿整個螢幕地區的表單被稱為全螢幕表單(也稱為遊戲表單)。換句話說,一個全螢幕表單佔據整個案頭(或者客戶區)和非客戶區比如頂部的標題/導航條,邊框和底部的菜單條。

  一個應用程式通過設定它的WindowState為Maximized來建立一個全螢幕表單。

  form.WindowState = FormWindowState.Maximized;

  如果表單上帶有菜單條(或者在Pocket PC的工具列)那麼它不算是全螢幕。

  在Pocket PC的.NET Compact Framework 1.0版本中,為了建立一個全螢幕應用程式,WindowState屬性必須在表單的OnLoad中設定。

  下面的圖1和圖2說明了Pocket PC上的全螢幕和非全螢幕表單的區別。

 

  圖1非全螢幕表單

 

  圖2全螢幕表單

  全螢幕表單的主要的含意就是沒有標題列/導航條或者菜單條。應用程式必須考慮到這些因素,並且在必要時要盡量不使用這些功能。

  如果你只是想要你的表單佔滿可用的案頭地區(而不是全螢幕),那麼你不必做任何事。預設時,.NET Compact Framework將自動地改變表單大小佔滿Pocket PC的螢幕。

  事實上,最好你別明確地設定表單的ClientSize,因為如果你這麼做的話,在各種Windows CE.NET裝置之間可能會防礙你的應用程式的相互適應性。 比如,如果你明確地設定你的應用程式顯示尺寸來匹配某種裝置的表單,那麼它很可能在不同的裝置上就不能很好的顯示。 建議使用表單的預設大小。

  覆蓋OnPaint和OnPaintBackground

  一個典型的遊戲應用程式將自訂描畫表單的內容。 應用程式通過覆蓋一個控制項的OnPaint()事件然後自訂處理視窗的描畫。

 

  每當一個控制項開始描畫時,它的背景首先自動地重新整理。 舉例來說,在OnPaint()描畫控制項內容的過程中,它的背景先使用this.Backcolor中指定的顏色描畫。 但是上面提到的這種應用程式自己描畫表單的情況可能並不太理想;在應用程式完成前景著色以前,背景的自動著色可能導致背景的瞬間閃爍。

  為了防止這種預設的情況發生,每當一個應用程式覆蓋OnPaint()方法的時候,強烈建議也覆蓋OnPaintBackground ()方法重畫背景本身。 象在下面的常式中一樣,應用程式可以處理OnPaint()中的所有的描畫,而空著OnPaintBackground()。

 

  用於著色的Off Screen位元影像技術

  你可以通過擷取用於螢幕的繪圖物件,在屏內描畫,通過調用一個控制項的this.CreateGraphics()直接畫到上面。 要牢記,當屏內繪圖物件不再需要的時候,一定要把它去除。不這樣做可能會使顯示裝置的資源緊張。

  如前面章節所述,你可以通過PaintEventArgs.Graphics訪問OnPaint()和OnPaintBackground()方法中的螢幕繪圖物件。一旦這些描畫方法被執行,這些繪圖物件就會被自動去除。

  遊戲程式在螢幕上直接描畫往往並不理想。因為當你在螢幕上描畫許多個物件的時候,你將看到螢幕閃動。為了避免螢幕閃動,遊戲開發人員通常使用屏外描畫技術。

  主要的思想是建立一個屏外位元影像,獲得它的繪圖物件,執行關於它的所有的描畫操作(在記憶體中)並且複製產生的位元影像到螢幕上。

 

  在這個例子裡,我將建立一個正好是遊戲表單客戶區大小的屏外位元影像。 基於需要,它的尺寸是可以改變的。 然而,維持屏外和屏內圖形邊界大小關係為1:1將非常有益,尤其是當需要翻譯屏內和屏外子圖形的座標時。

 

 

  這個技術避免了螢幕的閃動,並且當記憶體中所有的屏外描畫操作都在進行的時候也非常快。

  子圖形

  像位元影像這樣的圖象都是以矩形形式出現,但是在現實世界中大部分的子圖形是不規則形狀的(並不是矩形的)。 所以我們需要找到辦法讓我們從一個矩形圖象中提取出一個不規則子圖形圖象。

  Color Key透明度

  遊戲開發人員使用的一種流行的技術就是Color Key技術,當渲染時指定的顏色就被從位元影像中抽去。 這種技術也稱為色度鍵掩蓋,顏色剔除和透明混合。

 

  圖3子圖形.

 

  圖4使用Color Key透明度

 

  圖5未使用Color Key透明度

  在子圖形位元影像中(圖3),非對象地區充滿著絳紅色,可以被用做color key。 使用或者不使用這種技術的混和效果分別地4和圖5所示。

  透明混合的第一步是建立在渲染時要被掩蓋的color key(色度鍵)。我們需要指定一個精確的色度索引值,而不是指定一個範圍。

 

  如果你不想使用Color類中提供的標準顏色組,你可以按照如下方法來指定紅色、綠色和藍色(RGB)值構造你自己的顏色。

 

  另一種我經常用來指定色度值的技術就是直接使用像素值。 這就避開了處理RGB值的必要。 而且,色度值不是寫入程式碼,可以獨立的在位元影像上被改變。

 

 

imgattr.setcolorkey(bmpsprite.getpixel(0,0), bmpsprite.getpixel(0,0));

  現在,讓我們看看如何使用我們建立的色度值透明地描畫子圖形。

 

  在上面的程式碼片段裡,目標矩形被指定為new Rectangle(x,y,bmpSprite.Width,bmpSprite.Height),這裡x和y是子圖形的所要置放位置的座標。

  通常,在描畫的時候,有可能需要伸展或者縮小子圖形。 你可以通過調節目標矩形的寬度和高度達到這個目的。 同樣,你還可以調節源矩陣來僅僅描畫子圖形的一部分,即使這並不一定非常有用。

  當設定用於你的子圖形的位元影像時,建議考慮一下你的目標裝置的色彩解析度。 例如,一個24位色位元影像在一個12色彩解析度的裝置上可能不能渲染;這兩種在顏色梯度上的區別可能依賴於選擇使用的顏色。 而且當選擇要被掩蓋的ColorKey時,要保證這個顏色值要處於目標顯示支援的色彩範圍之內。 記住,它支援精確的ColorKey匹配。

  Color Key透明度是.NET Compact Framework支援的唯一的混合技術。

  把圖象作為嵌入資源

  你可以把一個圖片資源嵌入到你的組件中去,添加圖象到工程中,並且設定它的Build Action屬性為" Embedded Resource "。 請參看線上說明主題" Embedding Resource Files in Applications "擷取更多的資訊。

  然後我們就可以象下面這樣使用資源中的內嵌位元影像了。

 

  Bitmap類支援BMP、JPG、GIF和PNG映像格式。

  調整你的著色方法

  遊戲中的著色程式必須嚴格的最佳化設計以便取得最好的效能。 強制的給螢幕著色將會擦除並重畫所有的屏外的子圖形,然後使用屏外圖象刷屏。 顯然,這樣做效率很低,因為我們沒有必要每次都重畫整個螢幕。 在這裡,我們的畫面播放速率取決於Compact Framework能夠重新整理整個螢幕的速率。

  一種更好的方法是計算我們的遊戲中的子圖片的變化的地區,然後只重新整理螢幕中這些變化的部分。 子圖片可能因為各種原因變化,比如移動、在圖象/顏色上變化或者與其他的子圖片衝突等。在本章,我們將討論各種用來有效計運算元圖形變化地區的技術。

  變動地區計算

  讓我們研究一個移動的子圖形,計算變動地區的一個簡單的方法就是取得新圖片和老圖片界線的並集。

 

 

refreshscreen(rectangle.union(sprite.previousbounds, sprite.bounds));

  這裡的RefreshScreen()是一個重新整理屏內指定矩形地區的方法。

 

  圖6.變化地區為新老邊界並集

 

  圖7.大的變動量產生大的變化地區

  注意 如果新舊座標之間的變化量很大,或者子圖形的尺寸很大,那麼這種技術可能會產生一個不必要的大的變化地區,參看圖7。

  在這種情況下,用單位矩形組合起來表示變動地區,計運算元圖形的變動地區非常有效。

  首先讓我們看看新舊邊界是否重疊。 如果沒有重疊的話,我們可以分別把新舊兩個的邊界當成是兩個獨立的矩形來計算。 所以,如7所示方案,把新邊界和舊邊界作為兩個不同的變化地區分別處理。

 

 

  如8所示,上面的技術也可以用到不必在乎重畫重疊區兩次的情況下。

 

  圖8變化地區被分為新舊兩個邊界

  現在,讓我們看看如何把新舊邊界的重疊部分分成單位矩形用來計算變動地區,這樣就不會把變動地區重複兩次了,意思是所有的單位矩形都是互不相交的。

  首先,把新的邊界作為整體單位。注意,這包括新舊邊界的重疊部分。

  變化單位地區1:描述當前邊界的變化矩形

 

 

refreshscreen(sprite.bounds);

 

  圖9.變動地區被分解為幾個單位。

  現在,把舊的邊界中的不重疊部分分解成為兩個獨立的單位,見下面的代碼:

 

 

  變動地區單位3

 

  檢測衝突

  現在,讓我們看看一個子圖形和另一個子圖形衝突的情況。 你可能忽視了兩個子圖形之間的衝突,而只是使用我們前面討論的技術分別的去更新子圖形的變動部分。

  但是出於遊戲應答的目的,你經常需要去檢測子圖形的衝突。 舉例來說在一個射擊遊戲中,當一發子彈擊中靶子,你可能會想要出現爆炸等可視的反應。

  在本文中,我將不詳細地討論不同的可用的檢測衝突的技術。但是,我會突出介紹它們中的幾種。

  讓我們回想一下,大多數的子圖形都是不規則形狀的,但是描述它們的位元影像都是矩形的。很難把一個子圖形的邊界顯示為自由的地區,所以我們求助於通過封裝矩形來顯示它。

  當遊戲者觀察螢幕上的子圖形的時候,他實際上只是注意看子繪圖區域而對非子繪圖區域並不十分注意。 因此,子圖形之間的任何衝突檢測必須只在它們各自的子繪圖區域內發生,而不應該包括非子繪圖區域。

  對於較小的子圖形,當我們計算衝突並在視覺上消除它的時候通常使用整個子圖形邊界。 因為如果對象很小並且移動迅速,肉眼是注意不到那些錯覺的。 這兩個子圖形邊界的簡單矩形相交就足夠了。

 

 

rectangle.intersect(sprite1.bounds, sprite2.bounds);

  如果子圖形是圓形的,那麼我們可以計算圓心之間的距離然後減去它們的半徑;如果結果大於零那麼我們就會探測到一個衝突。

 

  快速邊界插入技術應當首先應用到檢測子圖形的邊界衝突上。如果發生衝突,那麼我們可以使用一個更精確的方法,比如衝突位元影像掩蓋技術來識別重疊像素。

  如果我們不在乎像素水平的間隔度,那麼我們可以使用前面在變動地區計算部分提到的計算衝突地區的方法。不同於處理一個子圖形的新舊邊界,我們現在將處理兩個衝突子圖形的邊界。

  具體的衝突檢測技術應該由具體的情況決定。選擇某種特定的技術取決於各種各樣的因素,比如子圖形的大小與形狀,遊戲的特性等等。 在單個遊戲中,使用這些技術並不罕見。

  子圖形速度

  畫面播放速率經常會被誤解為子圖形移動速度。我們不能只依靠畫面播放速率,還要調節子圖形每幀移動的距離來取得所要的淨速度。

  讓我們研究一下下面這個例子,這個例子裡我們想要子圖形在1秒時間內垂直移動100像素單位。現在我們可以固定畫面播放速率為10 fps,然後每幀移動子圖形10像素單位達到那個淨速度;或者我們可以增加畫面播放速率為20fps,並把子圖形每幀垂直移動量降為5像素。

  這兩種獲得相同淨速度的方法,區別是在前面的一種情況下,子圖形的移動可能在視覺上有一些跳動,因為它在比後者更少的重新整理迴圈中移動的距離更大。但是在後面這種情況下,我們的遊戲是20fps,所以在決定使用哪一種方法之前,我們需要絕對確保硬體、系統和.NET CF的效能。

  遊戲進展技術

  一個遊戲應該有情節發展,這時隨著使用者互動,螢幕內容會變化。

  遊戲迴圈

  在遊戲中,我們初始化、維持並取消一個迴圈,遊戲迴圈在必要時能給我們渲染螢幕內容的機會。一般情況下,遊戲開始的時候,初始化遊戲迴圈, 一般地情況下,當遊戲啟動的時候遊戲迴圈初始化,然後通過休眠和根據需要迴圈返回來維持迴圈,直到遊戲終止。

  這個技術提供動作遊戲最大的靈活性和快速反應性。我們現在來實現一個用於我們足球遊戲的遊戲迴圈。假定這個遊戲有很多層級。

 

 

  注意,每次我們在迴圈返回之前,在迴圈中調用Application.DoEvents(),我們這麼做的目的是與系統保持主動聯絡,並且處理事件隊列中等待處理的訊息。這是很必要的,因為當我們的應用程式處於一個迴圈中的時候,我們基本上失去了處理任何來自系統的訊息的能力;除非我們明確調用 Application.DoEvents(),否則我們的應用程式不會響應系統事件,並且可能產生不希望有的副作用。

  遊戲迴圈中要考慮的另一個問題是渲染速率。大部分的遊戲動畫需要至少8 - 10幀每秒。相比較之下,典型的動畫電影渲染速度是14 - 30幀每秒。

  一個簡單的畫面播放速率調節技術就是確定需要的每秒幀以及迴圈中休眠(1000/fps)毫秒。但是我們也需要計算處理所使用的時間,否則我們的渲染速率將要比預期的要低。處理時間可能會相當長,尤其在較慢的硬體上,因為它要進行高成本的操作,比如處理使用者輸入,渲染遊戲等等。

 

 

  定時回話

  另一種技術是建立一個周期性地回話的系統計時器。就象遊戲迴圈一樣,定時器一般在遊戲開始和定時訊號事件(每隔一定時間發生)被處理的時候執行個體化,直到遊戲結束。

  我們選擇了遊戲迴圈這個簡單的比喻,是因為我們讓系統為我們處理定時器。我們只要處理定時器回話,然後通過每次重畫一幀的方法讓遊戲進展下去。而且,我們不必擔心會消耗完事件隊列。

  但是我們必須小心選擇定時器的定時訊號間隔,因為它決定了我們遊戲的畫面播放速率。

  在遊戲迴圈技術中,兩個定時訊號之間的時間間隔是完全被我們的控制的,而且前面我們也可以看到,這很容易考慮處理時間。另一方面,定時回話意味著時間間隔不能改變。 所以我們要麼把定時間隔設定的足夠大,以便能夠完全處理每個回話;要麼調節定時訊號的處理過程,通過明確地掌握處理定時訊號和根據維持節奏需要而跳過定時訊號的時間。

  使用定時器回話的一個主要缺點就是我們要依賴作業系統定時器的解析度。最小定時訊號間隔可能取決於定時器最大可能的解析度。 在Pocket PC上這可能是一個限制因素,因為在Pocket PC上,時間解析度很低,就是說用在本方法中的fps也很低。而且,作業系統定時事件的優先權相當低,意味著遊戲的響應度也很低。

  如果不管這些限制的話,這個技術最適用於慢進度的遊戲,在這些遊戲裡畫面播放速率並不是最重要的。比如說,螢幕保護裝置程式。

 

  注意:當遊戲結束的時候,你必須去除定時器。

  注意沒有必要調用Application.DoEvents(),因為我們既不使用迴圈,也不截取任何系統事件,事實上,定時器回話也正是另一種系統事件。而且,注意大部分遊戲工作程式被壓入OnTimerTick()事件處理常式。

  無效更新

  讓遊戲進展下去的方法就是在一個已經設定的基礎上渲染它。每當遊戲程式探測到螢幕需要被重新整理,我們就可以請求系統使螢幕的某些相應的地區失效,然後重新整理這部分。

  在所有適用於遊戲進展由使用者互動控制的遊戲的技術中,這種技術是最簡單的。可用於那些沒有恒定定時訊號和渲染(見前面遊戲迴圈、定時回話)的遊戲,這些遊戲只能靠使用者操作才能進展,比如猜謎遊戲。

  我們可以通過調用this.Invalidate()使我們的遊戲表單整個客戶區失效,或者通過調用this.Invalidate( dirtyRect)使客戶區的一部分失效。

  僅僅調用this.Invalidate()不能保證及時描畫螢幕。我們必須通過調用this.Update(),來保證在進行下一步之前重新整理螢幕。非同步地調用Invalidate()和Update()方法,在某些情況下有助於取得更高的效能。但是不使用正確的幀同步技術,它可能導致在螢幕上出現偽跡,並且使幀丟失。

  如果我們能夠每次重新整理整個螢幕,那麼我們只要調用this.Refresh(),就能保證Invalidate()和Update()依次調用。

  當我們可以自己描畫表單的時候,我們可以在螢幕的任何部分需要被重新整理的時候調用this.Refresh(),然後有選擇性的重新整理OnPaint()和OnPaintBackground()內的螢幕。

  最佳化啟動時間

  在遊戲中,遊戲開發人員通常在遊戲啟動的時候把所有的遊戲參數都初始化,以避免在遊戲啟動並執行時候產生不必要的延遲。這種方法不好之處在於延遲都被轉入遊戲啟動時間中,尤其是如果使用者在開始玩遊戲之前,遊戲載入時間過長的話可能讓人感覺非常不愉快。

  在這種情況下,最好的辦法是我們能夠顯示一個遊戲相關資訊的宣傳頁面,然後在後台進行啟動工作比如載入資源,初始化遊戲參數等等。

  我們可以要麼使用一個單獨的全螢幕表單作為宣傳頁面,要麼僅使用主遊戲表單本身配以基本的遊戲資訊。

 

 

  重要的是不要在啟動介紹頁面裡提供任何函數功能,最好只是把它用做一個介紹/資訊頁。啟動時顯示宣傳介紹頁面並不是必須的。

  遊戲按鍵

  方向鍵

  在Pocket PC中,方向鍵(即上下左右鍵)在遊戲中扮演了一個非常重要的角色。我們可以把這些鍵的KeyDown、KeyPress和KeyUp事件分別設定為我們遊戲表單中的相關的事件方法。

  通常,我們想處理這些方向鍵的KeyDown事件,提供遊戲級功能。

 

 

  Pocket PC輸入筆

  Pocket PC上的輸入筆的功能就好象台式機的滑鼠。我們可以把MouseDown、MouseMove和MouseUp事件分別設定為我們遊戲表單中的相關的事件方法。

 

 

  在Pocket PC上,.NET Compact Framework V1.0不支援滑鼠右鍵和hardware鍵。

  其它提示

  可能的情況下,與其使用一幅位元影像,不如自己畫圖。這將減少佔用記憶體大小,還可以提高效能。比如說,在一個太空射擊遊戲中,與其使用位元影像作為背景,不如自己使用黑色的矩形填充背景然後畫上星星。

  嘗試把類似的位元影像組合成一張大的位元影像,以後可以根據需要使用相應座標選取對應的單位位元影像。使用大的位元影像代替好幾張小圖將所有所在資源的大小。

  試用除了BMP以外的映像格式(例如JPEG),這樣可以充分利用其良好的映像壓縮率。

  儘可能多的靜態初始化你的遊戲程式,以免在運行期間進行大量的計算。 例如,在猜謎遊戲中,你應該靜態儲存答案,而不要在遊戲運行時再去使用代價高昂的動態演算法。

  結論

  當我們編寫用於Pocket PC這樣的小型裝置的遊戲時,我們要牢牢的記住,顯示螢幕非常小,並且硬體比台式機功能要差很多。

  所以我們要最大限度的最佳化用於這些小型裝置上的遊戲。當設計遊戲時,要認真的考慮目標硬體、作業系統和.NET Compact Framework的效能。

  一個遊戲還要以它的描畫程式取勝。高效率的描畫技術決定了遊戲的反應靈敏度,特別是象Pocket PC這樣的小型裝置。所以要使用我們前面提到的描畫調節技術(比如變動地區計算技術)來節省每幀描畫所用時間。

  畫面播放速率是另一個要牢牢記住的重要因素,要根據目標裝置的效能靈活選擇。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.