🪷 Cocos Creator 3.x 純代碼驅動 UI 常見陷阱排錯
背景
佛心項目使用全 code-driven 方式建立 UI(無 Editor 綁定),new Node() + addComponent(Label) 動態生成。這種方式容易遇到幾個 Cocos 3.x 特有的坑。
必檢查清單(按優先級)
1. ✅ Layer 必須明確設置為 UI_2D
動態 new Node() 預設的 layer 是 DEFAULT(即 3D 層),會被 Main Camera 以 3D 方式渲染,導致 UI 文字變成暗黑/灰色剪影。
const UI_2D_LAYER = 1 << 25; // 33554432
const myNode = new Node('MyText');
myNode.layer = UI_2D_LAYER; // ← 每個動態 UI Node 都必須加!
重要: 子節點不會繼承父節點的 layer!每個 new Node() 都要單獨設置,即使父節點已經是 UI_2D。
2. ✅ 所有 Label 必須加 useSystemFont = true
動態生成的 Label 如果沒有指定 font asset,可能完全不會渲染文字(顯示為空白或暗黑)。
const label = node.addComponent(Label);
label.string = '文字內容';
label.useSystemFont = true; // ← 必須加!
label.fontSize = 20;
3. ✅ Label.color 必須用 new Color(r, g, b, a) 直接賦值
Color.fromHEX() 在 Cocos 3.8.8 中可能有不穩定的問題。最穩妥的寫法是直接使用 new Color() 實例化。
// ✅ 正確 (強烈推薦)
label.color = new Color(255, 255, 255, 255); // 純白
label.color = new Color(255, 215, 0, 255); // 金色
// ❌ 可能失敗
label.color = this._hexToColor('#FFFFFF');
// ❌ 絕對錯誤 — 不能直接賦值 hex string
label.color = '#FFFFFF';
4. ⚠️ 場景 JSON 不可手寫 — 極高風險!(2026-06-03 Update)
Cocos 3.x 的 .scene JSON 是一個 flat array,使用 array index 作為 implicit __id__。這意味著:
- ✅
__id__值必須為null(不能用數字) - ✅ 位置
[i]的 object 就是__id__: i - ✅
__id__指向另一個 object 時,值是 array index(如"__id__": 2表示 array[2]) - ✅ 最大
__id__reference 值必須 < array length
極常見錯誤:手寫 custom script component
錯誤寫法(自定義 type name + __scriptAsset__):
{
"__type__": "GameBootstrapper", // ❌ 錯誤!Cocos 不認
"node": { "__id__": 2 },
"__scriptAsset__": { "__uuid__": "..." } // ❌
}
正確寫法(cc.Script + _scriptAsset):
{
"__type__": "cc.Script", // ✅ 必須用 cc.Script
"_name": "GameBootstrapper",
"node": { "__id__": 2 },
"_scriptAsset": { // ✅ 用 _scriptAsset(底線)
"__uuid__": "df04b42a-..."
},
"_id": "zen-bootstrapper-001",
}
Array index (id) 規則(真實案例):
- Array 長度 17 個 entries (index 0-16)
- Canvas node 的
_components[]指向__id__: 5(UITransform)、__id__: 6(Canvas) - 如果你要加第三個 component(GameBootstrapper),必須用
__id__: 16(因為 index 16 是最後一個 entry) - 用
__id__: 17會 crash —Cannot read properties of undefined (reading '__type__')
正確做法(按優先級):
- 🥇 完全避開 Scene JSON — 用純 code-driven:
new Node()+addComponent(GameBootstrapper)動態掛載(Cocos auto-mount pattern) - 🥈 用 Editor 操作 — Add/Remove node/component(最安全)
- 🥉 完整重建 scene JSON — 只用喺極端情況,嚴格遵守
cc.Scriptformat 同 array index 規則
錯誤做法:
- ❌ 用
patch()編輯.sceneJSON — escaped quotes (\\\") 會 corrupt 檔案 - ❌ 從 JSON array splice 刪除元素 — 後面所有
__id__錯位 - ❌ 自定義
__type__名稱(非cc.Script)— deserializer 會 crash - ❌ 用 python
json.dump保留__id__的 numeric value — 必須設為null
5. ✅ Scene cache 問題
直接修改 .scene 檔案後,Cocos Editor 可能仍使用 cache,導致「Load current scene data failed」錯誤。
解決方法: 關閉並重開 Cocos Creator(File → Quit → 重新打開 project)。
6. ✅ 強制 TypeScript 重新編譯
修改 .ts 檔案後如果 Play mode 不生效,可能因為 Editor 未觸發重新編譯。
強制刷新方法:
- Developer → Compile(手動觸發)
- 或者 Save Scene(Command+S)後等待自動 compile
- 或者 Build 任意平台來觸發完整 compile
- 查看 Console Panel 是否有紅色錯誤
完整範例:一個正確的 code-driven Label
import { _decorator, Component, Node, Label, Color, UITransform } from 'cc';
const UI_2D_LAYER = 1 << 25;
export class MyUI extends Component {
start() {
const root = new Node('MyRoot');
root.layer = UI_2D_LAYER;
this.node.addChild(root);
const labelNode = new Node('MyLabel');
labelNode.layer = UI_2D_LAYER; // ← 每個子節點都要
root.addChild(labelNode);
const label = labelNode.addComponent(Label);
label.string = '清晰可見的文字';
label.useSystemFont = true; // ← 必須
label.fontSize = 24;
label.color = new Color(255, 255, 255, 255); // ← 用 new Color()
}
}
排錯流程(按順序)
- Layer 檢查 — 所有
new Node()有冇layer = UI_2D_LAYER? - Font 檢查 — 所有 Label 有冇
useSystemFont = true? - Color 檢查 — 所有
.color =係咪用new Color(r, g, b, a)? - Scene 檢查 — 有冇手動改過
.sceneJSON 的__id__? - Cache 檢查 — 有冇試過重開 Cocos Creator?
- Compile 檢查 — Console 有冇 compile error?
佛心項目特殊備註
- 背景色使用深黑
#0A0A12(對應 RGBA: new Color(10, 10, 18, 255)) - 金色
#FFD700(對應: new Color(255, 215, 0, 255)) - 純白文字
#FFFFFF(對應: new Color(255, 255, 255, 255)) - Button 背景方塊:
new Color(40, 40, 80, 220)