原生canvas游戏性能优化
微信小游戏在 17 年末推出,再次带火了 H5 小游戏的开发,本公众号准备一些 H5 游戏开发的文章,奉献给读者,想做小游戏的可以练练手,没时间做的可以学习下游戏常用的一些方法和概念。
本文来自 lizardlove,提到的一些 Canvas 游戏的优化方法,很值得阅读,比如对象池方法、worker 这些用法可以用在其他需要优化的项目中。
随着微信小游戏的推出,其全面支持以往的 H5 游戏开发,微信借小游戏的社交方式彻底激活小程序。同样的,也算是重新吹起了 H5 游戏的风口。
可以预见的是,借助小游戏的风,前端游戏开发这一分支也会燃起来了。在游戏开发中,最令人难受的也许就是性能优化了吧。本人在整理过往几次游戏开发的经历中,总结了一些常被忽视的优化小措施,与诸君分享。
针对游戏性能优化,首先,我们要知道我们优化的目标是什么?往往我们觉得性能优化很难,是因为我们不确定优化目标是什么,针对什么进行优化。
在我看来,性能优化的实质,实际上就是尽可能的减少等待时间和内存使用。
有了目标有好办了,接下来,我们需要知道我们通过优化哪些目标可以减少代码执行和内存使用。我粗略的分为了 3 个方面:
Canvas,原生 canvas 游戏,首要目标自然就是 canvas
内存使用,果 7 之前 safari 运行内存只有 100M,滥用内存直接给你强制锁死
多线程,两条腿走路肯定比一条腿快多了啊
Canvas
离屏 canvas
场景:针对需要大量使用且绘图繁复的静态场景
实现:对象内放置一个私有 canvas,初始化时将静态场景绘制完备,需要时直接拷贝内置 canvas 的图像即可
//每一帧重绘时
setInterval(function () {context.fillRect(x,y,width,height)context.arc(x,y,r,sA,eA)context.strokeText('hehe', x, y)
}, 1000/60)
设置离屏 canvas
let background = {width: 400,height: 400,canvas: document.createElement('canvas'),init: () => {let self = thislet ctx = self.canvas.getContext('2d')self.canvas.width = self.widthself.canvas.height = self.heightctx.fillRect(x,y,width,height)ctx.arc(x,y,r,sA,eA)ctx.strokeText('hehe', x, y)}
}
background.init()
setInterval(() => {context.drawImage(background.canvas, background.width, background.height, 0, 0);
}, 1000/60)
不设置离屏 canvas 的情况下,每帧绘制会调用 3 次绘图 api;设置离屏 canvas 后,每帧只用调用一次 api。
实质:减少调用 api 的次数,减少代码执行语句,从而减少每帧渲染时间,从而提高动画流程度。
状态修改
场景:针对需要频繁修改 canvas 对象的渲染状态 (fillStyle, strokeStyle ...)
实现:按 canvas 状态分别绘制,而不是按对象进行绘制
混合绘制
for (let i = 0; i < line.length; i++) {let e = line[i]context.fillStyle = i % 2 ? '#000': '#fff'context.fillRect(e.x, e.y, e.width, e.height)
}
不同状态分别绘制:
context.fillStyle = '#000'
for (let i = 0; i < line.length / 2 - 1; i++) {let e = line[i * 2 + 1]context.fillRect(e.x, e.y, e.width, e.height)
}
context.fillStyle = '#fff'
for (let i = 0; i < line.length / 2 - 1; i++) {let e = line[i * 2]context.fillRect(e.x, e.y, e.width, e.height)
}
前后比较看,虽然循环次数没变,但循环内调用的语句变少了,即不在循环内修改 canvas 状态了。
实质:减少 canvas api 的调用,不用在每次根据对象属性去修改 canvas 的状态,而是将具有相同状态的对象提出,批量渲染。
分层和局部重绘
场景:针对场景中大背景变化缓慢,而角色的状态变换频繁
实现:将场景按状态变换快慢进行层次划分,设置不同的透明度和 z-index 进行层级叠加。
实质:通过分层,对连续帧中的相同场景不重复渲染,减少渲染所需的 canvas api 的调用。
但在微信小游戏中,本方法不能使用,因为微信小游戏中有全局唯一 canvas,其他 canvas 都是离屏 canvas,不能显示。
requestAnimationFrame
这个不存在什么场景,就是一把梭,无脑直接上 RAF,别再 setInterval 了。
简单点说,RAF 是浏览器根据页面渲染的情况,自行选择下一帧绘制的时机。
但是有一个 tip 需要注意,RAF 不管理回调函数,即在 RAF 回调被执行前,如果 RAF 多次调用,其回调函数也会多次调用。所以需要做好防抖节流。不然会导致 RAF 的回调函数在同一帧中重复调用,造成不必要的计算和渲染的消耗。
const animation = timestamp => console.log('animation called at', timestamp)
window.requestAnimationFrame(animation)
window.requestAnimationFrame(animation)
内存优化
对象池
场景:针对游戏中需要频繁更新和删除 的角色
实现:对象池维护一个装着空闲对象的池子,如果需要对象的时候,不是直接 new,而是从对象池中取出,如果对象池中没有空闲对象,则新建一个空闲对象。
const __ = {poolDic: Symbol('poolDic')
}
/*** 简易的对象池实现* 用于对象的存贮和重复使用* 可以有效减少对象创建开销和避免频繁的垃圾回收* 提高游戏性能*/
export default class Pool {constructor() {this[__.poolDic] = {}}/*** 根据对象标识符* 获取对应的对象池*/getPoolBySign(name) {return this[__.poolDic][name] || ( this[__.poolDic][name] = [] )}/*** 根据传入的对象标识符,查询对象池* 对象池为空创建新的类,否则从对象池中取*/getItemByClass(name, className) {let pool = this.getPoolBySign(name)let result = ( pool.length? pool.shift(): new Object() )return result}/*** 将对象回收到对象池* 方便后续继续使用*/recover(name, instance) {this.getPoolBySign(name).push(instance)}
}
实质:减少内存的使用。每次创建一个对象,都需要分配一点内存,而由于浏览器的回收机制,导致会有大量无用的对象的累加,白白消耗大量的内存。
多线程
Worker
场景:针对需要进行大量计算任务
实现:使用 worker 单独开启线程进行并行计算,主线程仍执行自己的任务。
实质就是并行计算,避免进程堵塞。任务计算需要的时间是不会减少的,形象点来说就是从一条腿走路变成两条腿走路
//main.js
//创建worker线程
let worker = new Worker('worker.js')
//监听worker线程的返回事件
worker.onmessage = (e) => {//e worker线程的返回对象
}
//发送消息
worker.postMessage(obj)
//worker.js
//监听主线程的执行请求
onmessage = (e) => {//执行对象epostMessage(result)
}
实质:并行计算,可以认为计算任务与主线程工作是异步的,互不干扰。因为是将计算任务全部交给 worker,所有计算时间是不会减少的。
对象池不仅可以针对对象,还可以针对 worker 进行线程池的管理,有兴趣的朋友可以试试。
其实除了上述 3 个方面,还有一个非常重要的优化目标,那就是网络优化,但这也是我们常说的浏览器性能优化的终点内容,所以关于网络优化,各位就请移步其他大神的文章,我也就不再卖弄我那一点三脚猫技术了。各位朋友有什么其他的优化措施的,欢迎交流。
原生canvas游戏性能优化相关推荐
- Unity移动端游戏性能优化简谱之 以引擎模块为划分的CPU耗时调优
<Unity移动端游戏性能优化简谱>从Unity移动端游戏优化的一些基础讨论出发,例举和分析了近几年基于Unity开发的移动端游戏项目中最为常见的部分性能问题,并展示了如何使用UWA的性能 ...
- 移动端HTML5游戏性能优化
移动端HTML5游戏性能优化 戴嘉华 created on NOV 01, 14 last updated on NOV 01, 14 本文同时也发布在我的博客:http://www.livora ...
- 游戏开发43课 移动游戏性能优化1
1. 前言 很多年前就想将这些年工作中积累的优化经验撰写成文章,但懒癌缠身,迟迟未动手,近期总算潜下心写成文章. 涉及到具体优化技巧时,博主会尽量阐述原理和依据,让读者知其然也知其所以然.要完全读懂这 ...
- 极光会客厅:大型H5游戏如何登陆微信小游戏及游戏性能优化分享
上周末,由极光网络主办的首期"极光会客厅"正式开门迎客.在本次的"2D小游戏开发实战技术沙龙"上,极光网络客户端主程陈策以及极光网络项目总监陈源向一众与会者分享 ...
- 白鹭引擎王泽:重度H5游戏性能优化技巧
9月15日,无惧17级台风"山竹",320名开发者齐聚广州贝塔空间共同探讨"怎样做一款赚钱的小游戏".针对众多开发者关心的重度H5游戏性能优化技巧,我们整理了现 ...
- 白鹭引擎王泽:重度H5游戏性能优化技巧标题的文章
我们的引擎架构师做某一沙龙活动的演讲速记,纯纯的干货,分享给大家. 王泽:各位开发者下午好!我叫王泽,是白鹭引擎的首席架构师. 今天给大家分享的题目是<重度H5游戏性能优化技巧>.之所以决 ...
- 【Egret优化分享】白鹭引擎王泽:重度H5游戏性能优化技巧
本文转自:https://mp.weixin.qq.com/s/GIzXA51D7_hMqajCRuJE2g 9月15日,无惧17级台风"山竹",320名开发者齐聚广州贝塔空间共同 ...
- 移动游戏性能优化通用技法
1. 前言 很多年前就想将这些年工作中积累的优化经验撰写成文章,但懒癌缠身,迟迟未动手,近期总算潜下心写成文章. 涉及到具体优化技巧时,我会尽量阐述原理和依据,让读者知其然也知其所以然. 要完全读懂这 ...
- Unity移动端游戏性能优化简谱之 常见游戏内存控制
<Unity移动端游戏性能优化简谱>从Unity移动端游戏优化的一些基础讨论出发,例举和分析了近几年基于Unity开发的移动端游戏项目中最为常见的部分性能问题,并展示了如何使用UWA的性能 ...
最新文章
- 河海大学839计算机技术基础,2017年河海大学计算机与信息学院839通信原理考研强化模拟题...
- java单例设计模式
- 巧用ActionFilterAttribute实现API日志的记录
- 自动化测试用例设计的原则
- POJ 3624 Charm Bracelet【01背包】
- 量化投资学习——如何阅读研报
- 阿帕奇服务器配置文件,阿帕奇服务器基本参数配置
- 中文繁体与简体字转换
- 神秘AI变脸软件风靡全球,让你秒变身迪士尼在逃主角
- 微信小程序 wx.previewImage 预览分享图片结束之后 执行事件
- 宝塔显示100%负载100%cpu解决办法
- 通信系统原理[郭宇春]——信号与噪声——课后习题答案
- wsimport 无法读取wsdl文档,unknown extensibility element or attribute “EndpointReference“
- python八枚硬币问题
- 商场播放系统服务器,购物中心播音及背景音乐系统(IP广播)解决方案
- skin卓沿护肤品怎么样_白金卓沿护肤品怎么样孕妇能用吗
- java软件工程师简历
- 对停留在云计算概念层面已经腻了?请看《云计算》教材
- 【车载开发系列】CAN总线通信---总线报文格式
- 单片机类型介绍和入门单片机
热门文章
- 【2018最新VR眼镜哪个好】什么VR眼镜好,全民评测,选最合适的
- Win 11环境下 Texlive中文字体缺失问题(Package fontspec Error: The font )
- 这是我所收集的一些工具网站
- 想知道如何批量旋转图片?只要学会这两招就可以
- conda配置清华源
- 微型计算机储存系统一般指主存器和,2019年12月网络教育统考《计算机应用基础》复习题(八)...
- 容器网络连接被重置?这篇文章教你如何去定位及分析
- DELL-DRAC远程控制卡使用教程
- 通达信 缠论分笔、分段DLL插件
- 美团CEO王兴的互联网思维