html5 restore,HTML5 Canvas save() and restore() performance

Animation and Game performance tips.

Avoid save restore

Use setTransform as that will negate the need for save and restore.

There are many reasons that save an restore will slow things down and these are dependent on the current GPU && 2D context state. If you have the current fill and/or stroke styles set to a large pattern, or you have a complex font / gradient, or you are using filters (if available) then the save and restore process can take longer than rendering the image.

When writing for animations and games performance is everything, for me it is about sprite counts. The more sprites I can draw per frame (60th second) the more FX I can add, the more detailed the environment, and the better the game.

I leave the state open ended, that is I do not keep a detailed track of the current 2D context state. This way I never have to use save and restore.

ctx.setTransform rather than ctx.transform

Because the transforms functions transform, rotate, scale, translate multiply the current transform, they are seldom used, as i do not know what the transform state is.

To deal with the unknown I use setTransform that completely replaces the current transformation matrix. This also allows me to set the scale and translation in one call without needing to know what the current state is.

ctx.setTransform(scaleX,0,0,scaleY,posX,posY); // scale and translate in one call

I could also add the rotation but the javascript code to find the x,y axis vectors (the first 4 numbers in setTransform) is slower than rotate.

Sprites and rendering them

Below is an expanded sprite function. It draws a sprite from a sprite sheet, the sprite has x & y scale, position, and center, and as I always use alpha so set alpha as well

// image is the image. Must have an array of sprites

// image.sprites = [{x:0,y:0,w:10,h:10},{x:20,y:0,w:30,h:40},....]

// where the position and size of each sprite is kept

// spriteInd is the index of the sprite

// x,y position on sprite center

// cx,cy location of sprite center (I also have that in the sprite list for some situations)

// sx,sy x and y scales

// r rotation in radians

// a alpha value

function drawSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){

var spr = image.sprites[spriteInd];

var w = spr.w;

var h = spr.h;

ctx.setTransform(sx,0,0,sy,x,y); // set scale and position

ctx.rotate(r);

ctx.globalAlpha = a;

ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage

}

On just an average machine you can render 1000 +sprites at full frame rate with that function. On Firefox (at time of writing) I am getting 2000+ for that function (sprites are randomly selected sprites from a 1024 by 2048 sprite sheet) max sprite size 256 * 256

But I have well over 15 such functions, each with the minimum functionality to do what I want. If it is never rotated, or scaled (ie for UI) then

function drawSprite(image, spriteInd, x, y, a){

var spr = image.sprites[spriteInd];

var w = spr.w;

var h = spr.h;

ctx.setTransform(1,0,0,1,x,y); // set scale and position

ctx.globalAlpha = a;

ctx.drawImage(image,spr.x,spr.y,w,h,0,0,w,h); // render the subimage

}

Or the simplest play sprite, particle, bullets, etc

function drawSprite(image, spriteInd, x, y,s,r,a){

var spr = image.sprites[spriteInd];

var w = spr.w;

var h = spr.h;

ctx.setTransform(s,0,0,s,x,y); // set scale and position

ctx.rotate(r);

ctx.globalAlpha = a;

ctx.drawImage(image,spr.x,spr.y,w,h,-w/2,-h/2,w,h); // render the subimage

}

if it is a background image

function drawSprite(image){

var s = Math.max(image.width / canvasWidth, image.height / canvasHeight); // canvasWidth and height are globals

ctx.setTransform(s,0,0,s,0,0); // set scale and position

ctx.globalAlpha = 1;

ctx.drawImage(image,0,0); // render the subimage

}

It is common that the playfield can be zoomed, panned, and rotated. For this I maintain a closure transform state (all globals above are closed over variables and part of the render object)

// all coords are relative to the global transfrom

function drawGlobalSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){

var spr = image.sprites[spriteInd];

var w = spr.w;

var h = spr.h;

// m1 to m6 are the global transform

ctx.setTransform(m1,m2,m3,m4,m5,m6); // set playfield

ctx.transform(sx,0,0,sy,x,y); // set scale and position

ctx.rotate(r);

ctx.globalAlpha = a * globalAlpha; (a real global alpha)

ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage

}

All the above are about as fast as you can get for practical game sprite rendering.

General tips

Never use any of the vector type rendering methods (unless you have the spare frame time) like, fill, stroke, filltext, arc, rect, moveTo, lineTo as they are an instant slowdown. If you need to render text create a offscreen canvas, render once to that, and display as a sprite or image.

Image sizes and GPU RAM

When creating content, always use the power rule for image sizes. GPU handle images in sizes that are powers of 2. (2,4,8,16,32,64,128....) so the width and height have to be a power of two. ie 1024 by 512, or 2048 by 128 are good sizes.

When you do not use these sizes the 2D context does not care, what it does is expand the image to fit the closest power. So if I have an image that is 300 by 300 to fit that on the GPU the image has to be expanded to the closest power, which is 512 by 512. So the actual memory footprint is over 2.5 times greater than the pixels you are able to display. When the GPU runs out of local memory it will start switching memory from mainboard RAM, when this happens your frame rate drops to unusable.

Ensuring that you size images so that you do not waste RAM will mean you can pack a lot more into you game before you hit the RAM wall (which for smaller devices is not much at all).

GC is a major frame theef

One last optimisation is to make sure that the GC (garbage collector) has little to nothing to do. With in the main loop, avoid using new (reuse and object rather than dereference it and create another), avoid pushing and popping from arrays (keep their lengths from falling) keep a separate count of active items. Create a custom iterator and push functions that are item context aware (know if an array item is active or not). When you push you don't push a new item unless there are no inactive items, when an item becomes inactive, leave it in the array and use it later if one is needed.

There is a simple strategy that I call a fast stack that is beyond the scope of this answer but can handle 1000s of transient (short lived) gameobjects with ZERO GC load. Some of the better game engines use a similar approch (pool arrays that provide a pool of inactive items).

GC should be less than 5% of your game activity, if not you need to find where you are needlessly creating and dereferencing.

考虑柔性负荷的综合能源系统低碳经济优化调度【考虑碳交易机制】(Matlab代码实现)内容概要:本文围绕“考虑柔性负荷的综合能源系统低碳经济优化调度”展开,重点研究在碳交易机制下如何实现综合能源系统的低碳化与经济性协同优化。通过构建包含风电、光伏、储能、柔性负荷等多种能源形式的系统模型,结合碳交易成本与能源调度成本,提出优化调度策略,以降低碳排放并提升系统运行经济性。文中采用Matlab进行仿真代码实现,验证了所提模型在平衡能源供需、平抑可再生能源波动、引导柔性负荷参与调度等方面的有效性,为低碳能源系统的设计与运行提供了技术支撑。; 适合人群:具备一定电力系统、能源系统背景,熟悉Matlab编程,从事能源优化、低碳调度、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究碳交易机制对综合能源系统调度决策的影响;②实现柔性负荷在削峰填谷、促进可再生能源消纳中的作用;③掌握基于Matlab的能源系统建模与优化求解方法;④为实际综合能源项目提供低碳经济调度方案参考。; 阅读建议:建议读者结合Matlab代码深入理解模型构建与求解过程,重点关注目标函数设计、约束条件设置及碳交易成本的量化方式,可进一步扩展至多能互补、需求响应等场景进行二次开发与仿真验证。
### 在 HBuilder 中调试 HTML5 Canvas 动画的方法 在 HBuilder 中调试 HTML5 Canvas 动画,主要依赖浏览器的开发者工具与 HBuilder 自身的调试功能。由于 Canvas 是通过 JavaScript 在 `<canvas>` 元素上进行绘制的,因此调试过程中需要关注 DOM 结构、JavaScript 执行流程以及绘图上下文的状态。 #### 使用浏览器开发者工具 在 HBuilder 中运行 HTML 文件后,可通过浏览器的开发者工具进行调试。打开方式为右键点击页面并选择“检查”或使用快捷键 `F12`,这将打开包含多个调试面板的控制台 [^3]。其中以下几个面板尤为重要: - **Elements(元素)**:可以查看 `<canvas>` 元素是否正确加载,以及其宽高属性是否符合预期。 - **Console(控制台)**:用于查看 JavaScript 输出的日志信息,如 `console.log()` 或错误信息,有助于排查绘图逻辑中的错误 [^3]。 - **Sources(源代码)**:可以设置断点,逐步执行 JavaScript 代码,观察变量状态,例如 `ctx` 上下文对象是否正确初始化。 - **Performance(性能)**:用于分析动画的帧率与资源消耗情况,优化 Canvas 画性能。 #### 利用 HBuilder 的调试功能 HBuilder 提供了对 HTML、CSS 和 JavaScript 的实时预览与调试支持。在编写 Canvas 动画代码时,可利用以下功能提升调试效率: - **代码自动补全与提示**:帮助快速编写正确的 Canvas API 调用语句,减少语法错误。 - **内置浏览器预览**:可在 HBuilder 内部直接运行 HTML 文件,快速查看 Canvas 动画效果。 - **断点调试**:通过 HBuilder 的调试器设置断点,逐步执行 `requestAnimationFrame` 循环或粒子更新逻辑,确保动画更新逻辑无误。 #### 调试 Canvas 动画的常见技巧 1. **绘制辅助图形**:在调试阶段可以临时绘制坐标轴、边界框等辅助图形,帮助理解 Canvas 的绘制区域和坐标变换。 2. **输出调试信息**:在关键逻辑中插入 `console.log()` 输出粒子位置、动画状态等信息,有助于分析动画行为。 3. **简化动画逻辑**:在调试初期可以关闭部分动画效果(如粒子透明度变化、重力影响等),逐步启用以定位问题。 #### 示例代码片段 以下是一个简单的 Canvas 动画示例,可用于调试: ```javascript const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; function animate() { ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 示例:绘制一个旋转的矩形 ctx.save(); ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(Date.now() / 1000); ctx.fillStyle = 'red'; ctx.fillRect(-50, -50, 100, 100); ctx.restore(); requestAnimationFrame(animate); } animate(); ``` 通过上述方法,可以在 HBuilder 中高效调试 HTML5 Canvas 动画,确保其逻辑正确且性能良好。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值