天天看點

Silverlight C# 遊戲開發:遊戲循環體的五種設計方式

我們在遊戲設計和開發中,尤其是引擎開發中,邏輯循環是一個重要組成部分,循環決定了遊戲的基礎邏輯和運作方式,在不同的開發環境和語言下,對于循環的釋義甚至相差甚遠,那麼我想和大家分享的是在Silverlight遊戲開發中,循環的設計方式和做法。

以下内容來自以往的遊戲開發經驗,可能在其他語言中的相關文章更加詳細,謹在這裡讨論有關在Silverlight遊戲開發中的應用。

特别提示:如果你的《資料結構》學的不好,不要看,你會吐飯,如果你的《資料結構》學的很棒,不要看,你會吐血。

在傳統的開發觀念中,無論任何開發環境,它都逃不出While,代碼一般是這樣:

while (true)  

{  

if (GameExit() == true)  

break;  

else  

GameLoop();  

}  

這個代碼方式隻是一個模型,可以将其了解成為一個不停在檢查狀态的狀态機。

那麼在Silverlight遊戲開發中,我們是否也可以這樣應用呢?道理上差不多,但是隻是實作了一個根(Root)部,這方面深藍色右手以及很多其他朋友都有了各種各樣的解決方案,有興趣的朋友可以找他們的文章,無論是用線程(Thread)、故事闆(Storyboard)、Rending、DispatcherTimer,都是一個好的循環體的開始。那麼我們是否到底在遊戲産品(或者叫成品更加貼切)的角度考慮更加深層的細節。

對于遊戲而言,尤其是網絡遊戲,我們将面臨着大量的互動,這些互動可能來自使用者,也可能來自自身的遊戲邏輯,其他的都好說,最現實的問題是,當一個遊戲的同螢幕呈現100個以上的角色的時候,我們的循環是否是以而“卡”住,在早期的時候,我陷入了一個誤區,呈現足夠多的角色就是最大的性能展現(能呈現600個角色不卡),現在看來卻是不然,因為單純的角色呈現,有幾百個不算什麼,當在一個整體遊戲的執行時候,它是否還能保持足夠的流暢,因為我們的戰鬥邏輯、界面邏輯、場景管理器無時不刻在消耗着系統資源,而此時的角色也絕非幾張圖檔那麼簡單,他們身上的裝備、部件、特效都将成為遊戲開發者的負擔。

在此種情況下,優化循環過程相當重要,作為團隊經驗積累,今次拿出來大家一起研讨,看看是否這麼回事,有什麼好的想法和建議歡迎一起交流一下:)

針對于在一個遊戲整體下的部分,用到循環最多應是動畫,對此,我總結了在Silverlight遊戲設計中能應用的五種循環方式,這些方式在傳統的遊戲開發中是非常常見的,隻不過沒有人願意拿出來分享,兩個原因:第一、太簡單,講出來怕笑話,第二、太神秘,我們要将其封裝起來,這樣才能忽悠人,下面的五種循環設計模式名字自己亂起的不好,還請見諒。

那麼好,我們設計一個場景:有一個OBJ内部有一個LogicLoop的方法,内部實作了最簡單的它會切換動畫幀,并且向一個方向走,走到底會從頭繼續走。而場景中有非常多的OBJ。

自身式循環比較容易了解,比如一個精靈控件,自己内部實作一個循環,來不停的檢測和執行邏輯,開發者都不需要去單獨做什麼,隻需要new出來它們自己就會執行邏輯了,這種方式非常便捷和友善,開發起來也相對容易,互相之間沒有任何關系,此時需要借助單例之類的設計模式來解決互相的結合問題。圖示如下:

<a target="_blank" href="http://blog.51cto.com/attachment/201111/131612363.jpg"></a>

很顯然,我們自身邏輯有一個最大的問題是獨自的性能占用,如果一個場景(不是同屏)有幾百個這樣的循環時,那麼遊戲各個線程就會吃掉大量的CPU,尤其是用Thread、Storyboard、DispatcherTimer的時候。

二、鍊條式循環

自身邏輯存在各自的循環消耗問題,那麼有沒有辦法将各自的循環邏輯統一到一個循環中呢,如果學過資料結構,我們可以透過連結清單的形式來做,基本的原理是将各個循環體放入到一個大循環中,然後從第一個開始執行循環邏輯,隻執行一次,然後下一個,到底以後回來繼續執行,模型如下:

<a target="_blank" href="http://blog.51cto.com/attachment/201111/131620138.jpg"></a>

這是一種常見的處理方法,能夠大大降低系統消耗,而且C#提供了疊代器等好用的周遊,使得我們結合面向對象的思路更友善。示意代碼如下:

public class obj  

public void OnLogic();  

List&lt;obj&gt; ObjList = new List&lt;obj&gt;();  

public void OnLoop()  

foreach (var item in ObjList)  

item.OnLogic();  

鍊條式循環最大的優點是将所有的獨立循環全部集中到一個大循環中,需要注意的有一個問題,那就是動态處理,因為遊戲當中的物體生成和銷毀是非常頻繁的,正在循環的時候發生了集合改變,那麼就危險了,我們的做法有兩種,分别是數組轉換和回收判斷,數組轉換非常容易,将集合拷貝到一個數組中,然後循環數組的各個元素;回收判斷是通過辨別将物體摘出到一個回收清單中,然後在安全的時機清理。

鍊條式循環的優點可以創造一個遊戲的RootHead,将所有的元素加入到這個RootHead當中,建立一個主循環然後周遊即可,當然了,你需要通過基類的方式來達到目的。

這是一種好的方式嗎?在某種情況是的,它能解決性能損耗,當然了,要是内部實作的邏輯過于複雜,有的時候可能還得借助一下另外線程。但是,在遊戲産品中,有一個更加直接的需求,那就是系統問題,也就是說,你的循環到底有多足夠大才能讓包容一切,比如場景管理中的場景物體,如果有邏輯循環就直接加入到這個大循環中嗎?在遊戲運作時,有一些循環在特定的時候是不需要使用的,或者不需要執行的,也為後續開發造成了障礙,是以,在我們的MMOROG引擎中,最多應用是下面的這種循環模式。

三、子樹式循環

子樹循環顧名思義,使用樹狀結構來處理循環邏輯,我們實際應用中還有可以分為:活動子樹式循環和固定子樹循環,為了友善講解,主要講固定子樹循環的模式。

我們知道在一個遊戲中,有很多的系統,比如場景系統、戰鬥系統、隊伍系統、公會系統、聊天系統……N多系統,它們自己内部是否有一個循環呢?如果從直覺角度上,上述系統可能不需要循環,但是事實不然,比如隊伍系統,可能為了完成組隊、移動等行為,專門有一個循環來處理判斷邏輯,雖然這個邏輯很簡單,再比如公會系統是否有每10秒鐘重新整理一下公會清單的需求……

<a target="_blank" href="http://blog.51cto.com/attachment/201111/131643514.jpg"></a>

如上圖所示,我們利用子對象的方式創造一顆樹,然後逐一進行周遊,在執行過程可以使用疊代,也可以使用遞歸,不管那種方式,對于子樹而言沒有太大的差別,但是對于性能而言,我們可以做一些有趣的優化,當一個系統關閉的時候,它在樹中就不執行了——具體用什麼方法,看情況而定,無論是拆枝還是邏輯判定都行。我們得到的效果是,關閉的子樹下面的元素也不會執行循環,多麼簡單,比鍊條式的容易多了,一斷全都斷。

子樹式循環在常用系統級别非常常用,對于那些比較頻繁的更換的邏輯比較實用,比如特效動畫、地圖系統等等,具體的算法和操作在《資料結構》中有明确的答案,可以在其中找到想要的東西:)。

四、區間式循環

區間式循環嚴格意義上是循環中的一個判定方式,而不是實作模式,原理是将遊戲系統各個部分拆分開,挂入不同的循環結構中,如果說鍊條式和子樹式是一種Object集中,區間式可以說是一種Objects集合打散,釋義圖如下:

<a target="_blank" href="http://blog.51cto.com/attachment/201111/131652261.jpg"></a>

區間式在大系統級别,可以分拆最消耗性能的部分,到另外一個線程(或循環結構)中完成循環,比如說戰鬥系統、地圖處理、場景管理器,而場景管理器下也可以帶入一個區間式循環,将場景分割,然後對一個區域範圍的物體進行處理(如果想想上面的圖是否可以做成一個二維數組呢?),對于超出區域和不在區域範圍内的循環邏輯完全視而不見,否則的話,要處理一片大場景中的N多個角色,無論是在自身、鍊條、子樹都會一筆不小的開銷。

區間式最大的優點是加強了範圍判定,如果寫的好,還可以多重結合,使用二維(三維也行)數組完成各個需要循環邏輯的配置設定,将不需要的拆分出去,這裡的算法可能稍微有點意思,類似哈希和List的結合,要注意的是當一個物體(OBJ)從區間1到區間2的時候,會發生什麼事情:)

五、組合式循環

其實組合式循環是一個非常偷懶的部分,因為組合的是前四種而已,在遊戲開發中,并不是上述的那種方式最好,而是因地制宜,什麼樣的模式滿足什麼樣的需求,不能隻是單純為了達到高效而高效,更加要注意未來開發的順利程度,避免返工。

<a target="_blank" href="http://blog.51cto.com/attachment/201111/131700535.jpg"></a>

如上圖所示,我們可以很清楚的分析不同循環方式在不同的環境下的應用:

自身式循環比較适合界面,因為比較固定,而且複雜邏輯不多,當然了這隻是在Silverlight的UI當中比較适用,其實主邏輯就是一個很大的自身循環,Root的循環方式就是一個自身式循環。

鍊條式循環比較使用與第二級的遊戲系統,将系統全部串起來,以達到快速周遊目的,但是在系統的下一級,就是子樹式循環,系統元素全部在一個系統下,下面的子樹中也可能會出現鍊條式,很顯然是一種最頻繁的組合方式。

區間式循環主要是應用在場景系統,可能需要一個鍊條循環或者子樹循環帶動,具體情況需要看遊戲的設計模式,如果單個場景(比如地圖)是使用單例的方式,那麼使用鍊條式循環帶動循環邏輯比較合适,如果單個場景是通過new出來的,那麼使用子樹方式來切換銜接更加容易明了。

以上是我們在做MMORPG時候的一些小小經驗總結,上述中我們用的最多是組合式循環(廢話,組合式全包了),但是對于一些小型的遊戲,建議還是不要設計這麼複雜,對于大型的網絡遊戲而言,程式設計這部分的重要性非比尋常,最後,看過很多這樣或那樣的說法,網頁遊戲對于性能是不行的,我想大部分的性能問題并不是技術本身,而是開發者沒有将一個遊戲本身思考清楚,什麼時候我們用什麼方法可以達到什麼目的,而很多的開發者期望也這個友善,那個也好,一味的追求萬事俱備隻欠東風的美好環境,殊不知,所謂的拿來思想隻會使自己退步,期望各位開發者多能從中找到一點靈感,為自己的提升有個交代:)。

本文轉自nowpaper 51CTO部落格,原文連結:http://blog.51cto.com/nowpaper/712448

繼續閱讀