37DATA

pns数字门小游戏转试玩广告实践

背景

https://gevents.37games.com/pnsmathsdoor202410GameLevel/web/index.html?level=0

如url 所示,pns数字门小游戏是用 layaAir 3.1.0 开发好的一款小游戏,通过参数 level 控制不同的关卡,目前总共有 40 关。

现在需要将该小游戏转为海外试玩,海外试玩的要求是:所有资源和代码打包成一个 html,不能有任何外链,且 html文件体积不能超过 5M。

使用 layaAir IDE 构建发布后的小游戏是一个 web文件夹,里边有很多文件,因此,要解决的核心问题就是两个:

  1. 需要将这个 web文件夹转化为一个 html。
  2. 需要确保 html的体积不能超过 5M。

web文件夹转化为一个 html(思路 1)

1、项目构建生成 web 文件夹;

2、遍历web 文件夹,将所有资源处理成一个映射表(如下图所示),其中图片/音频/字体/其他二进制文件都会转为 base64(体积会增大 33%),json 和 js 则序列化以字符串的方式存储;

Image

3、将映射表序列化,借助 jszip等算法进行压缩,压缩后的二进制内容转成 base64 塞进 html(体积会增大 33%),挂载到 window.__zip;

4、运行时解析 base64、解压内容,将资源映射表挂载到 window.__res;

5、获取 js字符串,通过 eval执行,js执行会触发游戏的初始化逻辑,进而触发资源加载;

6、最后一个关键步骤是,需要重写 laya 的资源加载过程,确保从window.__res 中获取资源,而不是走网络请求(这里有很多细节,需要根据资源类型的不同,修改加载和解析过程);

web文件夹转化为一个 html(思路 2,当前也是基于此思路实现)

1、项目构建生成 web 文件夹;

2、整个 web 文件夹借助 JSZip等算法进行压缩,打包成一个 zip包;

3、压缩包也是二进制,转成 base64 塞进 html(体积会增大 33%),挂载到 window.__zip;

4、运行时解析 base64,将 jszip解压的内容挂载到到 window.__res;

5、获取 js字符串,动态创建 script 标签插进 body,触发游戏的初始化逻辑,进而触发资源加载;

6、最后一个关键步骤是,需要重写 laya 的资源加载过程,确保从window.__res 中获取资源,而不是走网络请求(这里有很多细节,需要根据资源类型的不同,修改加载和解析过程,如下代码所示);

自定义加载和解析资源

Image

html的体积优化过程(这里是已走通的优化记录,还有一些未走通的不再赘述,见下边的思路总结)

未优化前:web 16.5M,单 html 文件 14M

从资源体积占用来看,laya引擎、路面图片、主角模型,三者加起来就占到 56.1%,因此这里是优化的重点。

Image

优化 :所有图片进行 tiny 压缩

web 文件夹 14.4M,单 html 11.2M

优化 :路面图片只保留一张最小的 322KB

web 文件夹 12.2M,单 html:8.67M

优化 :路面图片改为小图拼接【经验:很多大图可以通过小图平铺、变换、九宫格裁剪等方式实现】

web 文件夹 11.9M,单 html:8.31M

优化:.lm 网格文件勾选网格压缩(网格是 3D模型的组成成分)【3D 模型的压缩办法之一】

web 文件夹 10.4M,单 html:7.25M

优化:删除 resources 文件夹中的冗余文件5M_China_vase.lm和T_Misc_prop.jpg

web 文件夹 10.2M,单 html:7.08M

优化: 继续删除 resources 文件夹中的冗余文件LN_LOW、UI/lu.jpg、木桶/蓝色图【经验:只有脚本动态加载的资源才能放resources 文件夹,因为 laya打包构建时,不管资源有没有用到,只要在resources文件夹内,都会复制过去;这里两次清除冗余文件,html直接减了1.65M】

web 文件夹 9.16M,单 html:5.6M

优化 :丧尸只用一种【经验:不影响视觉效果时,可以对内容展示进行精简】

web 文件夹 8.8M,单 html:5.35M

优化:木桶、数字门、升级特效中的模型,fbx 压缩网格和压缩动画数据【3D 模型的压缩办法之二】

web 文件夹大小 8.49M,单 html:5.29M

优化:删除 boss 中没有用到的动画 + 丧尸也有一份冗余动画

web 文件夹大小 8.26M,单 html:5.15M

优化:使用LOD减面插件,对boss网格进行减面,尝试减到 50%

web 文件夹大小 8.39M,单 html:5.02M

优化:使用LOD减面插件,对主角的身体、头、武器M4 、武器加特林 的网格进行减面,尝试减到 50%【3D 模型的压缩办法之三】

web 文件夹大小 7.92M,单 html:4.83M

优化:boss和主角身体的网格二次减面【到这里 html 体积达到要求了】

web 文件夹大小 7.8M,单 html:4.81M

html 的体积优化思路总结

体积压缩,目前探索来看,还可以从以下 几 个方面着手

一、资源体积控制:

  1. 图片进行 tiny 压缩,如果还很大,让设计师通过调整分辨率等方式减低图片体积,如果还不行,就换一种轻量级的图片;
  2. 通过变换、平铺、九宫格裁剪等方式通过小图实现大图的功能;
  3. 能用 jpg 就不要用 png,因为 jpg 压缩率比 png 高;
  4.  3D模型网格压缩、网格减面(压缩不影响质量,减面可能会影响质量,减面有工具减面和美术手工减面两种,上述优化过程中使用的是 LOD 插件自动减面);
  5.  3D模型动画压缩、删除未用到的动画;
  6. 移除 resources 中没有用到的文件、只有脚本动态加载的资源才能放resources 文件夹

二、引擎体积控制:

  1. 引擎功能裁剪,去掉没用到的模块;
  2. 构建时配置减少体积,比如去除纹理压缩、去除 polyfill 等;
  3. 找到最适合试玩的版本(比例 cocos3.8.5 引擎裁剪功能粒度更细,至少能省 200K,laya 3.3.0 也有类似改进);
  4. 进阶版的话可以手动去除引擎中未用到的文件和函数,然后重新 build一次生成简化版的引擎文件(不过这要足够熟悉引擎或有类似文章参考才比较好处理);

三、压缩算法优化:

目前用了 JSZip 压缩和解压二进制。

四、压缩后的二进制内容编码输出到 html:

目前只找到 base64 一条路,但是 base64 让体积增大 33%。如果能找到比 base64 更优的编码方式,可以进一步降低 html的体积。

此处,简单解释下,base64 为什么体积会增大 33%


假设我们有一段 3 字节的二进制数据,用十六进制表示为 `A1 B2 C3`。

1. **原始数据**:
   - 3 字节,即 24 位。
   - 数据:`A1 B2 C3`

2. **Base64 编码过程**:
   - 将 3 字节数据 `10100001 10110010 11000011` 拼接成 24 位
   - 将这 24 位分成 4 组,每组 6 位:
     - `101000` (40)
     - `011011` (27)
     - `001011` (11)
     - `000011` (3)
   - 根据 Base64 编码表,将这些数值转换为对应的字符:
     - 40 → `o`
     - 27 → `b`
     - 11 → `L`
     - 3 → `D`
   - 编码结果:`obLD`

3. **结果对比**:
   - 原始数据:3 字节
   - Base64 编码后:4 字节

可以看到,原始数据是 3 字节,编码后变成了 4 字节,体积增加了 1 字节,即增加了约 33%。