Migrate Unity 2D Game to Cocos Creator
Overview
本文主要分享從 Unity 2D 小遊戲轉移到 Cocos Creator 上的一些心得
- Why?
- 會遇到什麼問題?
- 轉移要花多少時間?
- C# => TypeScript
- Unity => Cocos
- 小結
為什麼會想從 Unity 轉移到 Cocos 上呢?
- 需要使用目標遊戲引擎的某些特殊功能
Ex. Cocos Build 完體積較小、支援 H5 小遊戲 - 成本:Cocos 開源免費,Unity 綁約一年對小型工作室來說負擔較高
- 尚不熟悉目標遊戲引擎,先以原遊戲引擎驗證遊戲核心後,再進行轉移
- 公司或手上資源、共用程式庫大多以目標引擎居多,想統合資源
不管什麼原因,轉移都將要面對到以下問題
- 是否所有 2D 功能都能轉移?
- C# 如何轉換成 TypeScript?
- Unity 元件如何對應到 Cocos Creator?
- 會花多少時間進行轉移?
關於第一個問題筆者也無法回答
只能說必須看專案中使用到什麼樣的 Unity 元件
如果是 Unity 特有的元件或是 AssetStore 的套件
那麼很有可能 Cocos 要再進一步將特化或第三方的元件重製才有辦法
但是以簡單的 HyperCasual Game 來說
一般常用的 2D 元件 Cocos 大都可以進行對應
那麼要花多少時間進行轉移呢?
以下是筆者實際轉移一款小遊戲大略所花費的時間:
- 學習 TypeScript + Cocos:3天
- 遊戲資源轉移:1.5天
- 遊戲邏輯轉移:3.5天
- 測試 & Debug:2天
接下來會開始分享 C# 如何轉換到 TypeScript
建構子 — Constructor
建構子的部分,TypeScript 會是以固定的關鍵字 constructor
而不像 C# 以類別名稱
建構子多載 — Constructor Overload
TypeScript 下要撰寫建構子多載蠻麻煩的
首先要先寫一個空的建構子,再將不同的建構式一一填上
最後還需再撰寫一個帶有 nullable參數的建構子
函式 — Function
函式部分沒什麼特別的差異
就是參數和返回值的順序不同,TypeScript 還會額外有冒號
轉換一陣子後就會習慣了
函式多載 — Function Overload
相對於建構子多載,TypeScript 的函式多載就更麻煩了
除了要像剛剛建構子多載時提到的,把所有的函式列出之外
最後帶有 nullable 參數的函式還要進行額外的型別判斷
很不方便,筆者偏好直接宣告另一個名稱的函式而不使用函式多載
Getter / Setter
C# 在撰寫 Getter/Setter 時很彈性,寫法可以搭配 Lambda
帶有 Block {} 的完整寫法也可以自由加入 get 或 set
TypeScript 則是需明確指明為 Getter 或是 Setter,並且要分開撰寫
不過也只是需要習慣一下,並沒什麼特別
容器 — Collections
TypeScript 預設的容器只有 Array
但在 Unity C# 我們應該還蠻常使用到 List、Dictionary、Queue 等容器
雖然 TypeScript 沒有,但好在已經有現成的程式庫可供使用
安裝完 NPM Package 即可進行使用,詳細點以下儲存庫
https://github.com/basarat/typescript-collections
Linq
TypeScript 並沒有相對應 Linq 的查詢語法
但相對 Linq 核心的 IEnumerator<T> Extension Methods 幾乎都有對應
有些 Linq 方法如 Distinct,轉換成 TypeScript 會變得較冗長
大部分都還算簡短,詳細請參考:
https://decembersoft.com/posts/typescript-vs-csharp-linq/
Delegate
TypeScript 下並沒有與 C# event 一模一樣的機制
雖無法使用疊加 += 進行託管
但是可以使用類似 Lamda 的匿名函式直接進行指派
對於只有隔一層的類別要進行溝通還是蠻方便的
Graphic Binding
Graphic Binding,或是稱 Asset Binding
指的是如何將編輯器中已經拉好的元件 Reference 綁定到程式中
在 Unity 大家熟知的就是使用 SerializeField 這個 Attribute
而 Cocos 也有類似的功能,叫 property 的 Decorator
TypeScript Decorator
TypeScript Decorator 和 C# Attribute 功能十分類似,寫法十分簡潔
都是實現 Meta-Programming 的一種方式
將程式碼本身當作資料,進一步的操作
不論是 Unity 的 [SerializeField] attribute
或是 Cocos 的 @property decorator
都是把我們所宣告出來元件,在引擎編輯器中做了額外處理後
開發者才能夠在 Inspector 中看到這些欄位並進行元件的拖拉綁定
只是 TypeScript 的 Decorator 其實還在實驗階段
所以可以在 jsconfig.json 下看到 experimentalDecorators = true
Property Decorator
要創建一個自訂的 Decorator 其實並不難
其實就是寫一個函式,而每種 Decorator 會有固定的寫法格式
以 Property Decorator 為例,參數會有一個 target 和 propertyName
實際上使用時就可以直接用 @函式名稱
就能夠開始進行 meta-programming 了
Graphic Binding — Components
將 Component 加上 property decorator 後
你就可以像 Unity 一樣將基本元件如 Sprite、Label 進行拖拉綁定
容器的話有 Array 可以使用,而自定義元件只要繼承 cc.Component 後
就像 Unity 繼承自 MonoBehaviour
加上 property decorator 後一樣可以進行拖拉綁定
生命週期 — LifeCycle
基本上 Cocos 的 cc.Node 跟 Unity 的 GameObject 生命週期是一樣的
但 Unity 的會複雜很多,而 Cocos 名稱稍有不同,Awake 變成是 onLoad
常用元件 — Components
在 Unity 下常用的 2D 元件大概就是 Image、Sprite、Text
到了 Cocos 變成 Sprite、SpriteFrame、Label
除此之外,Cocos 還多了一個叫 Prefab 的型別
動畫部分 Cocos 並沒有 Animator 元件
但有 Unity 早期的 Animation 搭配 AnimationClip 可以使用
漸變 — Tween
在 Unity AssetStore 最廣泛被使用的 Tween 應該是 DOTween
而 Cocos 下也有相對應的 cc.Action 和 cc.Tween 可以使用
官方是推薦使用後來推出的 cc.Tween
跟 DOTween 一樣是採用鍊式寫法 (Method Chaining)
同樣也有 Sequence 可以將各種 Tween 進行組合
單例 — Singleton
這邊的 Singleton 指的是在 Cocos 下的,也就是繼承自 cc.Component 的
寫法十分簡單,只要在 onLoad 下將 this 指派給宣告為 static 的自身即可
事件 — Event
事件部分 Cocos 是採用冒泡事件流
如果有使用過時代的眼淚 — Flash 的朋友應該會有感覺是類似的機制
甚至連 stopPropagation 函式名稱也一樣
這個機制就是說在同一個節點樹下
只要我是你的爸爸 (parent),你發事件出來我就收得到
自定義事件 — Custom Event
利用冒泡事件流搭配 Cocos 原本提供的自定義事件類別 cc.Event.EventCustom,我們可以稍微包裝一下
將自定義事件透過類別名稱的方式來識別與發送
事件的監聽與發送直接使用 cc.Node 下的 on 和 dispathEvent 函式即可
詳細請見下圖程式碼,這邊就不再多加贅述
結構 — Struct
C# Struct 應該是在轉移過程中容易踩到的一個坑
TypeScript 並沒有相對於 Struct 的型態,只有 Class
但 Struct 一個重要特性就在於傳遞時會自動複製一份
當你當參數傳遞或是使用 Linq 的 ToList,都會再做一次複製
而不會修改原本的 (Pass-by-Value)
以筆者踩到的坑來說,原本在 Unity 下使用的 Vector2Int
到了 Cocos 下會是 cc.Vec2,但型態一個是 Struct,一個則是 Class
如果想要達到一樣的 Pass-by-Value 效果,需要進行 DeepClone
但你還是得要去檢視所有用到的,這部分改起來稍微比較累一點
轉移細節
筆者稍微分享轉移的一些細節,剛剛講的大部分針對第 2 和第 3 點
第 1 點則是說在實際轉移過程中,把你原本寫好的 C# 類別程式碼
全部複製過來後,再進行第一次的基礎轉換,比方說 import、函式宣告等
而比較複雜的函式內容,或是尚未需要驗證的功能,都暫時註解掉
比方說比較繁瑣的動畫,先測試到畫面能夠正常顯示就可以了
之所以要全部複製過來再做註解,主要是怕遊戲邏輯會漏搬
當所有程式碼都做完初步轉移後,再把註解打開進行第二階段轉移
而這樣應該會是最完整也最快的方法
畢竟減少了幾次人工 Context Switch 的時間
小結 — Summary
以結論來說從 Unity 轉移一個簡單的 2D 小遊戲到 Cocos 上沒什麼問題
從熟悉 Cocos + TypeScript 到完成轉移大概會需要 2 個禮拜左右的時間
主要是 Cocos Creator 既然改成像 Unity 一樣 Component-Based 的結構
而且連編輯器介面與元件各種屬性都很像
那麼熟悉 Unity 的你用起來就像是在用一套陽春版的 Unity
所以你只要評估現有遊戲中的
1. Data Structure (C# => TypeScript)
2. 遊戲引擎元件 (Unity => Cocos)
是否都夠轉移?不能轉移的是否能夠客製化出來?
接著就可以開始動工進行轉移了
轉移過程筆者感覺好像回到過去在寫 Flash 的 AS3.0
其實語法真的很像,畢竟都是屬於 ECMAScript 6 的語法
另外一個很有感的則是突然都不用再等編輯器編譯
對於追求速度的碼農來說,其實還真的蠻爽的
以上,希望對有要從 Unity 轉移到 Cocos 的朋友有幫助