您在這裡

Jonathan Blow: How to program independent games

1 篇文章 / 0 新
Jonathan Blow: How to program independent games

Braid 作者 Jonathan Blow 日前在他目前正在開發中的 The Witness 開發部落格上,發表了一篇他在今年四月份回 UC Berkeley 對他的學弟妹們演講的內容。演講的核心議題在「如何有效率地進行遊戲程式開發」,特別是針對獨立遊戲相關的開發。原網址上可下載 audio track 與 slide,但是 Jon 在 comments 中提到不知為何影片不見了 … XD 所以 Q&A 時段有一個 The Witness 的 preview 很可惜大家只能用「聽」的 XD ..

原網址:http://the-witness.net/news/?p=1004

下面我針對 talk 內容做一個翻譯與整理,但是在進入正題之前,有些前題希望大家先瞭解,不然可能會覺得「他為什麼要講這些」。

  1. 整個演講內容是 Jon 長年累積經驗歸納的心得,裡面也有些許舉例,但是這些舉例也有其時空背景環境,請不要太過著重於他所舉的例子字面上的意義。(或是可以怪我整理的不通順 :~)
  2. Jon 演講的對象是一群 UC Berkeley 的 Computer Science 學生,這些學生的性質、經驗、能力導向也許與你、我不同。而 Jon 真正的目的是要讓學生瞭解「學術」與「生產/開發」間明確的差異。
  3. 這場 talk 真的非常、非常 focus 在「獨立遊戲開發」,簡單的說就是通常只有一個人寫程式的狀態。

※ ※ ※

我粗略將演講內容分為以下幾大段落:

  1. 個人開發經驗與背景交待。
  2. 關於程式效率最佳化 …
  3. 關於使用資料結構 …
  4. 到底要最佳化什麼?
  5. 關於泛用化程式設計 …
  6. 總結:對於獨立遊戲開發來說,什麼叫「好的程式設計師」?
  7. Q&A (preview The Witness 那段會跳過,只能用聽的已經夠囧了,用文字描述感覺更差 XD)
    不過 Q&A 有不少學生問了我認為很重要的問題,也有很多學生在原網址回應問問題,會略作整理。

※ ※ ※

Jonathan Blow 本人從事遊戲程式開發長達 16 年,在這段時間中,實戰經驗的累積讓他對程式設計的「美學」定義產生不少改變,而很多都與他當年唸 Computer Science 時所認知的、老師所教導的,甚至一般程式開發上普遍認同的習慣或常識相悖離。

他在一開始先提到 Braid 當初開發的一些背景。Braid 從 2005 年開發到 2008 年上市歷時三年半,程式由一人撰寫,最後總共包括了 221 個 C++ source,238 個 C++ header,3 個 C source,20 個 HLSL source,約 12k 行的註解與 90k 行的程式碼,其中大約有 75k 行是完全新寫的,沒有使用任何「協助產生程式碼」的工具。The Witness 離目標發行時間可能還有將近一年,它的程式碼量也已經超過了 Braid 一些(但沒有到兩倍就是了),雖然有其他程式員幫忙,不過好像也只有一個人。另外,考量到很多程式會不斷反複修正,實際上當然是寫了更多東西(只是後來刪掉了)。

雖然單純看這些數字很難表達什麼很切實的東西,但不論從何種角度來說,這樣的程式大概已經遠遠超過一個 Computer Science 學生在學時期,或剛畢業的時候會碰到的規模。而 Jon 指出,統計調查的結果,程式員產量如果用秤斤兩的方式來算的話,每年每人約是 3250 行(雖然我不知道這個 study 資料哪來的,另外容易 google 到的敘述是程式員平均一天寫十行程式),當然我想這是指「有留下來的程式」。然而粗略的概算,也知道用這種速度來開發如同 Braid 一樣規模的遊戲程式的話,十幾年也寫不完。

就算完全不管品質的瘋狂亂寫,但也總要到「一定的堪用程度」,不可能無止境地用品質換速度;再考量 Braid 當初是在 Xbox Live Arcade 上推出的作品,Jon 也描述了在 Xbox 360 上開發作品一般人不太會知道的困難處:

  1. 512 MB RAM only 而且不能全用;它的 3 核 CPU 是 in-order 架構的;File System 因為安全性設計,速度也不快。
  2. 遊戲審核 fps drop 容忍範圍很小;不能有 crash,讀取時間也設限。
  3. "Soak Test",遊戲要跑滿整整 3 天(以 60fps 換算成 frame 數的話要跑超過 15M 幅),簡單說你每個 frame 有 4 Bytes 的 memory leak 的話就絕對無法通過遊戲審核。

簡單說,能通過審核程序的遊戲程式幾乎肯定是要有相當品質的。

別忘了,身為獨立遊戲開發者,遊戲設計關卡設計美術協調音效音樂協調商業營運行銷推廣財務管理沒有一項是可以漏掉不做的!「必須以極端的效率來完成事情」是最困難的挑戰。

※ ※ ※

第一個關於「程式效率最佳化」的議題,當然其實講的是老生常談了,不過不曉得有多少人在還在學生時期就有老師教過「未成年就這麼優是萬惡根源」,所以我想在此還是重複提醒一下大家 Jon 是在對一群還沒畢業的學生講話。我們也常聽過 80/20 法則被套用在這裡:八成的程式與最後的效率影響幾乎微乎其微,剩下兩成的程式則會影響八成的效率。Jon 提到的比例更極端些,Braid 中 90k 行的程式大約只有 6k 行是 performance-sensitive 的。所以不要去想「這邊怎麼寫跑起來會比較快」,平鋪直敘地寫過去就好,否則相當容易造成真正時間上的浪費。對於 Computer Science 出身的學生,也許不去做最佳化可能是很違反直覺的,但是要學會盡量克制。另一點是,針對效率最佳化的程式通常都比較難修改,或比較不直覺,若未來程式需要修改時,往往會造成麻煩。

※ ※ ※

延續第一個議題,學生在學校通常也被教導各種「資料結構」的使用時機,他的存取時間複雜度等等問題。Jon 說,這就已經隱含了「最佳化」的意義在裡面,而我們從前面知道最佳化通常是不好的,所以,使用「正確」的資料結構通常是不好的。不過我個人猜想這應該是在需要自行土炮資料結構的情況下,才會有這個 concern。譬如說確實看過不少例子是雖然用 C++ 寫引擎,但是在資料結構上都捨 STL 的不用,不過這已經超過本篇範疇,就先不談了。

Jon 在這段舉的例子是,他以前曾跑到 DOOM 的 mailing list 上說 DOOM 的場景資源管理的程式寫得不好,那一段程式在應該可以用 hash 或 b-tree based 資料結構的地方居然用 array,結果和 John Romero 互嗆了起來 XD 他事後回想,確實在這邊使用了比較高級的資料結構的話,只是花了更多時間寫、要花更長時間 compile、然後程式執行時會吃掉更多記憶體,不過實際上根本對效率沒有多大的影響,因為這個片段並不是整體程式執行效率的主導因素。Jon 也對學生提了一個觀念,就是當看到被公認為「高手」的人做了一些你覺得(技術上)「見面不如聞名」的事的時候,不妨多想想,也許你沒抓到重點或沒看到整體成果;況且,若對方有實績而自己沒有,似乎也該謙遜一點,畢竟很多臨場智慧,是沒實際走過一趟不知道的。

Jon 說他現在幾乎所有資料結構都是單純的 arrays of structs (in C/C++)。

※ ※ ※

開頭兩段其實主要都是在講與 optimization 有關的議題,那到底有沒有該最佳化的東西呢?

Jon 提出,比起最佳化程式執行的時間與耗用的記憶體空間,真的該最佳化的是「你在每個程式實作上所耗用的生命」,這才是真正有效益的最佳化考量。資料結構與複雜的演算法沒辦法最佳化你所耗費的生命,花時間在這些東西上面只會把更重要的事務(確實把東西做完)邊緣化而已;除非,你確定非這麼做不可,或是確定這麼做的效益非常非常明顯。

提到效益問題,Jon 很排斥一些實際上根本只是為了發表而發表的應用計算機科學(Applied Computer Science)的相關論文,他說幾乎所有這類論文都是不好的,往往提出了一個雖然有少許效益,但過度複雜的方法,無法被廣泛應用而且統計數字只挑好聽的來講。

※ ※ ※

再來提到泛用(generalized)程式設計,他認為「通常」泛用化的實作最終導致的結果會比幾個針對性、寫死的實作要來得差。譬如說未考量過到底真的有需求的是哪些功能/可能性,往往做出來的泛用性會包含了很多到最後也用不上的功能,中間摻雜了多餘的抽象層(abstraction),而且每當系統需求產生改變的時候,這樣的泛用設計反而比寫死的還難更動。他認為泛用系統的另一個缺點是,實際上真正的操作反而變得不明顯了。(講到這有點 Linus Torvalds 的感覺… )

在 Q&A 時 Jon 有提到,當然也有許多狀況下,泛用程式很明顯是優於各別寫死的系統,比起「不要太早最佳化」這點來說,泛用系統到底何時該用、何時不該用是一個比較難以明確界定的問題,他認為除了多寫多做、經驗累積之外沒有什麼直接的方法。

另外對於在既有程式上添加/撰寫新系統也必需格外小心,該考量的是如何刪除程式碼而能不影響任何程式功能,而非增加程式的複雜度;若把整個程式中的每個模組、類別、物件、函數等等當成一個節點,然後整個程式就是把節點連起來所組成的一張圖(這裡指 graph,不是 image)來看的話,每多一個節點也代表整張圖的連線複雜度,會以至少線性,至多平方關係的速率成長,也更易造成藕合。這也是《人月神話》(the Mythical Man-Month)中所提到當程式專案變大時它是如何越來越變得難以控制。

其實這對有一點程式開發經驗的人不難理解,而且應該也都聽過類似說法;不過 Jon 在此提到的例子是,有時候我們會傾向為了讓每一個 function/method 內容看起來盡量簡潔,所以常常為此重構(refactor)程式碼,抽出一些看起來讓 function 內容變亂的東西,把它整理成另一個 function,所以我們可能會把一個很長的 function 抽成好幾段,變成好幾個不同的小 function。但是 Jon 說,他寧可讓那個很長的 function 就長那個樣子,如果這整段程式確實只做一件事而且只出現在這裡的話。因為他不希望原本一目了然的操作,變成把實際操作的內容隱藏到其他地方去,就算那段程式可能長達一千行,那就一千行又如何呢?

(註:舉例用的程式片段在 Jon 的演講投影片第 28 頁,我這邊就不額外貼 code 了。)

※ ※ ※

所以到底對獨立遊戲開發來說,怎樣叫做一個好的程式員?

迅速、腳踏實地、會確實把事情做完,對於各種進階的程式技術與知識有廣泛的瞭解,但是只在這些技術真的非常非常有幫助時才去用它們。Jon 覺得當然各種程式設計的進階議題是一定要知道的,這確實是基礎,不過這不代表「有機會就該用上」;當人們學到一個新東西的時候,往往看到的只有這個新東西的好處,但是好處背後所隱含的一些不利因素,卻很難在當下就馬上有辦法衡量,而經驗上來說通常壞處都會大過好處。程式技術、軟體開發的方法、名詞琳瑯滿目,從「知道」到「真的瞭解」是漫長的過程,而且常常使人犯下「明知故犯」、「知行不一」的毛病。

※ ※ ※

後面 Q&A 有部份是針對 Braid 或 Jon 本人提的問題,和前面整篇文章的主旨關聯不大,整理起來不太順,包括有人問它 Humble Indie Bundle 和 Steam 比較的話哪個通路賣得比較好,或是 Braid 的一些設計理念,覺得 DLC 重不重要之類的。所以對於這幾點有興趣的話可以自行稍微聽一下演講錄音檔後半段 Q&A。

Q&A 中 Jon 有提到的幾個重點:

把握「現在夠好就好了」的原則很重要,不過,確實永遠都有某些片段你到最後非最佳化不可,譬如說對於 Braid 的話,就是「時間倒轉」系統的設計。印象沒錯的話 Jon 在 2010 年的 GDC 有講這個主題,我有機會會把這個主題略作研讀並寫寫筆記。

有人提問 Braid 會不會 open source,Jon 的回答是「也許」。不過他覺得現在網路上資源這麼多,而且開發的時空環境背景不同,就算釋出 Braid 的 source code 其實對大家沒有什麼幫助,除非有人想做和 Braid 幾乎一模一樣的遊戲;而且他又還找不到時間做這些額外的工作。

Jon 對 C++ 的看法是,業界很多人使用 C++ 是因為逼不得已,也有人問那 C# 與 XNA 呢?Jon 說就他瞭解絕大多數 XBLA 遊戲仍主要靠 C++ 來寫,因為審核規定實在太嚴格,C# 與 XNA 主要都被用在 XBLIG,這些是沒有技術審查的(他在此沒就現在的 PC Game 或其他 Mobile Game 部份做太多描述,在原網址回應中他也說他並不熟悉 Unity 之類的技術,他只說不對 Unity 做大改寫的話,大概也做不出 The Witness,原因我就不推敲了 :p)。

他和他認識的很多朋友其實只把 C++ 當成「可以在 struct 裡面放 function 的 C」;而 C++0x 他更是覺得太瘋狂了,雖然有少數功能確實是大家希望的改變。他提到很多語言本身擁有的功能、程式設計的技巧、程式架構上的準則,其實都是為了多人合作而存在的。如果你今天就是一個人寫程式,或最多兩、三個人,那些功能、技巧、架構其實都是多餘的,特別 indie game 的重點是如何用少數人在相對短的時間內完成一個中~大型的專案。Jon 在此講了一句話,我引用原句:

"Optimize the game development process to produce the highest quality game in a reasonable amount of time"

當然 quality 和 reasonable 這兩個字眼在缺乏背景設定的情況下,是很模糊的,但至少我們可以確定 the highest quality game 當然不等同於 the highest quality program(此指我們通常認知的「程式設計」)。

不要過早最佳化、不要過度設計、不要過度blahblah,這些字眼聽在一般寫程式的人耳裡是理所當然的,因為字眼上本來就存在過度兩個字,所以甚至連不寫程式的人都知道這不好。但是在整個 talk 中 Jon 很明顯是認為,對於 Computer Science 出身的學生,這些台詞必需要反複強調。

Jon 也指出他不論在 Braid 或 The Witness 中,沒用過超過三層的繼承樹;只在 Array 上使用 C++ Template(前面也提到他幾乎只用 arrays of structs 來當資料結構)。

另外,Jon 提到在 Braid 之前他也是有不少不怎麼成功的開發過程,而歸納起來當初設定的目標很多都是錯的,或規模與技術難度太高的,譬如說用電腦視覺的技術想衍生出一個好玩的遊戲,結果最後卻卡在處理技術問題上;也有製作過不少 3D 的遊戲,但是同樣很容易搞得太複雜而超過一己之力能掌握的範圍。Braid 之所以成功是因為它有辦法在一個大家已經非常熟悉的系統上,傳遞一個很不一樣的意念;而且光是操縱時間的系統在技術上就夠複雜了,其他「載體」應該越是簡單越好。(Jon 也強調他不是 Mario 迷,只是單純向 platformer 上最成功的作品表達敬意)

※ ※ ※

有個學生提問了很重要的問題,而且這和後來在原網址回應的一些內容有關,故一併整理在最後。

該學生問:「那為什麼現在學校都這樣在教程式設計?」

Jon 的回答是,第一,當然學校教的 Computer Science / Programming 基礎是必備的,但是要不要用,或用得有沒有真得有效是另一回事,不過若沒學過,也不可能去比較到底怎樣比較有效;第二,學校本來就不是在教「Production」的,「專科學校」與「大學院」的導向本來就是不同的(雖然目前遇到的狀況是產學斷層日益嚴重,而且專科學校與大學院的界定也越來越模糊,美國教育體系同樣面臨這個問題);第三,其實學校教的和 Jon 所講的內容並不真的衝突,這是兩個層次的事情:先學會規則,然後懂得忘掉規則(※)。只是學校往往連教完第一個層次都很勉強,遑論去教那種需要經驗累積才能歸納出來的結論。

在原網址回應的討論中,看得出來蠻多也是學生去發問的,譬如說「哪間學校比較好」、「這系這樣排課程對不對」,看了 Jon 的一些說明,原來美國也是很多一窩蜂的「我也有」學校,開很多 Game Design、Digital Media、blah blah 科系。比照台灣現況,好像有稍許寬心的感覺 XD?Jon 認為只有極其少數的學校值得推薦,保險起見還是從 Computer Science 或 Classical Art 等方面切入較好;遊戲的話可以自己找課餘時間做。(FYI,Jonathan Blow 在 UC Berkeley 是雙主修 Computer Science 和英文文學,不過據說沒畢業)

更詳細的討論可以定期回原網址查看。

※ ※ ※

最後還是再把警告標語拿出來唸一下 :p

  1. 整個演講內容是 Jon 長年累積經驗歸納的心得,裡面也有些許舉例,但是這些舉例也有其時空背景環境,請不要太過著重於他所舉的例子字面上的意義。(或是可以怪我整理的不通順 :~)
  2. Jon 演講的對象是一群 UC Berkeley 的 Computer Science 學生,這些學生的性質、經驗、能力導向也許與你、我不同。而 Jon 真正的目的是要讓學生瞭解「學術」與「生產/開發」間明確的差異。
  3. 這場 talk 真的非常、非常 focus 在「獨立遊戲開發」,簡單的說就是通常只有一個人寫程式的狀態。

如果您有親自去聽完演講錄音而與我解讀有些不同的話,歡迎提出討論,感謝!

 

(※)well,「先學會規則,然後懂得忘掉規則」這個解讀算是我濃縮原句自己掰出來的,因為聽到 Jon 在 Q&A 那段談話,我不得不想起大學時某教授講的話,雖然他實際上的作為是「大家連半套規則都還學不懂(因為他也不會教),就要大家忘掉規則」。