[轉]混合語言的遊戲開發系統架構

用什麼程式語言來做軟件是一個大問題,思考了一個週末,現時想做一個混合語言的遊戲開發系統架構。暫時只考慮三種程式語言: C++、C# 及Lua。以下首先分析這三種語言的特性,之後再提出一個系統架構科案。

三種語言的比較

C++

C++是一個strongly typed、static、multi-paradigm (procedural, object-oriented, meta-programming) 的語言。基本上是遊戲引擎的 de facto 語言,其實沒有什麼第二選擇。

優點

  • 高移植性: 所有遊戲平臺都提供C++ 工具(除了一些嵌入式系統,如只提供C 或Java)
  • 高效率: C++ 是通用高級語言中最高效的,無論是時間和空間上。

缺點

  • 程序庫不足: C++ 的標準程序庫是「簡而清」的,其實這是優點也是缺點。因爲C++ 本身可以在不同的應用層面及系統上,所以標準庫不可能加入如平臺相關的GUI、thread/process等程式庫,或應用相關的image processing、encryption等功能。就是這樣,C++纔會產生五花八門的第三方程式庫。經驗告訴我,要選擇、整合和維護第三方程式庫是不容易的。有時候不同的程式庫會在有兼容的問題,也會做成不協調(命名、記憶體管理等等)、或是功能上不能完全滿足需求。解決方法只有兩個──直接由程式庫的源代碼修改並嵌入系統裏、或放棄使用程式庫自己重做。
  • 高難度: 使用C++ 的難度實在太高。其中一個原因是C++ 的高自由度,你可以用不同的組合方式實現一個功能。另外是C++ 接近低階,很多細節要程式員非常小心去處理,例如資源管理、pointer等等。要編寫及維護高質量的C++ 程式是非常困難,看看剛畢業的新人加入團隊時要花多少時間及培訓就可見一二了。
  • 編譯慢: C++ 源至C,採用#include "header" 這種傳統文字方式去引用其他功能。就算採用了pre-compiled header 或distributed build (如使用IncrediBuild 軟件),一個大規模的系統都需要很長的編釋時間。一個Edit-compile-run Cycle 所需要的時間成爲開發速度的一個巨大因素。如有一些代碼需要Tweaking,例如一些視覺效果及遊戲內容,用C++ 去做的話實在會浪費太多時間在編釋上。
C#

C# 是爲.Net 而設計、 strongly typed、static、object-oriented 的語言。 C# 的語法參考了C++的語法,但作了許多改善。

優點

  • 高階的語言功能: C#有許多高階的功能如Garbage Collection、Reflection、Attribute、Serialization等等。在C++ 要做到同樣的功能是可以的,但沒有語言本身的支持寫出來的代碼很不美觀、亦難以維護。
  • .Net 的程式庫: .Net 的程式庫可謂包羅萬有,由低階的OS 功能,到公用的Xml / Regular Expression,到應用層面的GUI / Web / Database 都有很好的支持。 API 的設計也做得很好(相對於Windows 上C/C++ 的超大量新舊API)。
  • 編譯快: 從C# 編釋至Microsoft Intermediate Language (MSIL) 是很快的。相對於C++ 的#include "header" 方式,.Net 語言採用引用.Net assembly 的meta data來編釋,節省很多時間(包括C++ 編釋時讀取及生成檔案的大量I/O 時間)。
  • 中難度: 相對寫C++ ,寫C# 的人可能會長壽一點(^_^)。 C#代碼較簡潔美觀、不用分header/implementation 檔(.h/.cpp)、不用那麼着緊資源管理(雖然還是應該注意的)、不用調試release版本時看assembly...

缺點

  • 跨平臺問題: Microsoft 暫時沒有提供跨平臺的.Net,這是可以理解的。但理論上,.Net是應可以和Java 一樣做到跨平臺。開源的Mono項目就是提供跨平臺的.Net 方案,包括C#編繹器、Common Language Runtime (CLR) 和.Net Framework Class Library等。早前看過一些Mono 的資料,Mono 很成熟,也支持embedding (可以用C# 做Script Engine),但暫時不考慮這個方案,詳情看後文。
  • 與其他程式庫連接問題: 雖然.Net Framework Class Library 已經有大量標準的程式庫可供使用。但遊戲軟件必須使用一些特別的程式庫或API,例如DirectX、OpenGL 等。 C#提供P/Invoke及COM Interop機制去使用這些程式庫,但有一定的限制。
Lua

Lua 是一個dynamic、weakly typed 的腳本語言。 Lua 被應用到許多商業遊戲當中,最爲人熟悉的例子如Far cry/Crysis 用Lua 來做gameplay、World of Warcraft 用Lua 做使用者接口。這些例子中Lua 版本的API 也開放給玩家來做MOD 或Add-on。

優點

  • 輕量: Lua Runtime 加上它的standard library 只是100KB~200KB 左右。放在記憶體受限的系統也沒有問題(如可攜式遊戲console)。
  • 執行快: 一般性而言, Lua 的速度比許多其他腳本語言快。
  • 低難度: 由於是loosely typed,編寫腳本比較簡單及容易。
  • 動態: Lua 可以用字串生成代碼的執行,也可以在執行期爲物加入attribute 及method。這是Lua 與C++/C# 設計上的一個重大分別,但其實這是一個特性,很難說是優點或缺點。

缺點

  • 語法: 擁有自成一格的語法,和C/C++/Java/C# 系列的語言很不同。未接觸過Lua 的編程人員要花一點時間學習。
  • Object-oriented: Lua 語言是沒有制定OO 的支持。但它的設計令使用者可以自行製作一套OO 的系統,並加入一些syntactic sugar 幫助編寫OO 的代碼。
  • Unicode: 和C/C++ 一樣,Lua 沒有特別支持Unicode (可能是因爲完整的Unicode 支持可能需要很多代碼,使Lua 變大)。要修改Lua 的編釋器代碼,或使用Lua 的Mod 如Lua Plus

分析

沒有一個程式語言適合做所有的任務。我把以上的資料編成一個簡單的表:

2010022300492281.png

一個遊戲通常會由不同的人員製作,編程人員大概可以分爲做Technology、Toolset、Gameplay等領域。Technology 指做遊戲引擎核心部份,或客製化第三方的遊戲引擎。Toolset 包括面向不同使用者的軟件工具,從Content pipeline (如匯入匯出檔案)、Asset Management、Level Editor及其他編輯工具等。而Gameplay 是指遊戲內容中的行爲部份,可以分爲遊戲的核心行爲(如人物控制、戰鬥系統),及爲個別人物及關卡編寫的行爲(如NPC對話、AI、任務、場境中的trigger等等)。

基本上Technology 的部份需要高效、跨平臺、和低階API連接。基本上只可以選擇 C/C++。

Toolset 的部份需要許多GUI 的部份,也要因應使用者(美工、關卡設計、音效設計等)的要求迅速改變或加強功能。另外Toolset 要處理不同種類的檔案,現時常見會使用XML 作爲中介的檔案(如COLLADA)。以上三種語言其實都可以使用來做toolset。用C++ 的話可以選擇一個GUI API 如Win32、MFC、WTL、wxWindows、Qt 等等、或使用自己開發的GUI API。但是用C++ 開發GUI 的時候,編程困難程度比較高,編釋時間亦長。這兩點可能不符合需要經常改變需求的Toolset。如果使用腳本語言來做GUI 的話,就需要一個好的程序庫連接及工具。許多時候這些腳本用的程序庫和原來的GUI 程序庫會有版本後滯的問題。所以,我暫時認爲用C# 做大部份工具是比較好的選擇。 .Net 提供的GUI (Windows Form) 及XML、Regular Expression 等功能也支持得很好。

而 Gameplay 的部份是經常要改動的。除了純粹改動數值外,還要在行爲的處理上改動。對於個別人物和關卡的編程可能由關卡設計師負責,他們的編程能力可能相對較低。腳本語言比較適合。有一些情況也可以用視覺化的腳本來表達。首先嚐試用 Lua 吧。

設計科案

以下兩張圖是現時對於混合語言的遊戲開發系統架構的設計。

遊戲執行期

2010022300500189.png

遊戲開發期

2010022300493663.png

兩張圖的橙色部份都是由Swig 生成的模組。 這個設計是基於以上的分析,把Technology、Toolset和Gameplay的部份用各自最適合的語言來實現。 爲了跨平臺的需求,在執行期的版本是沒有C#的部份,只使用Lua 的輕量腳本Runtime。 C++ Engine 設定爲執行期和開發期的共通部份,所以把需要用C++ 的Toolset 部份抽取了出來。 而在遊戲開發期中,希望可以在工具裏直接運行及調試遊戲,所以會同時有三個語言的執行環境。

混合語言的優點
  • 各取所長: 透個組合各個語言的優點,可以增強開發的效率及最終的遊戲質量。
  • 適合不同的開發者: 做Technology、Toolset 和Gameplay 的開發人員在技能方面有所不同。不同語言各自照顧他們的需要。
  • 低藕合性(Coupling): 不同語言的中間有一個獨立的接口,使藕合性降低。例如同樣的Gameplay代碼可以在不同版本的引擎運行。
混合語言的缺點
  • 更多知識: Technology 的編程人員應該需要學習這三種語言,及相關的連接事宜。
  • 多個接口: 需要建立及維護多個接口。希望 Swig 可以減輕這個問題。
  • 調試困難: 調試時誇越一個語言可能會增加調試的難度。
其他設計科案

在蒐集資料的時候,看見可以把Mono 的CLR 嵌入程式中,就好像把C# 用來做腳本語言。連接的實現方式類似於P/Invoke。用Mono 作爲Gameplay 的腳本引擎是很吸引的。在效能上,由於採用Just-in-Time (JIT) 把MSIL 翻譯至native code,執行速度一定會比直譯式的腳本快。 C#在語法上跟C++/Java相似,許多人會懂得使用。此外,Mono 利用CLR 的特性,還可以支持其他語言。 這個方案的其中一個問題是它不太Light-weight。或許可以刪掉大部份的程序庫及JIT來改善。另一個想法是,透過另一種語言的結合,可以引證系統的可延展性。基於可延展性,在將來也可以考慮加入用Mono來做Scripting。所以暫時採用 Lua。

後記

原來只是想記錄一些想法,卻發現寫這篇日記花了多個小時。希望除了作爲一個記錄,也可以引發大家一起討論,那麼也可能是值得的。


我後來使用這架構開發 Mil Engine,但在開發中,我放棄使用.Net 的 XML 庫,而採用C++的 rapidxml 開源庫。之後會介紹陸續介紹 Mil 和把它開源。

其實一般遊戲引擎都會使用腳本語言,本文旨在分析及設計。而使用.Net來做ToolSet並非主流商用引擎的選擇,但在Mil 中也證實是一個很好的選擇。

本文原來是繁體中文,在2008-02-22發表於http://miloyip.seezone.net/?p=7,本文經過修正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章