视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
HTML5Canvas实现火焰效果像火球发射一样的示例代码
2020-11-27 15:11:00 责编:小采
文档
Canvas是HTML5中非常重要而且有用的东西,我们可以在Canvas上绘制任意的元素,就像你制作Flash一样。今天我们就在Canvas上来制作一款火焰发射的效果。就像古代的火球炮一样,而且可以在浏览器边缘反弹,感觉会比较屌。来看看效果图:

我们可以在这里查看火焰球的DEMO演示

当然,我们要来分析一下源代码,主要是一些JS代码。

首先很简单地在页面上放一个canvas标签,并且给它点简单的样式:

<canvas></canvas>
canvas{
 position: absolute;
 height: 100%;
 width: 100%;
 left: 0;
 top: 0;
 cursor: crosshair;
}

接下来就来分析一下JS代码。我们来逐步分解JS。

由于这个是二维动画,所以我们利用canvas的getContext方法来返回一个对象,这个对象包含我们对二维动画操作的API,代码如下:

canvas = document.querySelector('canvas');
ctx = canvas.getContext('2d');

下面我们来定义粒子:

particles = {};
newParticle = (function(){ var nextIndex = 0; return function(x,y,r,o,c,xv,yv,rv,ov){
 particles[++nextIndex] = {
 index: nextIndex,
 x: x,
 y: y,
 r: r,
 o: o,
 c: c,
 xv: xv,
 yv: yv,
 rv: rv,
 ov: ov
 };
 };
})();

然后我们来定义火球:

fireballs = {};
newFireball = (function(){ var nextIndex = 0; return function(x,y,xv,yv,life){
 fireballs[++nextIndex] = {
 index: nextIndex,
 x: x,
 y: y,
 xv: xv,
 yv: yv,
 life: life
 };
 };
})();

这里life表示火球的生命周期,下面我们可以看到,life值会随着火球发射力度的改变而改变。

接下来是定义鼠标拖动弹弓,准备发射火球:

mouse = {x:0,y:0,d:0};
onmousemove = function(e){
 mouse.x = e.clientX-o.x;
 mouse.y = e.clientY-o.y; var dx = mouse.x - pos1.x,
 dy = mouse.y - pos1.y;
 mouse.d = Math.sqrt(dx*dx+dy*dy);
};

charging = false;
pos1 = {x:0,y:0};
showInstructions = true;
onmousedown = function(e){
 pos1.x = mouse.x;
 pos1.y = mouse.y;
 charging = true;
 showInstructions = false;
};

onmouseup = function(){ if(charging){
 newFireball(
 mouse.x,
 mouse.y,
 (pos1.x-mouse.x)*0.03,
 (pos1.y-mouse.y)*0.03, 600
 );
 charging = false;
 }
};

可以看到,当鼠标按键弹起时,新建一个火球,并初始化life值。

下面是火球运动时的动画执行代码,包括碰到浏览器边缘时的反射效果:

time = 0;
requestAnimationFrame(loop = function(){
 ctx.setTransform(1,0,0,1,0,0);
 ctx.globalCompositeOperation = 'source-over';
 ctx.globalAlpha = 1;
 ctx.fillStyle = bgColor;
 ctx.fillRect(0,0,width,height);
 
 ctx.translate(o.x,o.y); 
 if(charging){ var c = Math.floor(30+mouse.d/2);
 ctx.strokeStyle = 'rgba('+c+','+c+','+c+',1)';
 ctx.lineWidth = 4;
 ctx.beginPath();
 ctx.moveTo(pos1.x,pos1.y);
 ctx.lineTo(mouse.x,mouse.y);
 ctx.lineCap = 'round';
 ctx.stroke();
 } 
 if(showInstructions){
 pos1.x = -70;
 pos1.y = -35; 
 if(time<10){ var x = -70,
 y = -35,
 r = 30-time*2,
 a = time/10;
 }else if(time<80){ var x = (time-10)*2-70,
 y = (time-10)-35,
 r = 10,
 a = 1;
 }else if(time<90){ var x = 70,
 y = 35,
 r = 10+(time-80)*2,
 a = 1-(time-80)/10;
 }else if(time<140){ var x = 70,
 y = 35,
 r = 30,
 a = 0;
 } var dx = pos1.x-x,
 dy = pos1.y-y,
 d = Math.sqrt(dx*dx+dy*dy); if(time<80&&time>10){
 ctx.globalCompositeOperation = 'source-over';
 ctx.globalAlpha = 1; var c = Math.floor(30+d/2);
 ctx.strokeStyle = 'rgba('+c+','+c+','+c+',1)';
 ctx.lineWidth = 4;
 ctx.beginPath();
 ctx.moveTo(pos1.x,pos1.y);
 ctx.lineTo(x,y);
 ctx.lineCap = 'round';
 ctx.stroke();
 } if(time<140){
 ctx.globalCompositeOperation = 'source-over';
 ctx.globalAlpha = a;
 ctx.beginPath();
 ctx.arc(x,y,r,0,Math.PI*2);
 ctx.lineWidth = 2;
 ctx.strokeStyle = '#aaa';
 ctx.stroke();
 } if(time==80){
 newFireball(
 x,
 y,
 dx*0.03,
 dy*0.03, 240
 );
 }
 time = (time+1)%180;
 }
 
 ctx.globalCompositeOperation = 'lighter'; 
 for(var i in particles){ 
 var p = particles[i];
 ctx.beginPath();
 ctx.arc(p.x,p.y,p.r,0,Math.PI*2);
 ctx.globalAlpha = p.o;
 ctx.fillStyle = p.c;
 ctx.fill();
 } 
 for(var i in particles){ 
 var p = particles[i];
 p.x += p.xv;
 p.y += p.yv;
 p.r += p.rv;
 p.o += p.ov; 
 if(p.r<0)delete particles[p.index]; 
 if(p.o<0)delete particles[p.index];
 } 
 for(var i in fireballs){
 f = fireballs[i]; 
 var numParticles = Math.sqrt(f.xv*f.xv+f.yv*f.yv)/5; 
 if(numParticles<1)numParticles=1; 
 var numParticlesInt = Math.ceil(numParticles),
 numParticlesDif = numParticles/numParticlesInt; 
 for(var j=0;j<numParticlesInt;j++){
 newParticle(
 f.x-f.xv*j/numParticlesInt,
 f.y-f.yv*j/numParticlesInt,
 7,
 numParticlesDif,
 particleColor,
 Math.random()*0.6-0.3,
 Math.random()*0.6-0.3, 
 -0.3, 
 -0.05*numParticlesDif
 );
 }
 f.x += f.xv;
 f.y += f.yv;
 f.yv += gravity; 
 var boundary; 
 if(f.y<(boundary = edge.top+7)){
 f.y = boundary;
 f.yv *= -1;
 }else if(f.y>(boundary = edge.bottom-7)){
 f.y = boundary;
 f.yv *= -1;
 } if(f.x>(boundary = edge.right-7)){
 f.x = boundary;
 f.xv *= -1;
 }else if(f.x<(boundary = edge.left+7)){
 f.x = boundary;
 f.xv *= -1;
 } if(--f.life<0)delete fireballs[f.index];
 }
 
 requestAnimationFrame(loop);
});

下载本文
显示全文
专题