Migrate Unity 2D Game to Cocos Creator

Scissor Lee
Akatsuki Taiwan Technology
11 min readJul 7, 2020

Overview

本文主要分享從 Unity 2D 小遊戲轉移到 Cocos Creator 上的一些心得

  1. Why?
  2. 會遇到什麼問題?
  3. 轉移要花多少時間?
  4. C# => TypeScript
  5. Unity => Cocos
  6. 小結

為什麼會想從 Unity 轉移到 Cocos 上呢?

  1. 需要使用目標遊戲引擎的某些特殊功能
    Ex. Cocos Build 完體積較小、支援 H5 小遊戲
  2. 成本:Cocos 開源免費,Unity 綁約一年對小型工作室來說負擔較高
  3. 尚不熟悉目標遊戲引擎,先以原遊戲引擎驗證遊戲核心後,再進行轉移
  4. 公司或手上資源、共用程式庫大多以目標引擎居多,想統合資源

不管什麼原因,轉移都將要面對到以下問題

  1. 是否所有 2D 功能都能轉移?
  2. C# 如何轉換成 TypeScript?
  3. Unity 元件如何對應到 Cocos Creator?
  4. 會花多少時間進行轉移?

關於第一個問題筆者也無法回答
只能說必須看專案中使用到什麼樣的 Unity 元件
如果是 Unity 特有的元件或是 AssetStore 的套件
那麼很有可能 Cocos 要再進一步將特化或第三方的元件重製才有辦法
但是以簡單的 HyperCasual Game 來說
一般常用的 2D 元件 Cocos 大都可以進行對應

那麼要花多少時間進行轉移呢?

以下是筆者實際轉移一款小遊戲大略所花費的時間:

  1. 學習 TypeScript + Cocos:3天
  2. 遊戲資源轉移:1.5天
  3. 遊戲邏輯轉移:3.5天
  4. 測試 & 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 的朋友有幫助

--

--