|前端如何快速上手 Web 3D 游戏的开发( 六 )


调试工具
工欲善其事必先利其器 , 当我们需要对项目进行性能优化的时候 , 我们首先需要分析性能瓶颈点 , 然后对症下药 , 很幸运的是chrome本身就自带性能分析工具(Performance:打开页面进入开发者工具即可看到) , 如下:
|前端如何快速上手 Web 3D 游戏的开发
本文插图
除了性能调试工具外 , 有时候我们还会遇到一些渲染异常 , 大多是给到GPU的数据有问题 , 而这部分数据我们没法console.log , chrome提供了一个非常好用的插件(Spector.js)帮助我们查看每一帧的数据 , 如下:
|前端如何快速上手 Web 3D 游戏的开发
本文插图
降低三角面
三角面越多 , gpu的计算量也会越大 , 结合游戏实际的玩法 , 我们对三角面这块的优化主要就是不同模型进行减面 , 最终三角面从20万+降低到6万+ , 具体如下:
1、人物这块 , 因为在跑动过程中 , 我们始终只能看到背面 , 所以把人物前面的三角面全部去掉
2、金币这块 , 在保证视觉效果看起来比较圆的前提下尽可能的减少三角面
3、楼房和人物类似 , 把赛道外部的游戏过程中根本看不到的面去除
|前端如何快速上手 Web 3D 游戏的开发
本文插图
提升帧率
提升帧率本质上就是减少cpu的运算时间 , 通过前面提到的分析工具分析 , 我们发现节点数量过多是导致cpu运算量大的主要原因 , 所以我们的优化重点是在降低节点数量上 , 最终我们的 fps 在低端机上面从10优化到25 , 下面来具体说下:
1、金币模型里面有很多没有用的空节点 , 这个我们找美术同学帮忙重新简化模型文件
2、金币模型简化后 , 其实模型里面还有2个节点(其中有一个rootnode其实没啥用 , 和美术同学交流 , 反馈是目前没有办法去掉) , 加上挂载模型的节点 , 我们一个金币对象其实就有3个节点 , 为了进一步优化 , 我们通过代码动态去掉多余节点并进行节点合并 。
3、使用对象池来避免反复创建金币 。 在主循环中 , 对一些循环出现的元素 , 我们一种优化手段就是在初始化的时候事先创建一定数量的对象 , 然后用的时候来取 , 用完就还回来 , 而缓存创建好的对象的结构就是我们的对象池了 。 对象池带来的好处:减少主循环过程中创建对象带来的开销、可以有效避免因创建释放等操作带来的GC 。 我们游戏中金币数量很多 , 并且是高频出现的 , 所以要用对象池来缓存 , 相应的设计如下:
class CoinPool { private _originNode = null; private _pool = []; constructor () { } init (originNode: o3.Node, capacity: number = 5) { this._originNode = originNode; this._genNode(capacity); } destroy () { this._originNode = null; this._pool.length = 0; } getNode () { if (this._pool.length === 0) { this._genNode(); } return this._pool.shift(); } putNode (node: o3.Node) { if (this._pool.indexOf(node) === -1) { this._pool.push(node); } } _genNode (num: number = 1) { const pool = this._pool; for (let i = 0; i < num; ++i) { let node = this._originNode.clone(); // 对金币模型节点的优化在这里统一处理 changeParent(node); purifyNode(node); pool.push(node); } } }对象池使用方式:
// 创建并初始化 const originCoin = node.findChildByName('coinParent'); // 挂载金币模型的节点 const coinPool = new CoinPool(); coinPool.init(originCoin, 24); // 从池子里面获取金币节点 const coinNode = coinPool.getNode(); // 金币节点不需要使用了 , 进行回收 coinPool.putNode(coinNode); // 整个节点池销毁 coinPool.destroy();其他