HTML5 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);
});

這款HTML5 Canvas火球動畫就到這里了,js代碼比較多,最終的源碼可以到這里下載,下載地址>>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM