之前在抖音上看到了一个很漂亮的焰火效果。这会儿有时间就用canvas实现了一下。

演示地址:http://suohb.com/work/firework4.htm

先看效果:(静态图片看不太出效果,请直接查看演示地址,考验电脑CPU的时候到了)

实现原理:

焰火特效运用到的物理知识就是抛物线运动

看起来很复杂的焰火实际上就是一条条的抛物线。

从一个中心点向四周方向抛出一个质点。将质点的轨迹画出来,就是焰火效果了。

//每一个质点对象
1
var obj = { 2 x: x,//当前X坐标 3 y: y,//当前Y坐标 4 sx: Math.cos(deg)*curSpeed,//X轴方向速度 5 sy: Math.sin(deg)*curSpeed,//Y轴方向速度 6 len: len + level*10*Math.random(),//焰火显示长度(这么多质点连接起来) 7 limit: limit + level*10*Math.random(),//质点移动最大步数 8 color: color,//焰火颜色 9 level: level,//焰火等级(因为特效是二级焰火,可以做多级) 10 list:[{x:x,y:y}]//质点轨迹(将这些轨迹连起来就是焰火的其中一条线) 11 };
//向360度方向生成一批质点,形成一个焰火元素
1
function addFire(x,y,color,level){ 2 curLevel = level ; 3 var lineLen = 10+level*20 + Math.random()*10, 4 deg , 5 speed = 1 + Math.random()*level*.4 , 6 len = 15 + Math.random()*level*6, 7 limit = len + 4 + Math.random()*level; 8 for(var i = 0 ; i < lineLen ; i ++){ 9 deg = i*(Math.PI*2/lineLen)+Math.random() ; 10 var curSpeed = speed + Math.random(); 11 var obj = 质点对象 12 list.push(obj); 13 } 14 }
//更新质点位置,并将新位置插入质点轨迹之中
1
function reviewFire(){ 2 for(var i = 0 ; i <list.length ; i++){ 3 let obj = list[i]; 4 obj.x += obj.sx ; 5 obj.y += obj.sy ; 6 obj.sy += G ;//抛物运动中的重力加速度 7 obj.list.push({x:obj.x,y:obj.y}); 8 obj.list = obj.list.slice(-obj.len); 9 } 10 }
//画出轨迹即可
1
function drawFire(){ 2 cxt.clearRect(0,0,pageWidth,pageHeight); 3 var obj ; 4 for(var i = 0 ; i < list.length ; i ++){ 5 obj = list[i] ; 6 cxt.beginPath(); 7 for(var j = 0 ; j < obj.list.length ; j++){ 8 if(i == 0) 9 cxt.moveTo(obj.list[j].x ,obj.list[j].y); 10 else{ 11 cxt.lineTo(obj.list[j].x ,obj.list[j].y); 12 } 13 } 14 cxt.strokeStyle = obj.color ; 15 cxt.lineWidth = obj.level ; 16 cxt.stroke(); 17 } 18 }

完整代码:

  1 <!doctype html>
  2 <html>
  3 <head>
  4 <meta http-equiv="Pragma" content="no-cache" />
  5 <meta http-equiv="Cache-Control" content="no-cache" />
  6 <meta http-equiv="Expires" content="0" />
  7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  8 <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
  9 <title>焰火特效-长按二维码关注公众号,了解更多特效</title>
 10 <style type="text/css">
 11 html{
 12     height: 100%;
 13 }
 14 html,body,ul,li,canvas{
 15     margin: 0;
 16     padding: 0;
 17 }
 18 
 19 </style>
 20 </head>
 21 <body bgcolor="#000000">
 22 <canvas id="knife"></canvas>
 23 <img src="../images/qr.jpg" style="position:fixed;bottom:0;width:100px;height:100px;right:0;">
 24 </body>
 25 <script>
 26 var canvas = document.getElementById("knife");
 27 canvas.style.position = "absolute" ;
 28 canvas.style.top = 0 ;
 29 var pageWidth = window.innerWidth ;
 30 var pageHeight = window.innerHeight ;
 31 canvas.width = window.innerWidth ;
 32 canvas.height = window.innerHeight ;
 33 var cxt = canvas.getContext("2d");
 34 var list = [] ;
 35 var G = 0.036 ;
 36 var colors = ["#8b008b","#ff69b4","#7fff00","#1e90ff","#00bfff","#0FF","#7cfc00","#ffd700","#ffdead","#f00"];
 37 var curLevel = 0 ;
 38 var curColor = 0 ;
 39 
 40 function addFire(x,y,color,level){
 41     curLevel = level ;
 42     var lineLen = 10+level*20 + Math.random()*10,
 43         deg ,
 44         speed = 1 + Math.random()*level*.4 ,
 45         len = 15 + Math.random()*level*6,
 46         limit = len + 4 + Math.random()*level;
 47     for(var i = 0 ; i < lineLen ; i ++){
 48         deg = i*(Math.PI*2/lineLen)+Math.random() ;
 49         var curSpeed = speed + Math.random();
 50         var obj = {
 51             x: x,
 52             y: y,
 53             sx: Math.cos(deg)*curSpeed,
 54             sy: Math.sin(deg)*curSpeed,
 55             len: len + level*10*Math.random(),
 56             limit: limit + level*10*Math.random(),
 57             color: color,
 58             level: level,
 59             list:[{x:x,y:y}]
 60         };
 61         list.push(obj);
 62     }
 63 }
 64 function reviewFire(){
 65     for(var i = 0 ; i <list.length ; i++){
 66         let obj = list[i];
 67         obj.x += obj.sx ;
 68         obj.y += obj.sy ;
 69         obj.sy += G ;
 70         obj.list.push({x:obj.x,y:obj.y});
 71         obj.list = obj.list.slice(-obj.len);
 72     }
 73 }
 74 function drawFire(){
 75     cxt.clearRect(0,0,pageWidth,pageHeight);
 76     var obj ;
 77     for(var i = 0 ; i < list.length ; i ++){
 78         obj = list[i] ;
 79         cxt.beginPath();
 80         for(var j = 0 ; j < obj.list.length ; j++){
 81             if(i == 0)
 82                 cxt.moveTo(obj.list[j].x ,obj.list[j].y);
 83             else{
 84                 cxt.lineTo(obj.list[j].x ,obj.list[j].y);
 85             }
 86         }
 87         cxt.strokeStyle = obj.color ;
 88         cxt.lineWidth = obj.level ;
 89         cxt.stroke();
 90     }
 91 }
 92 function step(){
 93     if(curLevel == 1 && list.length == 0){
 94         addFire(pageWidth/2,100,colors[curColor ++ % colors.length],2);
 95     }
 96     reviewFire();
 97     drawFire();
 98     requestAnimationFrame(step)
 99 }
100 requestAnimationFrame(step)
101 addFire(pageWidth/2,100,colors[curColor ++ % colors.length],2);
102 </script>
103 </html>

 

了解更多特效,请关注我的微信公众号: