WASM 崩溃

07/292 浏览
nvgCreateImage 在 WASM 环境下无法正确加载图片文件(中文路径/资源未打包进虚拟文件系统),返回看似正数但实际无效的纹理句柄。Lua 中 0/-1 都是 truthy,if 判断通过后把无效句柄传给 nvgImagePattern,C 层访问空指针 → WASM 内存越界。

彻底解决方案:纯矢量绘制,零文件 I/O

完全放弃图片加载,用 NanoVG 基础图元(圆/椭圆/描边)绘制熊猫币图标,不需要任何文件、句柄、资源打包。
关键代码:
lua
-- Desktop.lua:60-65 Init() 中删除 nvgCreateImage,无需加载任何图片 function Page:Init(ctx) self.vg = nvgCreate(1) self.fontId = nvgCreateFont(self.vg, "sans", Theme.FONT_PATH) -- 不再调用 nvgCreateImage,零文件依赖 self._bus = EventBus.New() ... end
lua
-- 纯矢量绘制熊猫币(金色圆+黑耳朵+黑眼圈+白高光+黑鼻子) function Page:_DrawCoinIcon(vg, cx, cy, size) local r = size * 0.5 nvgSave(vg) -- 金色圆币 nvgBeginPath(vg) nvgCircle(vg, cx, cy, r) nvgFillColor(vg, nvgRGBAf(0.95, 0.75, 0.15, 1.0)) nvgFill(vg) nvgStrokeColor(vg, nvgRGBAf(0.75, 0.55, 0.05, 1.0)) nvgStrokeWidth(vg, math.max(1, size * 0.04)) nvgStroke(vg) -- 黑色耳朵 local earR = r * 0.28; local earOff = r * 0.55 nvgBeginPath(vg) nvgCircle(vg, cx - earOff, cy - earOff, earR) nvgCircle(vg, cx + earOff, cy - earOff, earR) nvgFillColor(vg, nvgRGBAf(0.1, 0.1, 0.1, 1.0)) nvgFill(vg) -- 黑色眼圈 nvgBeginPath(vg) nvgEllipse(vg, cx - r*0.28, cy + r*0.05, r*0.20, r*0.26) nvgEllipse(vg, cx + r*0.28, cy + r*0.05, r*0.20, r*0.26) nvgFillColor(vg, nvgRGBAf(0.1, 0.1, 0.1, 1.0)) nvgFill(vg) -- 眼睛白高光 nvgBeginPath(vg) nvgCircle(vg, cx - r*0.28+1, cy + r*0.05-2, r*0.06) nvgCircle(vg, cx + r*0.28+1, cy + r*0.05-2, r*0.06) nvgFillColor(vg, nvgRGBAf(1, 1, 1, 1.0)) nvgFill(vg) -- 鼻子 nvgBeginPath(vg) nvgCircle(vg, cx, cy + r*0.28, r*0.08) nvgFillColor(vg, nvgRGBAf(0.1, 0.1, 0.1, 1.0)) nvgFill(vg) nvgRestore(vg) end
三处调用(HUD / 卡牌底部 / 卡包按钮价格)统一替换为 self:_DrawCoinIcon(vg, cx, cy, size),零判断、零守卫、零崩溃风险。

经验教训

陷阱规避方法
nvgCreateImage 在 WASM 可能返回假有效句柄NanoVG 图标一律用矢量绘制,不加载小图标文件
Lua 中 0/-1 是 truthy判断句柄必须 > 0,但最好的办法是不用句柄
nvgImageSize 在 Lua 绑定中签名不匹配不确定 API 是否绑定时,先查 .emmylua/ 类型定义
中文文件名在 WASM 虚拟文件系统可能失效资源文件一律用 ASCII 命名(显示文字可以中文)