2009年10月8日 星期四

家族日本行 (2)

隔天,坐上遊覽車,往箱根前進,沿路走了幾個景點。

第一個來到的是小田原城。

日本戰國時代,北条氏發跡的小田原城。

旅行之前,剛好在玩「信長之野望」,所以對這個城特別有興趣....XD

北条氏很猛,從小田原城發跡,曾經擋住了武田信玄的攻擊,一直傳了五代,每一代的領土都有擴張,直到豐臣秀吉用好幾路大軍包圍,北条氏才被吃掉。

不過我在玩的「信長之野望」裡頭,北条氏老是活不長,歷史模擬遊戲終究還是沒辦法模擬歷史。

DSC00644

DSC00648

天守閣的外觀

DSC00645

天守閣裡面有戰國時代的歷史文物展覽。不能拍照的,拍了一張就被制止了,所以這張照片很稀有....

接著咧,坐小火車上山。這個小火車跟阿里山的一樣,也是用之字形的方式上山。

DSC00654

車站裡頭

DSC00656

乘客可以直接看到駕駛員在做什麼。深深覺得台灣的火車跟捷運也要這樣透明才行。

DSC00667

上了山,參觀一個雕刻公園。

DSC00684

然後坐這個所謂的「海賊船」到湖的對岸。其實我不喜歡這種船,在日本嘛,就應該讓我們坐坐以前日本人當海盜的那種船啊!

DSC00691

跟著來到了一個叫做「忍野八海」的地方。八海指的是八個小池塘。這地方就有點歷史的感覺了。雖然裡面還是在賣現代化的土產。

(從這時候開始,遇到大陸旅行團了,所以開始用台語交談....)

接下來,就到了溫泉旅館休息泡湯。

hmm....全裸的泡湯就不能提供照片了....

因為不能帶相機進去....

2009年10月6日 星期二

家族日本行 (1)

九月底,咱們一家大小 (七個大人外加一個兩歲半的小朋友),到日本玩了五天。實際上是三天啦,迪士尼樂園玩一天,坐車到箱根的溫泉,沿路上參觀小田原城跟其他景點,在溫泉旅館住一晚,然後回頭到東京的景點晃一晃。

DSC00595

桃園機場大廳

DSC00599

兩歲半的小朋友和她媽媽(也就是我老妹)

小朋友超可愛,殺掉相機裡一半以上的記憶體......

DSC00608

迪士尼專車

DSC00617

迪士尼樂園拍不了全貌,只能拍大門的一角。

據說迪士尼樂園本來是要建在台灣的,不知道為什麼最後被東京給搶了去。總之脫不了短視近利外加豬腦袋這兩個原因。

迪士尼玩了一天,可是沒什麼照片。晚上的遊行表演倒是有影片。

呵....

對,影片拍得很不好....

2009年8月24日 星期一

Dirty Coding Tricks

Dirty Coding Tricks by Brandon Sheffield

================================================

今天在Gamasutra上看到的一篇文章。

遊戲開發有時程壓力,而當我們發現一個很難解的Bug,時間又已經來不及的時候,我們該怎麼辦? 這篇文章就舉出了幾個偷吃步的故事。

頭一個故事就很慘了。

在一個PS2遊戲即將要發行的時候,測試團隊發現,在第一個關卡裡,玩家只是靜靜的站著就偶而會造成crash,而且更不幸的是,是在燒成光碟之後,這個問題才會出現。

於是開發團隊為了解決問題,不斷的修改程式,燒成光碟,然後測試,弄了十幾個小時( 為了等程式 crash,只好拿 World of Warcraft 打發時間.... )。

後來奇蹟出現了。有人發現,一開始攝影機向右轉個90度的話,程式就不會出問題,於是乎,PS2的版本,就在攝影機轉個角度之後,順利通過測試而發片。而已經上架的另外兩個平台的版本,攝影機角度還是維持原先的設計。

我的結論是:寫程式,也需要奇蹟。

第二個故事,真的就是偷吃步了。

遊戲程式中所用到的資源,例如一大堆的檔案,在檔案系統中通常會想些編碼的方式當作索引來存取這些檔案。這個故事裡的團隊很倒楣,他們將檔案的檔名CRC32編碼,同時也將檔案內容做CRC32編碼,用這兩個值組成64位元的索引來存取檔案內容。

開發了兩年,處理了幾萬個檔案,從來沒有發生索引值衝突到的狀況。

可是,它真的發生了。兩個不同內容的檔案,卻有完全相同的檔名(也不知道為什麼要這樣設計....),而且檔案內容在編碼之後也得到相同的CRC32編碼--這下子事情大條。

改檔案系統,改索引方式,都是個大工程,而且誰知道改了之後會不會發生同樣的狀況? 這時候,再怎麼完美的編碼方式,都沒辦法給人信心了。

沒時間了,只好用一個最簡單的偷吃步解決這個問題 -- 把其中一個文字檔案打開,在最後面加一個空格,然後存檔。

於是乎,遊戲如期發行。

 

當然啦,這些方法都不是好的解決方式,而且會帶來後續的問題,不管是程式穩定度還是程式維護上的問題。

不過,對我們老是在有限時間跟疑難雜症打仗的人來說,這些故事是會讓人會心一笑的。

2009年8月18日 星期二

Design Patterns for Game Programming -- Reference Count

這是提供入行的新人教育訓練用,我們自己整理的Game Programming中的Design Patterns。我們所想到的第一個項目,就是Reference Count。所以就先將它整理出來了。

既然是寫設計模式,自然必須依照設計模式經典的編排方式來做。

以下進入正題。

 

Design Patterns for Game Programming -- Reference Count

使用時機

遊戲程式中充滿了使用記憶體資源的物件,其中有些物件的特性是,佔用大量的記憶體,又常常重複出現在遊戲中。例如,3D遊戲中的模型、貼圖,2D遊戲中的圖片資源等等。

clip_image002

(場景中重複出現的樹木就包括了重複使用的模型與貼圖) ( Screen-Shot from World of Warcraft )

針對這種物件,我們會將它設計成共享的資源物件,以節省記憶體的使用量。同時,我們也在共享資源物件中,加入參照計數(Reference Count),以便記錄每個共享資源所被參照的數量。

目的

將共用的資源做有效的管理。改善資源與記憶體的使用。

設計實作

clip_image003

架構上主要有三種物件。

Shared Resource :

也就是共享的資源物件,像是貼圖、模型、圖片等。成員變數m_iReferenceCount記錄的就是參照計數,而IncRefCount與DecRefCount則是用來對Reference Count遞增與遞減之用。每個Resource有一個唯一的Key值(例如,資源檔案名稱或是某種編碼後的整數)。

Resource Table :

存放Shared Resource的地方,通常會使用Hash Map、Binary Tree或是其他能夠快速的從Resource Key值搜尋物件的資料結構。

Resource Manager :

做為與應用程式溝通的介面物件。提供兩個最主要的成員函式 : Query Resource 與 Release Resource。

clip_image005

應用程式透過呼叫Resource Manager的Query Resource函式,來取得共享資源。

首先會在Resource Table中搜尋是否有對應Key值的資源存在,如果存在,就將資源的參照計數遞增之後,傳回給應用程式。如果不存在,就產生一個新的資源( 此時新資源的參照計數為1 ),插入Resource Table中,然後傳回給應用程式。

clip_image007

另外,應用程式也透過Resource Manager的Release Resource函式來釋放資源。

首先Manager會先將Resource的參照計數遞減,並且取得結果。如果參照計數小於或等於0,表示已經不再需要這個共享資源,就先從Resource Table中將資源移除,然後,刪除這個資源。

多緒環境下的設計實作

有兩項必須做到Thread-Safe,一是Resource Table的存取,避免多個執行緒同時修改Table內容以及相關的索引資料,另一個則是Reference Count的遞增與遞減計算,避免多個執行緒同時修改,造成資料錯誤。

使用設計上的限制

1. 在這個機制下,共享資源的生成與銷毀都必須是透過Manager的Query / Release來負責,應用程式要避免直接使用new / delete來生成 / 銷毀共享資源。一個可用的設計方式是,將資源物件的建構子與解構子封裝起來不公開,封鎖應用程式對共享資源的new / delete權限,同時宣告Manager為friend class,把權限讓給Manager。

2. 共享資源的Inc / Dec Reference Count操作必須是成對的,否則容易出現Memory Leak ( 當 Inc Reference Count次數大於 Dec Reference Count時 ) 或是使用到無效的指標 ( 當 Inc Reference Count次數小於 Dec Reference Count時 )。這項限制,可以透過Smart Pointer的設計來改善。

2009年7月31日 星期五

Code Review

前幾天在想有關Code Review的事情的時候,網路上瀏覽到這麼一張圖。

wtfm

哇哈,一張圖片,勝過千言萬語啊......

2009年7月10日 星期五

遊戲程式的設計模式

前幾天,老闆找我討論一個問題:要給程式新人怎麼樣的訓練,才能讓他們在專案開發上發揮該有的戰力?

我把這個問題繞了兩個彎,換成:有什麼東西是新人不懂,卻深植在老手腦子裡的?

於是我找到了幾個重點,其中一個就是遊戲程式的設計模式。

四人幫的書裡面所寫的設計模式,我稱它做一般化的設計模式。當然,在遊戲程式裡,也是多多少少會用到個幾種模式的,像是Singleton、Factory、State之類。

而我們要再進一步做整理的,是在遊戲程式裡常用的設計。

例如,在遊戲資源或是繪圖資源的管理上,運用Reference Count很常見,但是對剛跨入這一行的程式新人來說,Reference Count可是連聽都沒聽說過。而另外一個極端的資源管理方式,Garbage Collection,又是怎麼回事?

程式老手會說,拜託! 這是基本觀念好不好?

不過,要讓新手程式自己搞懂這是什麼,可是一個不算低的門檻。

以往,我們用的是,師父領進門,然後自己修行,從數十萬行的程式碼裡頭,自己把這些所謂的「基本觀念」搞懂的方式來訓練新人,訓練期不但太長,也未必人人都有辦法自己「頓悟」出來。而且,如果急就章似的就這樣把新人丟上線去打仗,那是很容易出問題的。例如,Reference Count一旦用錯了,小則memory leak,大則crash。

反正都不是好結果。

然後我們為了減少出錯的機率,將Reference Count的機制,套上了Share Pointer的Template來使用....

這又是新手程式要跨過的另一個門檻。

老手知道Reference Count的使用時機、使用方式,以及設計上所要考慮的點,也知道Share Pointer究竟要防範什麼樣的錯誤,以及會帶來什麼麻煩。但對新手程式來說,這是:千頭萬緒,治絲益棼。

所以我們要拉出一條可以當作起點的線頭,將這些遊戲程式中的設計模式,從複雜的程式碼裡頭整理簡化出來,降低新手程式的進入門檻。

也許哪一天我可以把某些個整理出來的模式Po出來也說不定......

2009年6月19日 星期五

Material Script and Technique

我想,大概沒有什麼繪圖或遊戲引擎不在引擎裡頭使用Material Script。

不過今天的重點不是 Material 怎麼設計 ( DirectX 裡頭的 Effect file 已經算是一個不錯的設計了 ),而是在使用 Material Script 所遇到的問題。

舉個例子,我們在遊戲裡,點選一個物品或怪物的時候,物品會有特殊的標示,像是加個邊框或是變得比較亮什麼的。因為Render的方式不同,所以我們必須更換不同的Render State或是Shader。

直覺的方法是,把Material Script換掉。直接換成加邊框的Material。

不過這樣會衍生一些問題。

第一個問題是,我們在遊戲裡有很多種Material,是不是每種Material都要再加一套加邊框的格式? 而且呢,更換 Material Script 意謂著我們需要重新編譯 Script,重新編譯 Shader,重新設定 Script 中的參數。同時,我們必須訂出一套 Material Script 檔案的命名規則,否則我們怎麼找到正確適合的 Material Script ?

另外一個問題。在我們的設計裡,Material Script 是屬於共用的檔案資源,同一個 Material 可以因為模型的不同而指定使用不同的貼圖,甚至於同一個模型都可以任意的更換貼圖。所以這麼一來,貼圖成了額外設定的一個變數,而這個變數,必須在更換 Material Script 時保持不變。

所以我沒有採用這種方法。

我的 Material Script 是直接使用 DirectX Effect file 的,Effect 裡頭有支援 Multi-Technique 的結構,所以我就修改了引擎中的 Effect Material 系統,將 Multi-Technique 的架構加了進去。

於是呢,我的 Material Script 中,除了預設的Technique之外,又加了一個加邊框的 Technique,需要更換 Render 方法或 Shader 的時候,就切換指定的 Technique,這麼一來,不但可以快速切換,不需要特別的檔案命名規則,而且,像是光源、貼圖等等在 Render 時所需要的參數,也不需要重新再連結設定一次。

不過,壞處是,我必須在每一個有需要更換 Technique 的 Material Script 中,把這樣的 Technique 都加進去,也是不小的工程。

還是說,誰有更簡潔的解決方法?