gpt4 book ai didi

javascript - 在 html5 Canvas 上绘制多个粒子元素而无需渲染终止

转载 作者:行者123 更新时间:2023-11-28 08:08:03 25 4
gpt4 key购买 nike

在下面的代码中,我在单击 block 时启动/停止粒子火焰。它工作正常,但是,我需要大约 10-20 个火焰能够单独启动/停止并跟踪它们。一位 friend 建议我将每个火焰放在一个小 Canvas 中,然后单独绘制每个 Canvas ,我认为这会导致渲染过度,同时运行 10-20 个draw()。我该怎么办?

需要注意的一点是,火焰的位置在article()中给出,然后创建一个粒子数组,它基本上代表了火焰。

// init canvas
var canvas = $('canvas'),
ctx = canvas[0].getContext('2d') // world
,
ctx2 = canvas[1].getContext('2d') // fog
,
context = canvas[2].getContext('2d') // flame
,
mDown = false,
r1 = 100,
r2 = 300,
density = .4,
hideOnMove = true,
hideFill = 'rgba( 0, 0, 0, 1 )'
,
overlay = 'rgba( 0, 0, 0, 1 )',
particles = [],
particle_count = 100;
// init flame
for (var i = 0; i < particle_count; i++) {
particles.push(new particle());
}

if (!hideOnMove) {
// shouldn't be done like this, but this is a demo
canvas.get(1).remove();
}

// black out the canvas
ctx.fillStyle = overlay;
ctx.fillRect(0, 0, 1280, 800);

// set up our "eraser"
ctx.globalCompositeOperation = 'destination-out';

canvas.last()
.on('mousemove', function (ev, ev2) {
ev2 && (ev = ev2);

var pX = ev.pageX,
pY = ev.pageY;

// reveal wherever we drag
var radGrd = ctx.createRadialGradient(pX, pY, r1, pX, pY, r2);
radGrd.addColorStop(0, 'rgba( 0, 0, 0, 1 )');
radGrd.addColorStop(density, 'rgba( 0, 0, 0, .1 )');
radGrd.addColorStop(1, 'rgba( 0, 0, 0, 0 )');

ctx.fillStyle = radGrd;
ctx.fillRect(pX - r2, pY - r2, r2 * 2, r2 * 2);

// partially hide the entire map and re-reval where we are now
ctx2.globalCompositeOperation = 'source-over';
ctx2.clearRect(0, 0, 1280, 800);
ctx2.fillStyle = hideFill;
ctx2.fillRect(0, 0, 1280, 800);

var radGrd = ctx.createRadialGradient(pX, pY, r1, pX, pY, r2);
radGrd.addColorStop(0, 'rgba( 0, 0, 0, 1 )');
radGrd.addColorStop(.8, 'rgba( 0, 0, 0, .1 )');
radGrd.addColorStop(1, 'rgba( 0, 0, 0, 0 )');

ctx2.globalCompositeOperation = 'destination-out';
ctx2.fillStyle = radGrd;
ctx2.fillRect(pX - r2, pY - r2, r2 * 2, r2 * 2);

})
.trigger('mousemove', {
pageX: 150,
pageY: 150
});


function drawing() {
// clear canvas
context.clearRect(0, 0, 1280, 800);
context.globalCompositeOperation = "lighter";

for (var i = 0; i < particles.length; i++) {
var p = particles[i];
context.beginPath();
//changing opacity according to the life.
//opacity goes to 0 at the end of life of a particle
p.opacity = Math.round(p.remaining_life / p.life * 100) / 100
//a gradient instead of white fill
var gradient = context.createRadialGradient(p.location.x, p.location.y, 0, p.location.x, p.location.y, p.radius);
gradient.addColorStop(0, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", " + p.opacity + ")");
gradient.addColorStop(0.5, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", " + p.opacity + ")");
gradient.addColorStop(1, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", 0)");
context.fillStyle = gradient;
context.arc(p.location.x, p.location.y, p.radius, Math.PI * 2, false);
context.fill();

//lets move the particles
p.remaining_life--;
p.radius--;
p.location.x += p.speed.x;
p.location.y += p.speed.y;

//regenerate particles
if (p.remaining_life < 0 || p.radius < 0) {
//a brand new particle replacing the dead one
particles[i] = new particle();
}
}
}

// set flame on/off
var myVar = 0;
var on = 0;
$('.c').css({
left: "610px",
top: "500px"
});
$('.c').click(function () {
if (on == 0) {
myVar = setInterval(drawing, 33);
on = 1;
} else {
clearInterval(myVar);
context.clearRect(0, 0, 1280, 800);
on = 0;
}
});

function particle() {
//speed, life, location, life, colors
//speed.x range = -2.5 to 2.5
//speed.y range = -15 to -5 to make it move upwards
//lets change the Y speed to make it look like a flame
this.speed = {
x: -2.5 + Math.random() * 5,
y: -15 + Math.random() * 10
};
//flame location
this.location = {
x: 640,
y: 520
};
//radius range = 10-30
this.radius = 10 + Math.random() * 20;
//life range = 20-30
this.life = 20 + Math.random() * 10;
this.remaining_life = this.life;
//colors
this.r = Math.round(Math.random() * 255);
this.g = Math.round(Math.random() * 255);
this.b = Math.round(Math.random() * 255);
}

在此处查看完整网页 http://codepen.io/anon/pen/hxrat

最佳答案

如果您在一堆小 Canvas 中预先生成粒子,您可能会提高性能。基本上生成具有不同颜色和大小的粒子图像列表,然后将它们用于所有粒子。绘制粒子图像时仍然可以应用不透明度。在给定位置以给定的不透明度绘制小 Canvas 应该比绘制具有径向渐变的路径更快。

这是一个示例,似乎至少使性能提高了一倍:http://codepen.io/anon/pen/Izqwu

我不预先生成粒子 Canvas 。相反,我编写了一个函数 getParticleCanvas() ,它接受颜色并返回 32*32 像素 Canvas (如果不存在则创建一次),然后在 Drawing() 中使用。然后以正确的尺寸和不透明度绘制粒子 Canvas 。为了提高性能,该位置四舍五入到最接近的像素。

此外,为了减少可能的粒子 Canvas 数量,随机颜色四舍五入为每个 channel 8 个不同的步骤:

this.r = Math.round(Math.random() * 8)*32;
this.g = Math.round(Math.random() * 8)*32;
this.b = Math.round(Math.random() * 8)*32;

您可以将 getParticleCanvas() 中的半径从 16 减小到 8,而不会被注意到。

关于javascript - 在 html5 Canvas 上绘制多个粒子元素而无需渲染终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24600164/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com