GodotWebGLWebAssemblyGame DevelopmentOptimization

Godot 4 Web 匯出怎麼檢查:執行緒、檔案大小、載入與聲音

··閱讀約 6 分鐘

Godot 的桌面版本能玩,Web 版本卻停在載入畫面,先別急著重編整個引擎。需要先分清楚:檔案是否正確送達、匯出是否需要跨來源隔離,以及遊戲是否已經開始執行。這三種問題的修法不一樣。

本文以本站 Last Pitch Derby 在版本 4a7aec3 的設定與已提交檔案為例。2026-09-21 重新量測大小並檢查載入程式,沒有重跑 iPhone 效能測試。舊文未附依據的流失率、秒開與 35 MB 壓到 8 MB 說法已撤下,以下只保留能重做的檢查。

先看自己的匯出設定

本站 export_presets.cfg 的 custom_template/release 為空,variant/thread_support 與 variant/extensions_support 都是 false。因此這個案例不能拿來證明「自行裁剪模板」的成效,也不能拿來宣稱所有 Godot 4 遊戲都需要相同標頭。先記錄編輯器、匯出模板與這兩個開關,再查相符版本的文件。

ini
custom_template/release=""
variant/extensions_support=false
variant/thread_support=false

Godot 官方文件說明,啟用 Thread Support 或 Extensions Support 才會帶來相應的跨來源隔離要求。若選用這些功能,要檢查正式 HTTP 回應的 COOP/COEP 與嵌入環境;不能只確認專案裡有一份 _headers。單執行緒匯出也仍需實測遊戲與音訊行為。

把壓縮檔、引擎與遊戲資料分開量

這份版本的 index.wasm.gz 是 10,052,173 bytes,解壓後的 WASM 是 39,509,339 bytes;index.pck 是 371,884 bytes。這是固定檔案的大小,不是瀏覽器記憶體,也不是玩家的下載秒數。不同網路、快取、裝置與伺服器設定都會影響等待時間。

javascript
import { readFileSync } from 'node:fs';
import { gunzipSync } from 'node:zlib';
import { createHash } from 'node:crypto';
const root = 'public/games/last-pitch-derby/';
for (const file of ['index.wasm.gz', 'index.pck']) {
  const bytes = readFileSync(root + file);
  console.log(file, bytes.length,
    createHash('sha256').update(bytes).digest('hex'));
  if (file.endsWith('.gz')) {
    console.log('decoded WASM bytes', gunzipSync(bytes).length);
  }
}

把上面程式存成 measure.mjs,在這份版本的專案根目錄執行 node measure.mjs。若你的數字不同,先比對檔案雜湊與版本,不要先推論壓縮工具變好或變差。PCK 主要承載專案資料;如果它變大,應回頭查看素材與匯出篩選,而不是只盯著 WASM。

下載本次檔案大小、雜湊與重做步驟

檔案存在,還要確認載入路徑正確

本站包裝腳本把 WASM 轉成 gzip 檔,產生的 HTML 則攔截 index.wasm 請求,改抓 index.wasm.gz。若伺服器已宣告 Content-Encoding: gzip,載入器不再手動解壓;否則用 DecompressionStream,再以 application/wasm 建立回應。直接把 .gz 改名成 .wasm,並不等於完成這條路徑。

因此灰畫面時,先看 Network 裡 WASM 與 PCK 的狀態、內容與大小。錯誤路徑可能收到 HTML 錯誤頁;載入器也可能收到無法解壓的內容。本站載入程式還要求 DecompressionStream,若瀏覽器沒有這個能力,會明確失敗,這是部署選擇帶來的相容性邊界。

下載完成不等於可以操作

這份 HTML 的 onProgress 使用下載的 current/total;engine.startGame 的 Promise 成功後才隱藏載入提示。它沒有量測「編譯佔 80–95%」或「著色器佔最後 5%」。若拿不到階段進度,顯示「正在啟動」比編一個精確百分比更清楚;要量首個可操作畫面,需另外設計遊戲端訊號。

驗收時記三個時點:請求開始、資料下載結束、第一個輸入確實產生遊戲反應。同一裝置分別做冷快取與暖快取測試,並註明網路條件。這樣才能區分傳輸慢與啟動慢,而不是看到 gzip 變小就宣布遊戲快了四倍。

聲音與手機問題,用可觀察的步驟定位

聲音測試應從重新開啟頁面開始,按一次明確的開始按鈕,再確認音效、背景切換與回到前景的行為。不要透過猜測的 Engine.getAudioContext API 接管引擎,也不要把所有無聲都稱為永久死鎖。先核對目前匯出使用的音訊模式與實際 Console 錯誤。

手機重整或閃退也不能只憑「停在 90%」判定記憶體不足。保留裝置、系統與瀏覽器版本,確認資源完整,再以減少大型貼圖、同時存在的場景或渲染負擔做對照。每次只改一個因素,記下是否仍重現;本文不提供跨所有 iPhone 適用的記憶體上限或音訊 buffer 神奇數值。

發布前留下這份紀錄

至少保留匯出設定、WASM/PCK 雜湊、正式 URL、瀏覽器版本,以及載入、第一個輸入、聲音、切換背景與重新整理的結果。檔案與設定驗證可以在電腦完成;iPhone Safari 是否能玩,仍要由該裝置上的實際操作回答。

參考資料