非電玩人學Unity3D — (2) 認透 GameObject 與 Component。

WuFeng Chiang
9 min readApr 15, 2018

--

在 Unity3D 中,Component 是一個不直覺的字彙。一開始使用 Unity3D 的人,筆者相信,很難在一開始就有良好的使用者/開發者體驗。

我們從介面談起:

圖一) Unity 3D 開發環境

在 Unity3D 開發界面的「工具列」(最上面一排),我們可以看出這套工具和其他應用程式的明顯差異在於:Assets、GameObject 與 Component 三個概念。(見圖一紅色標示處)

使用 Unity3D 時,開發者擔任的是「導演」的角色。一開始,Unity 會派一個攝影師 (Main Camera) 和燈光師(Directional Light)供你差遣。這兩個角色被放在 Hierarchy 這個小視窗中。見圖二:

圖二) "原裝"的攝影師和燈光師

Hierarchy 這個名字似乎只用來描述裡面每個成員的排列方式,對於理解成員本身的性質沒有幫助。(所以我覺得這個命名很爛)

如果我們一路用拍戲來做喻的話,Hierarchy 筆者覺得就是「劇組」。劇組又分:在鏡頭前面的,叫「演員/角色/幕前」,不在鏡頭前面(不露臉)的,叫「工作人員/幕後」。很明顯地,一開始身為導演的我們,有兩位幕後人員(攝影師、燈光師)。

GameObject

點選攝影師(Main Camera) 或燈光師(Directional Light)後,在右側 Inspector 視窗中,可以看到這兩個角色可以接受的命令。從他們名字前面的「三色立方塊圖」可以知道:它們都是 GameObject。(見圖三)

圖三) 三色立方塊圖示,表示為 GameObject。

從這點來看,Hierarchy 視窗的名字,若不叫「劇組」,也起碼叫「GameObjecs」還比較直覺吧?這是筆者的想法,僅供參考。

看看 GameObject 大抵包括了什麼,見圖四。

圖四:哪些東西是 GameObject

Effects 可以想像成「特效師」;Audio 則是「音效師」;3D Object、2D Object 與 UI 都是放在鏡頭裡面的東西,就跟演員差不多。Camera 就是「攝影師」。(在台灣每天播放的本土連戲劇是由三台攝影機拍攝而成,所以有複數個攝影師也很正常)

以上就是對 GameObject 最直觀的詮釋。

Component

相對於 GameObject,Component 是個怪詞。來看看官方對 Component 的說明:

A component tells Unity what the GameObject does, such as move or make a sound.

也就是說,Component 用於形容 GameObject 該做什麼事、有什麼行為。

在物件導向/面向對象程式語言(Object-oriented programming,以下簡稱 OOP。)的設計中,Object 的行為就是它的方法/函式,為何還需要 Component 來補助?若是這樣,為何 Component 不是命名為 Behavior ?或是 Ability?

OOP 中,有兩種擴充物件能力的方式:繼承或組合。

回顧一下「非電玩人學Unity3D — (1) 從原子開始」提到:GameObject 對應到的 C# Script 為 MonoBehaviour,所以若想用繼承方式來擴充 GameObject 的行為,應該就是設計並實作多層次的 MonoBehaviour 子類別。

用組合呢?那就是在 C# 中,把需要用到的其他 GameObject 宣告成 public attribute,然後找機會注入物件實體(至少有三種注入方式)即可。

這裡延伸出了兩個問題:

  1. MonoBehaviour 的 “Behaviour” 不就是「行為」的意思嗎?這個不就和 Component 的作用很像了?那要 Component 幹嘛?
  2. 用程式語言的機制(繼承或組合)來做實作功能的擴充,對於程式/軟體設計師來說,很直覺;但是,對於使用 Unity 的電玩工程師來說,就不一定了。並不是每個電玩創造家都愛寫程式的,事實上,筆者還看過一本 Unity 的書籍強調不用寫任何 Script 就可以打造一些相對簡單的遊戲。

下面來解釋。

第一個問題:有了 MonoBehaviour,為何又來一個 Component 用來描述 GameObject 的行為?

其實,這個問題的答案,是:在 Unity,行為是一種 Component,而不是 Component 是一種行為。會覺得「Component 是一種行為」,是由於官方給的定義:「A component tells Unity what the GameObject does」所誤導來的。

在 加藤政樹 所著、台灣書名譯為:《Unity超人氣遊戲設計全書》一書中,第5頁,是這樣形容:

元件 (component) 就是附加在遊戲物件 (GameObject) 的「功能」。

基本上和 Unity 官方給的解釋差不多。可是,其實這只是一個容易理解,但是不完全正確的說法。

回顧「非電玩人學Unity3D — (1) 從原子開始」中,筆者從 Unity Script 文件中,整理出的類別圖可以看出:不是 Componen 是一種行為,而是:行為 (Behaviour) 是一種 Component。

Behaviour 是一種 Component。

以 OOP 來說,我們可以說「人是一種動物」,但是不能說「動物是一種人」,所以 Behaviour 是一種 Component 的情形下,硬要大家也接受 Component 是一種(用以描述GameObject)的 Behaviour ,筆者覺得…實在是個錯誤。對於一向不善強識的筆者而言,用官方/書本的方式接受 Component 的概念,實在是困難。

第二個問題:對於 Unity 遊戲的設計師來說,不使用語言導向的方式擴充物件的能力,那要用什麼?

這個答案很簡單:用 Unity 的操作來完成物件能力的擴充。這裡再引用一次圖三,但是標註圖中下方的一個按鈕:

按下「Add Component」按鈕,就為 GameObject 加上額外的能力了。

使用 Unity 提供的機制:一個按鈕就加入某個「功能」,相較於使用程式來做,當然是簡單、直觀 (但不一定比較快速)地多。因為直觀,所以在變更上也就不難。

從上面兩個問題及解答來看,是不是:語言類別中的 Component 與 Unity 操作界面中的 Component 其實指的不是同一個東西?

答案是:它們的確是同一個東西

怎麼說?再次引用「非電玩人學Unity3D — (1) 從原子開始」中的另一個圖:

圖五

前面我們已經知道「Behaviour 是一種 Component」,而 「 MonoBehaviour 是一種 Behaviour」,所以,圖五可以替換成圖六:

圖六

圖六解釋出了:一個 C# Script (MonoBehaviour 的子類別)可不可以用在多個 GameObject 上?答案:可以呀!鳥能飛,蚊子也能飛,所以可以共用同一個表示行為的 Script。

圖六也產生了一個困惑:使用 Unity 時,是 GameObject 上加入多個 Component (這裡指"功能/行為"),但是圖六指的是:一個行為 (Component) 有包含了一個 GameObject。這樣的話,解釋起來,不就完全弄反了嗎?

來解答這個困惑,要再轉化一下圖六的畫法,這裡採分解動作:

步驟一:GameObject 本身是一種 Object,所以用 Object 來替換。
步驟二:既然 GameObject 可以畫成 Object,那就直接將組合線往上畫。

最後,再把所有的類別還原回去,就精彩了:

步驟三:把所有類別再擺回去的結果

大家看看,上圖和下圖像不像?

裝飾者設計模式

其實,兩張圖,是一樣的。也就是說,Unity 中的 Component 根本就是 Decorator (裝飾者)。它延伸至 MonoBehaviour 的子類別時,就是到了 ConcreteDecorator 的同一層,然後不論加上了幾層的 Decorator,最後返回的都是 Object (共同的父類別)。

以裝飾者設計模式的精神來說,被裝飾物可以不斷地增強自己的能力,就像聖誕樹被掛得愈滿、看起來愈漂亮一樣!同理,GameObject 在被加上多個 Component 的實作類別後,也會變得更功能豐富!

可知,Unity 界面中的 Component 與 C# 類別中的 Component 所指的是同一物。

結論

筆者覺得 Unity 中所使用的字彙,其實挺爛的。要嘛就用一個真實世界的例子來組成字彙,例如:導演、演員…,不然就用軟體工程中大家比較能一下就理解的字彙,例如:把 Component 改成 Decorator。

GameObject 一詞,可以說限縮了 Unity 的用途是在遊戲,但是大家用 Unity 真的只是為了做遊戲嗎?以前是,未來不一定。至少對筆者來說,它是一個實作跨手機平台應用的手段,或是用於快速開發 AR 和 VR 應用的工具,而不是拿來做遊戲的。

此外,Component 這個詞,怎麼看都看不出它的用途。這個詞被軟體業濫用過度,有太多解釋,在文件或書上又把它動詞化/動名詞化,如:what the GameObject does、功能,都是反而讓它難以被深化理解的。Component 是個純粹的名詞字彙,看不出它應該是表示動作/行為/功能。

不過筆者還是運用了上面的拆解,來深刻地理解了整個內容,相信就算不用再強識,未來也不會忘了 Unity 中的 Component 是幹嘛的了。

--

--