You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web端Godot优化:多PCK文件如何复用单引擎实例?

问题描述

我正在重构一个原包含Flash游戏的旧网站,用Godot重写了部分游戏,编译Godot源码时禁用了3D物理等不必要模块,当前godot.wasm大小约29MB。但切换游戏时,CPU占用过高会导致页面冻结2-3秒(Mac M2 Max设备),网站有多款游戏,每次加载都会出现这个延迟。

每个游戏都在独立仓库,编译生成单独的PCK文件。我用Vue单页应用(SPA)尝试复用Engine实例避免重复加载Wasm,代码如下:

const engineInstance = shallowRef(new Engine({
  /* ... 我的参数,没有mainPack */
  executable: '/gamesdata/godot',
  fileSizes: {
    '/gamesdata/godot.wasm': 29107076,
  },
}))
const isEngineLoaded = ref(false)
const currentPck = ref(null)

engineInstance.value.init('/gamesdata/godot').then(() => {isEngineLoaded.value = true})

export function useGodot() {
  const loadPck = async (pckPath, canvasElement, sizeOfPck, args = []) => {
    if (!engineInstance.value || !isEngineLoaded.value) {
      throw new Error('Engine not initialized')
    }
    args = ['--main-pack', pckPath, ...args]

    // 加载新PCK
    await engineInstance.value.preloadFile(pckPath, pckPath, sizeOfPck)
    await engineInstance.value.start({
      args,
      canvas: canvasElement.id,
      mainPack: pckPath,
    })
    currentPck.value = pckPath
  }
}

但发现无论如何都必须调用Engine.init(),请问有没有方案可以避免高CPU占用或重复加载godot.wasm?该如何优化?


优化方案

1. 正确复用Godot Engine实例,避免重复初始化

你当前的代码每次调用start()都会重新触发引擎初始化流程,这是CPU飙升的核心原因。正确的复用逻辑应该是:

  • 引擎init()只执行一次,完成后保留实例
  • 切换游戏时先清理当前游戏资源,再加载新PCK启动,而非重复初始化

修改后的核心逻辑示例:

const engineInstance = shallowRef(null)
const isEngineLoaded = ref(false)
const currentGameInstance = ref(null)

// 仅初始化一次引擎
async function initEngine() {
  if (engineInstance.value) return
  engineInstance.value = new Engine({
    executable: '/gamesdata/godot',
    fileSizes: {
      '/gamesdata/godot.wasm': 29107076,
    },
    // 提前禁用非必要模块,降低初始化负载
    args: ['--disable-3d', '--no-window'],
    asyncInit: true // 启用Wasm异步编译,避免阻塞主线程
  })
  await engineInstance.value.init('/gamesdata/godot')
  isEngineLoaded.value = true
}

export function useGodot() {
  const loadPck = async (pckPath, canvasElement, sizeOfPck, args = []) => {
    await initEngine()
    if (!engineInstance.value) throw new Error('Engine init failed')

    // 清理当前游戏资源
    if (currentGameInstance.value) {
      currentGameInstance.value.stop()
      // 把卸载操作放到空闲回调,避免阻塞主线程
      requestIdleCallback(async () => {
        await engineInstance.value.unloadFile(pckPath)
        // 触发浏览器GC,释放闲置内存
        typeof gc === 'function' && gc()
      })
    }

    // 预加载新PCK
    await engineInstance.value.preloadFile(pckPath, pckPath, sizeOfPck)
    
    // 启动新游戏,无需重复调用init()
    currentGameInstance.value = await engineInstance.value.start({
      args: ['--main-pack', pckPath, ...args],
      canvas: canvasElement.id,
      mainPack: pckPath,
    })
  }
}

2. 优化PCK资源加载

  • 预加载高频游戏PCK:在用户浏览网站时,利用空闲时间后台预加载热门游戏的PCK,减少切换时的等待
  • 开启PCK压缩:Godot导出时启用「压缩」选项,缩小PCK体积,降低加载和解压耗时
  • 提取公共资源:把多款游戏共用的UI、音效等资源拆分到独立公共PCK,仅加载一次,避免重复加载冗余资源

3. 进一步裁剪Godot编译模块

除了3D物理,还可以在编译Godot源码时禁用以下非必要模块,进一步降低Wasm体积和初始化开销:

  • 不需要音频的游戏:禁用module_audio
  • 不需要网络的游戏:禁用module_network
  • 不需要编辑器功能:确保编译的是导出模板而非开发版

4. 浏览器层面优化

  • 配置HTTP缓存:确保godot.wasm和PCK文件设置合理的缓存头,避免重复下载
  • 限制Wasm线程数:如果游戏不需要多线程,启动时添加--threads 1参数,减少CPU资源抢占
  • 使用Service Worker:预缓存核心资源,加速后续访问时的加载速度

内容的提问来源于stack exchange,提问作者Sw0ut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 00:33:29