欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

HTML5 Canvas火焰效果 像火球发射一样

程序员文章站 2022-07-06 10:56:32
canvas是html5中非常重要而且有用的东西,我们可以在canvas上绘制任意的元素,就像你制作flash一样。今天我们就在canvas上来制作一款火焰发射的效果。就像古代的火球炮一样,而且可以...
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);

});