Migrate Unity 2D Game to Cocos Creator



Overview

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

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


Why?為什麼會想從 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 開始進行分享


Unity to Cocos

建構子 - Constructor


建構子的部分,TypeScript 會是以固定的關鍵字 constructor
而不像 C# 以類別名稱

Unity to Cocos

建構子多載 - Constructor Overload


TypeScript 下要撰寫建構子多載蠻麻煩的
首先要先寫一個空的建構子,再將不同的建構式一一填上
最後再撰寫一個帶有 nullable參數 的整合判斷的建構子

Unity to Cocos

函式 - Function


函式部分沒什麼特別的差異
就是參數和返回值的順序不同,TypeScript 還會額外有冒號
轉換一陣子後就會習慣了

Unity to Cocos

函式多載 - Function Overload


相對於建構子多載,TypeScript 的函式多載就更麻煩了
除了要像剛剛提到的一樣,把所有的函式列出之外
最後帶有 nullable 參數的函式還要進行額外的型別判斷
很不方便,筆者偏好直接宣告另一個名稱的函式而不使用函式多載

Unity to Cocos

Getter / Setter


C# 在撰寫 Getter/Setter 時很彈性
加上 Block 的完整寫法可以自由加入 get 或 set
TypeScript 則是要明確指明為 Getter 或是 Setter
不過也只是寫法需要習慣一下,並沒什麼特別

Unity to Cocos

容器 - Collections


TypeScript 預設的容器只有 Array
但在 Unity C# 我們應該還蠻常會使用到 List、Dictionay、Queue 的
雖然 TypeScript 沒有,但好在已經有現成的程式庫可供使用
安裝完 NPM Package 即可進行使用,詳細點以下儲存庫
https://github.com/basarat/typescript-collections

Unity to Cocos

Linq

TypeScript 並沒有相對應 Linq 的查詢語法
不過相對 Linq 核心的 IEnumerator Extension Methods 幾乎都有對應
有些 Linq 方法如 Distinct,轉換成 TypeScript 會變得較冗長
但大部分都還算簡短,詳細請見
https://decembersoft.com/posts/typescript-vs-csharp-linq/

Unity to Cocos

Unity to Cocos

Delegate

TypeScript 下並沒有與 C# event 一模一樣的機制
雖無法使用疊加 += 進行託管
但是可以使用類似 Lamda 的匿名函式直接進行指派
對於只有隔一層的類別要進行溝通還是蠻方便的

Unity to Cocos

Unity to Cocos

Graphic Binding


Graphic Binding,或是稱 Asset Binding
指的是如何將編輯器中已經拉好的元件 Reference 綁定到程式中
在 Unity 大家熟知的就是使用 SerializeField 這個 Attribute
而 Cocos 也有類似的功能,叫 property 的 Decorator

Unity to Cocos

TypeScript Decorator


TypeScript Decorator 和 C# Attribute 功能十分類似,寫法十分簡潔
都是實現 Meta-Programming 的一種方式
將程式碼本身當作資料,進一步的操作

不論是 Unity 的 [SerializeField] attribute
或是 Cocos 的 @property decorator
都是把我們所宣告出來元件,在引擎編輯器中做了額外處理後
開發者才能夠在 Inspector 中看到這些欄位並進行元件的拖拉綁定
只是 TypeScript 的 Decorator 其實還在實驗階段
所以可以在 jsconfig.json 下看到 experimentalDecorators = true

Unity to Cocos

Property Decorator

要創建一個自訂的 Decorator 其實並不難
其實就是寫一個函式,而每種 Decorator 會有固定的寫法格式
以 Property Decorator 為例,參數會有一個 target 和 propertyName
實際上使用時就可以直接用 @函式名稱,就能夠開始進行 meta-programming 了

Unity to Cocos

Graphic Binding - Components

在 Cocos 下,你可以像 Unity 一樣將基本元件如 Sprite、Label 進行拖拉綁定
容器的話可以使用 Array,而自定義元件只要是繼承自 cc.Component
就像 Unity 繼承自 MonoBehaviour,就同樣可以加上 @property 後再進行拖拉綁定

Unity to Cocos

Unity to Cocos

Unity to Cocos

生命週期 - LifeCycle

基本上 Cocos 的 cc.Node 跟 Unity 的 GameObject 生命週期是一樣的
但 Unity 的會複雜很多,而 Cocos 名稱稍有不同,Awake 變成是 onLoad

Unity to Cocos

常用元件 - Components

常用的 2D 元件大概就是以下這些,在 Unity 下的 Image、Sprite、Text
到了 Cocos 變成 Sprite、SpriteFrame、Label
除此之外,Cocos 還多了一個叫 Prefab 的型別
動畫部分 Cocos 並沒有 Animator 元件,但有 Unity 早期的 Animation 搭配 AnimationClip 可以使用

Unity to Cocos

漸變 - Tween

在 Unity AssetStore 最廣泛被使用的 Tween 應該是 DOTween
而 Cocos 下也有相對應的 cc.Action 和 cc.Tween 可以使用
官方是推薦使用後來推出的 cc.Tween
跟 DOTween 一樣是採用鍊式寫法 (Method Chaining)
同樣也有 Sequence 可以將各種 Tween 進行組合

Unity to Cocos

單例 - Singleton

這邊的 Singleton 指的是在 Cocos 下的,也就是繼承自 cc.Component 的
寫法十分簡單,只要在 onLoad 下將 this 指派給宣告為 static 的自身即可

Unity to Cocos

事件 - Event

事件部分 Cocos 是採用冒泡事件流
如果有使用過時代的眼淚 - Flash 的朋友應該會有感覺是類似的機制
甚至連 stopPropagation 函式名稱也一樣
這個機制就是說在同一個節點樹下
只要我是你的爸爸 (parent),你發事件出來我就收得到

Unity to Cocos

自定義事件 - Custom Event

利用冒泡事件流搭配 Cocos 原本提供的自定義事件類別 cc.Event.EventCustom,我們可以稍微包裝一下
將自定義事件透過類別名稱的方式來識別與發送
事件的監聽與發送直接使用 cc.Node 下的 on 和 dispathEvent 函式即可
詳細請見下圖程式碼,這邊就不再多加贅述

Unity to Cocos

結構 - Struct

C# Struct 應該是在轉移過程中容易踩到的一個坑
TypeScript 並沒有相對於 Struct 的型態,只有 Class
但 Struct 一個重要特性就在於傳遞時會自動複製一份
當你當參數傳遞或是使用 Linq 的 ToList,都會再做一次複製
而不會修改原本的 (Pass-by-Value)。

以筆者踩到的坑來說,原本在 Unity 下使用的 Vector2Int
到了 Cocos 下會是 cc.Vec2,但型態一個是 Struct,一個則是 Class
如果想要達到一樣的 Pass-by-Value 效果,需要進行 DeepClone
但你還是要去檢視所有用到的,這部分改起來稍微比較累一點

Unity to Cocos

Demo - Details

筆者稍微分享轉移的一些細節,剛剛講的大部分針對第 2 和第 3 點
第 1 點是說在實際轉移過程中,你把你原本寫好的 C# 類別全部複製過來
進行第一次的基礎轉換,比方說 import、函式宣告等
而比較複雜的函式內容,大可以先註解掉
比方說比較繁瑣的動畫,先測試到畫面能夠正常顯示就可以了

之所以要全部複製過來再做註解,主要是怕遊戲邏輯會漏搬
所有程式碼都做完初步轉移後,再把註解打開進行第二階段轉移
這樣應該會是最完整也最快的方法,畢竟減少了幾次人工 Context Switch 的時間

Unity to Cocos

小結 - Summary

以結論來說從 Unity 轉移一個簡單的 2D 小遊戲到 Cocos 上沒什麼問題
主要是 Cocos Creator 既然改成像 Unity 一樣 Component-Based 的結構
而且介面元件你用起來會覺得十分熟悉
所以你只要確認遊戲中的 Data Structure (C# => TypeScript)
以及遊戲引擎元件 (Unity => Cocos) 都能夠進行轉移後,就可以開始動工了

轉移過程筆者感覺好像回到過去在寫 Flash 的 ActionScript 3.0,其實語法真的很像
另外一個很有感的則是突然都不用再等編輯器編譯完其實還真的蠻爽的
以上,希望對有要從 Unity 轉移到 Cocos 的朋友有幫助。

Unity to Cocos




歡迎您留言與分享!(Welcome for comments or sharing!)

Related Post:

Tagged on: ,