加載與避坑指南)
簡介這是一份圍繞Cocos Creator打造“大廳多個子游戲”整合模式的實戰(zhàn)筆記demo適合需要搭建多玩法入口、獨立熱更子游戲或模塊化游戲項目的開發(fā)者參考。壓縮包共64個文件以js腳本為主輔以json配置、meta資源描述、fire場景文件、png/jpg圖片素材、ttf字體及bat工具腳本整體僅7.09MB便于快速下載與對照學習。已有943人學習下載。資源演示了大廳作為子游戲入口的設計思路覆蓋場景切換、事件監(jiān)聽、資源動態(tài)加載、獨立子游戲熱更新、性能優(yōu)化與打包發(fā)布等關鍵環(huán)節(jié)目錄按大廳、子游戲及工具模塊劃分配合Readme閱讀可更清晰理解整包集成與獨立更新兩種模式的區(qū)別。適合希望從零搭建或重構多游戲整合框架的Cocos Creator開發(fā)者作為梳理流程、調試排錯和發(fā)布部署的參照。1. CocosCreator大廳子游戲整合先解決怎么把多個項目裝進一個App做休閑游戲或互動內容集的人大概率會在某一天收到這樣的需求手里已經有三五個獨立跑好的小玩法突然要合成一個“大廳 子游戲”的 App或者你想做一個類似內置小游戲集的產品主界面是兩排卡片點進去玩一局退出還能回到大廳。CocosCreator 里最省事的做法是把所有場景和資源塞進同一個主包但子游戲一多主場景越來越重首屏冷啟動越來越慢任何一個子游戲的小改動都要全量發(fā)版成本很快失控。這篇筆記不是一個泛泛的教程而是順著一個 CocosCreator 大廳子游戲 demo 的項目整合路徑走一遍怎么按 Bundle 拆分大廳和多個子項目、運行時動態(tài)加載、退出卸載、事件通信以及不跑一遍根本想不到的坑。適合準備把現有單場景工程改造成多子游戲架構的開發(fā)者看。2. 架構選型為什么“大廳 子項目”不是把多個項目硬塞進一個包2.1 Asset Bundle 是整合的基石先搞清它是誰Asset Bundle 是 CocosCreator 做資源按需加載的單元。每個 Bundle 在被構建后會生成獨立的資源清單和配置運行時通過assetManager.loadBundle加載。做大廳 子游戲的項目整合本質就是把子游戲相關的場景、預制體、貼圖、聲音、腳本代碼全部收進各自獨立的 Bundle 中大廳只保留最精簡的主包資源。這樣首包體積不會跟著子游戲數量漲進入子游戲時才拉取對應包體退出后還能釋放內存。在工程里配置 Bundle 其實很簡單對一個文件夾右鍵選擇“配置為 Bundle”然后在屬性檢查器里給它起名。名字很關鍵代碼里loadBundle(subgame1)用的就是這個名字。CocosCreator 在構建時會把這個文件夾里的資源按依賴關系抽離到獨立的 Bundle 目錄同時生成一份 Json 記錄資源 uuid、路徑和依賴表。這里有個容易忽略的點Bundle 不光是美術資源腳本代碼也會跟著走。正因為 Bundle 連代碼都能帶你才能做到“子游戲的邏輯只在你進入子游戲時才加載”。CocosCreator 的 Bundle 和純 C 或其他傳統(tǒng)前端里的模塊加載不太一樣它有自己的一套依賴追蹤和釋放策略。你在編輯器里看到的了一個文件夾構建后可能被拆成多個依賴層級這也是為什么要強調“邊界”這件事。提示Bundle 不是熱更新專屬機制。不配遠程服務器它也能作為本地按需加載的模塊使用。demo 階段可以完全跑在本地后面接熱更只需把 Bundle 的版本和遠程地址配好即可。2.2 子游戲的邊界哪些該進自己的 Bundle哪些必須共享一個干凈的子游戲 Bundle 邊界應該是自包含的子游戲專屬的場景、腳本、UI、交互循環(huán)都放在自己的 Bundle 里公共資源比如大廳風格、通用按鈕、工具函數庫放在一個公共 Bundle 或主包。如果子游戲 A 的資源被子游戲 B 引用要么把這兩段資源收進公共包要么接受重復打包別在運行時嘗試去另一個 Bundle 里找資源那樣會引入加載順序依賴非常容易踩到“資源找不到”的問題。對于“大廳 子游戲”這種常見玩法我習慣這樣劃邊界大廳本身一個常駐場景直屬大廳的 UI、通用組件放到一個 Common Bundle或者直接保留在主包里。每個子游戲一個獨立 Bundle入口是一個全屏 Prefab 或者一個獨立子場景。前者更方便因為大廳節(jié)點不用被切換掉后者適合子游戲內部自帶多個場景的玩法。子游戲依賴的公共數據、SDK 對接層、網絡請求等抽到commonBundle 并讓多個子游戲依賴。不要在每個子游戲里分別復制一份否則包體和代碼量會翻倍。還有一條經驗是越早約定“Bundle 不能跨引用”越好。編輯器里拖拽資源非常順手大廳預制體上隨手引了一個子游戲的貼圖構建時這張貼圖就會被算進主包依賴主包就被撐大了。這種錯誤構建時不報錯只在后面看包體占比時才嚇你一跳。后面避坑章會專門再講。2.3 對比整包方案為項目整合付出架構成本值不值整包和 Bundle 方式最直觀的區(qū)別可以用下面這個表來看對比維度整包集成大廳 子游戲 Bundle首包體積會隨子游戲數量線性增大首包只包含大廳公共部分首次加載冷屏要等全部資源只等大廳子游戲進入時再加載發(fā)版效率改個子游戲也要全量發(fā)版子游戲 Bundle 可以獨立更新內存壓力所有子場景資源常駐退出子游戲時手動釋放工程復雜度低需要處理加載順序和生命周期結論很直接如果只是兩三個休閑玩法的教學 demo整包來得省心但只要有“多個子項目后續(xù)還會繼續(xù)加”的情況建議首次就把 Bundle 架構立起來。項目整合越晚做拆分成本越高。我見過很多團隊一開始用整包頂著后來游戲多了想改大廳子游戲架構結果要動所有場景引用關系幾乎沒有后悔藥。等架構定了我們再來看 demo 怎么落地。實際跑代碼之前先把幾種加載模式區(qū)分開大廳直接通過loadBundle按需拉包是最常規(guī)的做法如果子游戲之間有切換比如從子游戲 A 直接進入子游戲 B大廳要先把 A 的資源釋放再加載 B。這個順序控制好了整個項目整合就算成了八成。3. 搭一個最小 demo在大廳里動態(tài)加載子游戲3.1 demo 工程結構三塊東西不要混在我寫代碼前先把工程分層擺出來。假設一個最簡單的演示有大廳和兩個子游戲assets/ hall/ // 大廳主場景和 UI scenes/ Hall.scene scripts/ HallManager.ts subgames/ sub1/ // 子游戲1這個 Bundle prefab/ SubGame1.prefab scripts/ SubGame1Root.ts res/ ... sub2/ // 子游戲2這個 Bundle prefab/ SubGame2.prefab scripts/ SubGame2Root.ts common/ scripts/ EventBus.ts GameDef.ts操作上在assets/subgames/sub1文件夾右鍵選擇“配置為 Bundle”Bundle 名稱填subgame1。sub2同理。兩個文件夾里的資源在構建時會各自獨立打包。hall文件夾不設成 Bundle所有資源直接進主包方便冷啟動。這里有一個參數值得強調Bundle 配置面板里的“目標平臺”可以單獨控制比如你只想讓subgame1打進微信小游戲包而subgame2只用于原生平臺構建配置里可以分開勾選。demo 階段不用管這個但要知道有這個能力因為大廳 多子項目的項目整合經常需要應對多端發(fā)布。每個子游戲最好都只有一個入口 Prefab這樣大廳加載時只需面對一個統(tǒng)一路徑。如果子游戲內部還有多個場景切換由子游戲自己管理大廳不感知。大廳負責的是“把子游戲的入口節(jié)點掛到自己的場景下”“退出時把它從場景移除”。把耦合限制在這兩個動作上后期新增子游戲就只需要加一個 Bundle 配置和一個入口按鈕映射。3.2 用 Bundle 動態(tài)加載子游戲最小代碼先實現最直接的流程點擊大廳列表里的按鈕加載subgame1這個 Bundle然后從 Bundle 里取出SubGame1.prefab掛到大廳場景下。import { _decorator, Component, Node, Prefab, assetManager, instantiate } from cc; export default class HallManager extends Component { currentNode: Node | null null; enterSubGame(bundleName: string, prefabPath: string) { assetManager.loadBundle(bundleName, (err, bundle) { if (err) { console.error([Hall] loadBundle ${bundleName} failed:, err); return; } const prefab bundle.get(prefabPath, Prefab); if (!prefab) { console.error([Hall] prefab ${prefabPath} not found in bundle); return; } this.currentNode instantiate(prefab); this.currentNode.setParent(this.node.parent ?? this.node); }); } exitSubGame() { this.currentNode?.destroy(); this.currentNode null; } }邏輯很簡單assetManager.loadBundle是入口回調成功表示 Bundle 已經加載bundle.get直接從已加載的 Bundle 里拿資源。注意instantiate(prefab)出來后掛到大廳 Node 的父節(jié)點下這樣預制體內部的start會被觸發(fā)。按鈕的click事件綁定時傳入兩個字符串參數比如(subgame1, prefab/SubGame1)。參數說明loadBundle的bundleName必須和構建 Bundle 時的名字一致默認是文件夾名prefabPath是相對 Bundle 的路徑不包含assets/前綴。bundle.get只適合 Bundle 已經確認加載完的情況如果加載過程還沒結束get拿不到資源所以更穩(wěn)妥的是用bundle.load。示例里沒有做加載失敗重試實際項目會封一層管理器下面繼續(xù)。3.3 用統(tǒng)一的 SubGameManager 管理“進入/退出”狀態(tài)只寫上面的方法雖然能跑但大廳里同時多點幾個入口或者重復進入同一個子游戲會出現多個節(jié)點疊在一起、事件互相干擾的情況。我習慣把入口邏輯收攏成一個管理類維護“當前是否有子游戲在運行”的狀態(tài)import { _decorator, Component, Prefab, Node, assetManager, instantiate } from cc; type LoadDone (node: Node) void; export default class SubGameManager extends Component { public currNode: Node | null null; public currentBundleName: string ; enterGame(bundleName: string, prefabPath: string, onDone?: LoadDone) { if (this.currNode) { console.warn([SubGameManager] 已經有子游戲在運行先退出再進入); return; } assetManager.loadBundle(bundleName, (bundleErr, bundle) { if (bundleErr) { console.error(加載 ${bundleName} 失敗, bundleErr); return; } bundle.load(prefabPath, Prefab, (loadErr, prefab) { if (loadErr) { console.error(加載 ${prefabPath} 失敗, loadErr); return; } const node instantiate(prefab); node.setParent(this.node); this.currNode node; this.currentBundleName bundleName; onDone onDone(node); }); }); } exitGame() { if (!this.currNode) return; this.currNode.destroy(); this.currNode null; this.currentBundleName ; } }相比最小示例這里用currNode記錄當前子游戲防止重復進入用bundle.load而不是bundle.get規(guī)避了“資源未加載完”的窗期。這個管理器掛在 Canvas 下的一個常駐空節(jié)點上子游戲 Prefab 都作為這個空節(jié)點的子節(jié)點這樣即使大廳 UI 切換層級子游戲層和大廳層也能保持邏輯隔離。在enterGame里還有個細節(jié)成功回調里做node.setParent(this.node)this.node就是管理器節(jié)點的引用。因為this是管理器的組件實例this.node才是場景樹上的節(jié)點。如果你把管理器掛在大廳根節(jié)點上那子游戲就是大廳根節(jié)點的直接子節(jié)點退出時要不要恢復層級要看你的設計。這里我選擇獨立掛載規(guī)避一層耦合。4. 項目整合中的通信與生命周期不處理好進入退出兩三次就會出鬼4.1 用事件總線打通大廳與子游戲大廳和子游戲各自獨立不能直接拿著對方的組件引用來調用方法否則會形成強耦合。常見做法是掛一個全局事件總線。子游戲要向大廳匯報分數發(fā)出事件大廳監(jiān)聽事件并更新 UI。一個極簡事件總線可以這樣寫import { EventTarget } from cc; const bus new EventTarget(); export function onEvent(name: string, callback: (payload?: any) void) { bus.on(name, callback); return () { bus.off(name, callback); }; } export function emitEvent(name: string, payload?: any) { bus.emit(name, payload); }EventTarget是 CocosCreator 自帶的簡單事件目標不需要引第三方庫也沒有平臺差異。用onEvent返回的 off 函數可以在子游戲銷毀時解綁防止回調泄漏。如果你是第一次寫這種跨模塊通信建議把事件名定義成枚舉放進common/scripts/GameDef.ts比如export enum GameEvent { SUBMIT_SCORE SUBMIT_SCORE, GAME_EXIT GAME_EXIT, }這樣做的好處是子游戲內發(fā)事件時如果拼錯字符串TypeScript 編譯階段就會報錯而不是運行時靜默丟掉。另一個隱藏收益是編輯器全局搜索方便重構事件名時可以快速定位所有引用處。事件總線的邊界要克制。如果大廳和子游戲之間交互特別密集比如子游戲內有個進度條要實時同步到大廳那就不要把每個進度都發(fā)到全局總線否則總線會變成黑匣子。更好的做法是子游戲進入時大廳把可以用于同步的UIProxy傳給子游戲根節(jié)點子游戲內部通過這個代理更新 UI而不是發(fā)事件。職責劃分上總線適合一次性的“結果通知”代理適合持續(xù)性的“狀態(tài)同步”。4.2 子游戲退出時只銷毀節(jié)點是不夠的子游戲節(jié)點被destroy()后它下面所有組件的onDestroy會執(zhí)行但不會自動替你恢復大廳 UI 的狀態(tài)。比如子游戲全屏 UI 把主廳 UI 蓋住了退出時大廳停留在進入前的狀態(tài)這沒問題。問題在別處子游戲里的定時器、Tween、網絡輪詢、全局事件監(jiān)聽稍微不干凈就會殘留在大廳進程里。一個健壯的子游戲入口組件通常會顯式做清理import { _decorator, Component, Node, Tween } from cc; import { offEvent } from ../common/EventBus; import { GameEvent } from ../common/GameDef; export default class SubGame1Root extends Component { private offFuncs: Array() void []; onLoad() { this.offFuncs.push(offEvent(GameEvent.SUBMIT_SCORE, this.onSubmitScore)); this.scheduleOnce(() { // 子游戲自己的開機初始化 }, 0.1); } onDestroy() { this.offFuncs.forEach(f f()); this.offFuncs.length 0; Tween.stopAllByTarget(this.node); } private onSubmitScore(score: number) { // 往大廳上報分數 } }關鍵點在于將所有需要解綁的監(jiān)聽器統(tǒng)一收進數組在onDestroy里一起解除。如果用EventTarget的on就必須持有off引用別在onDestroy里去寫bus.off(SUBMIT_SCORE, 一個匿名函數)那會失效因為每次聲明匿名函數都是新的引用。Tween.stopAllByTarget(this.node)能停掉針對該子游戲根節(jié)點的所有緩動防止動畫殘留在舞臺上。setInterval這類全局定時器也必須記得清掉。你可以把setInterval返回的句柄存在組件的私有屬性里在onDestroy里調用clearInterval。有些開發(fā)者覺得子游戲節(jié)點銷毀了定時器就會自動消失但實際不是這樣——定時器是全局的和節(jié)點生命周期沒有綁定。跑一次進入退出循環(huán)如果你在 Console 里看到節(jié)點無法釋放或內存增長先檢查定時器。4.3 退出子游戲時清掉 Bundle 里的資源緩存但要小心公共資源恭喜你到了項目整合里最容易出對錯的一個點。assetManager.loadBundle把 Bundle 加載進來之后它會對 Bundle 內的資源建立緩存bundle.releaseAll()能釋放所有屬于該 Bundle 的資源。理論上“退出子游戲并釋放 Bundle”是最理想的內存回收方式。但是這里有個細節(jié)如果子游戲 Bundle 里引用了commonBundle 里的某個公共 SpriteFrame 或字體releaseAll()會把它引用到的公共資源也一起釋放導致其他 Bundle 也使用該公共資源時出現“資源為空”或黑圖。正確做法是先確認依賴關系。在 CocosCreator 里可以用bundle.getDependencies()查看依賴的資源 uuid再決定哪些該 release 哪些不該動。我一般用“引用計數”思維做不直接對 Bundle 調用releaseAll()而是把未共享的資源顯式釋放把公共資源留在公共 Bundle 里讓它在整個生命周期內不因子游戲退出被錯誤銷毀。demo 階段最簡單的是退出時只看節(jié)點銷毀不做內存管理。等真正上生產再按下面的exitGame增強版處理exitGame() { if (!this.currNode) return; const bundle assetManager.getBundle(this.currentBundleName); this.currNode.destroy(); this.currNode null; if (bundle) { bundle.releaseAll(); assetManager.removeBundle(bundle); } }這行代碼寫起來很爽跑起來如果你沒有公共資源引用也沒問題。萬一你遇到了子游戲退出后公共 UI 丟貼圖就是它干的。真遇到那種情況把releaseAll改成只釋放部分資源或者在關閉子游戲時暫時不removeBundle把它留在內存里供下一次快速進入。這個權衡需要結合你子游戲的數量和內存預算不是越傾向釋放越好。5. 項目整合避坑這5個問題我踩過你最好提前知道5.1 加載了子游戲 Prefab但屏幕還是空的現象進入大廳點擊按鈕控制臺沒有任何報錯或者只打了一個“加載成功”但是屏幕上看不到子游戲任何元素。原因這個坑十有八九是子游戲 Prefab 的父節(jié)點不對。如果你的大廳是一個全屏節(jié)點而子游戲 Prefab 掛到大廳這個節(jié)點底下并且子游戲內部坐標計算受父節(jié)點UIOpacity、Scale影響可能被縮放成 0 或透明也或者掛到了一個隱藏節(jié)點下面看起來就是“沒出來”。解決先在大廳代碼里給當前節(jié)點設置一個可視標記比如把currentNode.parent設成 Canvas 節(jié)點下的一個專門“子游戲層”別掛在大廳 UI 的某個按鈕下面。另外檢查 Prefab 根節(jié)點的active是否為 true。CocosCreator 的預制體實例默認 active 和編輯器里保持一致如果你在 Prefab 編輯器里掛了隱藏根節(jié)點怎么加載都不會顯示。還想加一道保險就在SubGameManager.enterGame成功回調里強制node.active true。5.2 子游戲資源被打進主包Bundle 白設了現象本地跑的時候一切正常構建以后首包體比你預計的多打開構建產物也沒見子游戲的貼圖資源占比統(tǒng)計里把子游戲資源算到了主包。原因CocosCreator 的 Bundle 打包遵循“資源究竟從哪里被引用”。當大廳場景或大廳里的公共組件直接引用了子游戲 Prefab 的一部分資源比如一個公共圖集、一個腳本常量構建器會認為這個資源是主包依賴于是把它默認復制到主包。這樣子游戲內部確實能運行但主包已經被越界引用撐大了。解決嚴格檢查跨包引用。建議在子游戲開發(fā)階段就約定大廳腳本只通過 Bundle 加載子游戲所有子游戲內部資源都不要在編輯器中拖拽到大廳預制體的屬性上。如果發(fā)現某個 SpriteFrame 被大廳的管理器引用到了把引用改成運行時通過 Bundle 加載或者把該資源轉移到公共 Bundle。這個坑沒有構建報錯只有靠資源管理器的“依賴圖表”來查。5.3 子游戲onLoad被調用兩次或者沒調用現象在子游戲腳本里打console.log(load)第一次進入打了兩遍退出再進又不打了或者反過來第二次進入后子游戲的start一直不觸發(fā)。原因很多是加載姿勢不對。我們用bundle.load拿到同一個 Prefab 再instantiate每次 instantiate 出來的新節(jié)點都會跑onLoad但如果節(jié)點沒有 active 地掛到 Canvas 下而是掛到了一個 inactive 節(jié)點下start不會執(zhí)行onLoad可能延遲或完全不觸發(fā)。另外如果同一個 Prefab 的引用被大廳的多個按鈕同時持有點擊時實例化兩次就會看到兩個onLoad。解決一套嚴格流程是確保 Prefab 節(jié)點最終的父節(jié)點是 active 的并且setParent之后不要立刻對父節(jié)點做destroy。想要防御在子游戲入口腳本的onLoad里加守衛(wèi)判斷一個全局單例是否存在避免重復初始化。比如if (SubGame1State.isLoaded) return; SubGame1State.isLoaded true;這個守衛(wèi)還有一個作用當子游戲被異常重復加載時不至于同時跑兩套游戲循環(huán)。5.4 大廳界面被子游戲遮擋退出后界面錯位現象從子游戲回到大廳大廳原本的排行榜、頭像或彈窗不見了或者坐標整體偏移。原因子游戲 Prefab 通常是全屏的會蓋在大廳 UI 上面這沒問題。問題出在進入子游戲前你手動修改過大廳主 UI 節(jié)點的active或層級退出時沒有恢復。比如enterGame里順手把大廳主 UIactive false但exitGame忘了把active true。解決狀態(tài)保存與恢復要在進入和退出時成對寫。我習慣維護一個SceneUIState對象記錄進入前的節(jié)點active和setSiblingIndex退出時按記錄恢復而不是寫死“大廳 UI 一定存在”的假設。代碼結構類似private savedState: { node: Node; active: boolean }[] []; enterGame() { this.savedState []; for (const uiNode of this.hallUIList) { this.savedState.push({ node: uiNode, active: uiNode.active }); uiNode.active false; } } exitGame() { for (const state of this.savedState) { state.node.active state.active; } this.savedState []; }這樣做能避免“進入子游戲時隱藏大廳退出時又忘記顯示”的低級錯誤。5.5 構建后 Bundle 找不到控制臺報 2048現象構建出來的版本在真機上點擊入口回調函數能執(zhí)行但err非空錯誤碼 2048或者提示Bundle not found編輯器里跑卻正常。原因CocosCreator 的 Bundle 尋址依賴構建后的配置。代碼里assetManager.loadBundle(subgame1)的名字需要和構建面板里的 Bundle 名稱一致大小寫也必須一致。如果沒在構建配置里把該文件夾勾選為“Bundle”或者構建時沒勾選對應平臺都會導致運行時找不到。解決打開構建面板展開“Bundle 配置”確認subgame1和subgame2都被勾選。真機調試時如果用了遠程資源服務器要確保服務器對應目錄有config.json。別前端拿不到資源就猜代碼先用瀏覽器 DevTools 或原生抓包看網絡請求路徑多半是路徑少了斜杠或者域名不對。6. 進階技巧給大廳到子游戲的加載過程加進度和預取進入子游戲如果全都是動態(tài)加載真機從磁盤讀 Bundle 時用戶會看到大廳按鈕點擊后卡一兩秒體驗很差。我最后的建議是把大加載過程拆成“進度條 預取”兩步。先做一個簡單加載面板彈出后開始加載export class LoadingView extends Component { progress: Label; show(bundleName: string, prefabPath: string, done: () void) { this.node.active true; assetManager.loadBundle(bundleName, (bundle) { bundle.load(prefabPath, Prefab, (err, prefab) { if (!err) { done(); this.node.active false; } }); }); } }上面代碼只有回調沒有進度。要顯示進度可以在loadBundle的 options 里帶onProgressassetManager.loadBundle(bundleName, { onProgress: (current: number, total: number) { this.progress.string 加載子游戲 ${Math.floor(current / total * 100)}%; } }, (err, bundle) { ... });不過要注意loadBundle的進度回調是整個 Bundle 資源的加載進度Bundle 內部還有一次loadprefab 的進度想要完整表現需要把兩段進度做串連。實踐中我更推薦另一套在大廳空閑時預取子游戲 Bundle但只加載配置不實例化。比如在首屏 UI 加載完成之后調一次assetManager.loadBundle(subgame1)趁用戶在首頁瀏覽時先把 bundle 拉進內存。等點擊進入時直接從getBundle里取資源速度會快一個量級。預取代碼// 大廳 onLoad 里預取 assetManager.loadBundle(subgame1, (err, bundle) { if (!err) { // 只是為了緩存 bundle節(jié)點先不實例化 console.log([Hall] subgame1 ready); } }); // 點擊時 const bundle assetManager.getBundle(subgame1); if (bundle) { const prefab bundle.get(prefab/SubGame1, Prefab); this.instantiateSub(prefab); }預取要注意兩點一是別在首屏onLoad里預取所有子游戲那樣首屏還是會變慢建議只預取第一個入口或用戶最常進的那一個。二是內存預算。預取占用的內存高峰期疊加如果你在低端機上跑需要根據占用狀況主動釋放不再需要的 Bundle。CocosCreator 提供assetManager.getDependencyStat可以打資源統(tǒng)計我上線前會通過它觀察整包內存分配。說個我自己的習慣每次新增子游戲時都要反復確認“大廳入口、加載路徑、退出清理”三件事能不能在 3 步內 trace 通。trace 不通就說明邊界設計有問題真正多子游戲上線出問題的往往不是加載邏輯而是狀態(tài)殘留。項目整合做的是工程結構長期賬別圖一時方便而放棄結構上的清晰邊界。希望這個筆記對你的 CocosCreator 大廳子游戲 demo 有些幫助踩過的坑你已經提前知道了。本文還有配套的精品資源點擊獲取