[Unity] 從零開始的學習心得 #1 – 遊戲如何動起來
此篇文章是《從零開始的 Unity 學習心得》系列的第一篇文章,這個系列是記錄我對 Unity 的開發及學習心得,包含我用何種方式去理解 Unity 的運作,並且在我所知的範圍內盡可能說明相關原理與開發要點。完整系列的目錄可以參考:
在開始深入 Unity 之前,我會建議先有點撰寫程式的概念。而這篇文章會先說明,遊戲程式與一般學習程式語言時撰寫的單次性程式的差異:遊戲迴圈。
讓遊戲動起來 – 遊戲迴圈 (Game Loop)
如果你去網路上搜尋 “遊戲迴圈" 四個中文字,跑出來的內容可能是關於遊戲體驗、遊戲企劃設計之類的內容,但這不是我說的對象;改用英文 “Game loop" 才比較容易精確找到我所想指稱的內容,精確對應的中文專有名詞應該是沒有吧。
一個 Game loop 分成了三個階段:
- Input:偵測並收集所有外部輸入的資料,包括玩家操作、資源檔載入、網路封包等。
- Update:依照當前既有的資料、以及最新的 Input 進行邏輯運算、資料更新。
- Rendering:依照最新的資料,更新畫面。
只要遊戲程式一被順利開啟、持續地在運作,這三個階段就不斷的被依序重複執行,形成一個迴圈 (loop),一直到遊戲被關閉結束,這迴圈都不會停止,是遊戲能夠 “被遊玩" 的基本原理。
舉例來說明的話:
- Input:按下鍵盤上的方向鍵。
- Update:發現最新的輸入資料有方向鍵,朝該方向移動腳色的位置資料。
- Rendering:繪製出最新的畫面,讓腳色的位置跟過去有所差別。
如此一來,遊戲角色就開始在畫面中移動了!
有個相關名詞:禎率 (FPS,Frame per second),直接翻譯的話就是 “每秒的畫面數",在遊戲中代表著畫面更新速度,同時也代表著每秒運作了多少次的 Game loop 。跟電影或動畫一樣,遊戲也依靠每秒替換幾張圖片來讓畫面動起來,只是遊戲作為 “可以控制的動畫" 多了 1 跟 2 兩個步驟。
Unity 在 Game loop 上的實現與窗口
使用 Unity 進行遊戲開發,遊戲的運作原理依舊離不開 Game loop 的概念,只是三個步驟被打散到遊戲引擎的不同功能,並由引擎本身來進行整合,實現遊戲的運作。
Input 部分
Unity 的程式腳本 API 中,便有一個以 Input 為名的類別,可以用來得知玩家的輸入訊號,包括鍵盤、滑鼠或是觸控螢幕的點擊。配合在專案中對 Input Manager 的設定,還能取得搖桿的輸入訊號;配合 GUI Event System 的設定,則可以直接對應到 UI 元件的輸入等。
這些 Input 訊號會由 Unity 統一擷取,被且將訊號的最新資訊儲存在遊戲引擎的某處,Update 階段再由腳本呼叫 API 進行取用。
廣義上的輸入,還有檔案讀取的部分。Unity 有場景 (Scene)、資源 (Resource)、串流 (Steaming Asset) 等不同手段,用來配合不同的需求。網路部分則有 WWW 以及 UnityWebReqeust 兩個類別來支援;若有需要,.NET C# 提供了 TCP 與 UDP 的 Socket 連線類別,在 Unity 上也能直接使用。
Update 部分
如果要撰寫 Unity 的腳本,第一個會認識到的類別便是 MonoBehaviour,這是每個要跟 Unity Game Loop 進行互動時,必然要使用到的類別。
不同遊戲的 Update 階段會因為相異的玩法與設計需要,有著各式各樣的自訂邏輯,為了要將自訂的邏輯定義給 Unity 執行,一般會將相關的程式碼寫在 MonoBehaviour 的 Start、Update、FixedUpdate 等方法中,來與 Unity 進行互動。
可以想像成 Unity 的 Game loop 在 Update 階段留下了許許多多的空格,讓遊戲開發者將邏輯相關的程式碼直接填入其中。這樣當 Game loop 運作的過程中,Unity 會在符合定義情況時,直接取用對應區塊的程式碼來執行,就像在一個現成個骨架上推砌積木,讓開發者建立出形形色色的玩法。
對應不同的情況跟時機,Unity 會執行的方法 (Message Function) 有相當多種類,在開發 Unity 遊戲時,如果有數個物件之間會相互影響,便要注意這些 Message Function 的先後順序,來避免預期之外的錯誤發生。要記得,Unity 是個開發工具,不是通靈許願機,只有你主動去了解並正確的使用它,遊戲才能真正地依照設計去運作。
- 說明 Update 流程的官方文件:https://docs.unity3d.com/Manual/ExecutionOrder.html
除了直接用腳本來告知 Unity Update 邏輯,還可以配合內建的許多工具:動畫狀態機 (Animator)、物理碰撞器 (Collider)、腳色尋徑 (Navigation) 等功能,來節省需要撰寫的程式碼,以及配合動畫控制、物理系統上的複雜開發。
Rendering 部分
在 Unity 中,任何 Update 階段對場景配置進行的更動,都會透過許多 Unity 的 API 來完成,而 Unity 再透過場景的配置 ,自動地完成畫面的繪製與更新。
原本作為畫面呈現的這個階段,越是複雜的遊戲,越是有著包山包海的開發工作要進行,但是 Unity 做為一個遊戲引擎,已經內建完成了大部分的工作,我們只要利用不同的 GameObject 跟 Camera 來排列出想要的畫面即可。
除了 GameObject 的位置,為了做出各種不同的畫面效果,Unity 提供了 Particle System 以及 Shader Lab 來提供開發者進行特效製作與自訂的畫面效果。
一般來說,Rendering 的開發細節與原理會歸類在 Unity 的進階部分,不只是要能了解 Unity 本身的知識,還要進一步吸收關於 Rendering Pipeline 等遊戲開發的理論原理,才能自由自在地做出理想的畫面,可以說是無底洞般的大坑。
不過 Unity 的 Asset Store 跟網路上已經有了許多付費或免費的資源,透過社群交流與分享的力量,讓本來是神秘黑科技的遊戲開發細節,成為相對容易使用的現成工具,可以直接用在遊戲的開發上,這也是使用商業引擎開發遊戲的主要優勢之一。