App下載

JS如何實(shí)現(xiàn)酷炫的煙花特效?(附源碼)

猿友 2021-03-10 18:01:05 瀏覽數(shù) (12377)
反饋

想必有不少人喜歡看煙花吧!絢麗的煙花在黑空中迸發(fā)出完美的粒子光芒,并最終無限暗淡至隕落。煙花雖美但易逝,自然是不能經(jīng)常看到煙花的,那么如果編寫一段代碼,讓它實(shí)現(xiàn)煙花綻放效果不就可以了。其實(shí)煙花效果并不難實(shí)現(xiàn),僅需用到 JavaScript 即可。

先讓我們來看下實(shí)現(xiàn)效果:

yanhua

源碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>JS實(shí)現(xiàn)煙花特效-W3C技術(shù)頭條</title>
    <style>
        body{
            margin: 0;
            padding: 0;
            background: url("./images/background-image.png") no-repeat center center fixed;
                /*兼容瀏覽器版本*/
                -webkit-background-size: cover;
                -o-background-size: cover;                
                background-size: cover;
        }
    </style>
</head>
<body>
<canvas id="mycanvas"></canvas>
<script>
    //window.requestAnimationFrame()這個(gè)API是瀏覽器提供的js全局方法,針對(duì)動(dòng)畫效果。
    window.requestAnimationFrame=(function(){
        return window.requestAnimationFrame||
                        window.webkitRequestAnimationFrame||
                        window.mozRequestAnimationFrame||
                        function (callback){
                            window.setTimeout(callback,1000)
                            //每間隔10秒執(zhí)行一次動(dòng)畫
                        }
    })();
    //獲取canvas區(qū)域.并設(shè)置寬和高
    var area=document.getElementById("mycanvas");
    area.width=document.documentElement.clientWidth;
    area.height=document.documentElement.clientHeight;
    //轉(zhuǎn)換成2d模型
    var ctx=area.getContext("2d");
    //煙花數(shù)組
    hue=120;//設(shè)置顏色范圍
    timerTick = 0;//計(jì)時(shí)器
    timerTotal=5;//每間隔5秒煙花綻放一次
    fireworks=[];//存放煙花數(shù)組
    particles=[];//存放碎屑數(shù)組
    //隨機(jī)min和max之間的值
    function random(min,max){
        return Math.random()*(max-min)+min;
    }
    //計(jì)算兩點(diǎn)之間的距離
    function distans(sx,sy,tx,ty){
        var xdistan=sx-tx;
        var ydistan=sy-ty;
        return Math.sqrt((Math.pow(xdistan,2)+Math.pow(ydistan,2)));
    }
    //定義煙花對(duì)象
    function Firework(sx,sy,tx,ty){
        this.x=sx;
        this.y=sy;
        this.sx=sx;
        this.sy=sy;
        this.tx=tx;
        this.ty=ty;
        //計(jì)算兩點(diǎn)之間的距離
        this.targetDistances=distans(sx,sy,tx,ty);
        //運(yùn)行距離
        this.distancesc=0;
        //定義變量生成的運(yùn)動(dòng)軌跡
        this.guiji=[];
        this.guijicount=3;
        while(this.guijicount--){
            this.guiji.push([this.x,this.y]);
        }
        //計(jì)算角度
        this.angle=Math.atan2(ty-sy,tx-sx);
        this.speed=2;
        this.jiasudu=1.05;
        this.brightness=random(50,70);//煙花的明度
        this.targetRad=5;//煙花小圈的半徑
    }
    //更新煙花的位置
    Firework.prototype.update=function(index){
        this.guiji.pop();
        this.guiji.push([this.x,this.y]);
        //目標(biāo)圓運(yùn)動(dòng)
        if(this.targetRad<8){
            this.targetRad+=0.3;
        }else{
            this.targetRad=1;
        }
        //根據(jù)加速度計(jì)算速度并且計(jì)算出煙花運(yùn)行過程中x軸和y軸的速度
        this.speed*=this.jiasudu;
        var vx=Math.cos(this.angle)*this.speed;
        var vy=Math.sin(this.angle)*this.speed;
        //重新計(jì)算兩點(diǎn)之間的距離
        this.distancesc=distans(this.sx,this.sy,this.x+vx,this.y+vy);
        //如果煙花運(yùn)行距離大于或等于初始位置到目標(biāo)位置之間的距離,生成新煙花并移除當(dāng)前煙花,否則更新煙花位置
        if(this.distancesc>=this.targetDistances){
            //生成煙花碎屑
            createparticals(this.tx,this.ty);
            //銷毀煙花小圈
            fireworks.splice(index,1)
        }else{
            this.x+=vx;
            this.y+=vy;
        }
    }
 
    //開始畫運(yùn)行軌跡
    Firework.prototype.draw=function(){
        ctx.beginPath();
        //軌跡的起點(diǎn)
        ctx.moveTo(this.guiji[this.guiji.length-1][0],this.guiji[this.guiji.length-1][1]);
        //繪制線條到目標(biāo)點(diǎn)
        ctx.lineTo(this.x,this.y);
        //畫出不同顏色的煙花
        ctx.strokeStyle='hsl('+hue+',100%,'+this.brightness+'%)';
        ctx.stroke();//繪制煙花軌跡
        //畫出目標(biāo)小圓
        ctx.beginPath();
        ctx.arc(this.tx,this.ty,this.targetRad,0,Math.PI*2);
        ctx.stroke();
    }
    //定義煙花碎屑方法
    function Particle(x, y) {
        this.x = x;
        this.y = y;
        this.guiji = [];
        this.guijicount = 10;
        while(this.guijicount--){
            this.guiji.push([this.x,this.y]);
        }
        //生成任意方向的碎屑
        this.angle=random(0 , 2*Math.PI);
        this.speed=random(1,10);//隨機(jī)的速度
        this.mocal=0.95;//摩擦力
        this.gravity=0.98;//重力
        this.hue=random(hue-20,hue+20);//碎屑顏色變化范圍
        this.brightness=random(50,80);
        this.alpha=1;//定義碎屑初始不透明
        this.decay=random(0.015,0.03);//碎屑消失的時(shí)間
    }
    //更新碎屑
    Particle.prototype.update=function(index){
        this.guiji.pop();
        //unshift() 方法可向數(shù)組的開頭添加一個(gè)或更多元素,并返回新的長(zhǎng)度。
        this.guiji.unshift([this.x,this.y]);
        //下面是煙花碎屑的運(yùn)動(dòng)
        this.speed*=this.mocal;
        this.x+=Math.cos(this.angle)*this.speed;
        this.y+=Math.sin(this.angle)*this.speed+this.gravity;
        this.alpha-=this.decay;//不透明度一直隨時(shí)間變?yōu)?;即煙花碎屑消失
        if(this.alpha<=this.decay){
            particles.splice(index,1)//銷毀煙花碎屑
        }
    }
    //畫煙花碎屑軌跡
    Particle.prototype.draw=function(){
        ctx.beginPath();
        ctx.moveTo(this.guiji[this.guiji.length-1][0],this.guiji[this.guiji.length-1][1]);
        ctx.lineTo(this.x,this.y);
        //畫出不同顏色的煙花利用HSL
        ctx.strokeStyle='hsl('+hue+',100%,'+this.brightness+'%)';
        ctx.stroke();
    }
    //創(chuàng)建碎屑
    function createparticals(x,y){
        //設(shè)定碎屑數(shù)目
        var particalcount=500;
        while(particalcount--){
            //隨著碎屑數(shù)目的減少為0,又重新調(diào)用碎屑方法
            particles.push(new Particle(x,y))
        }
    }
    //獲取屏幕的寬和高
    var clientw=document.documentElement.clientWidth;
    var clienth=document.documentElement.clientHeight;
    function loop(){
        //requestAnimationFrame() 方法來告訴瀏覽器需要執(zhí)行的動(dòng)畫,
        // 并讓瀏覽器在下一次重繪之前調(diào)用指定的函數(shù)來更新動(dòng)畫。
        requestAnimationFrame(loop);
        hue+=0.5;
        //在源圖像外顯示目標(biāo)圖像。只有源圖像外的目標(biāo)圖像部分會(huì)被顯示,源圖像是透明的。
        ctx.globalCompositeOperation = 'destination-out';
        ctx.fillRect(0,0,clientw,clienth);
        ctx.fillStyle='rgb(0,0,0,0.5)';
        //顯示源圖像和目標(biāo)圖像。
        ctx.globalCompositeOperation='lighter';
        var i=fireworks.length;
        while(i--){
            fireworks[i].draw();
            fireworks[i].update(i);
        }
        var i=particles.length;
        while(i--){
            particles[i].draw();
            particles[i].update(i);
        }
        //此時(shí),我們還沒有創(chuàng)建任何的煙花。我們希望設(shè)置一個(gè)定時(shí)時(shí)間timerTotal,周期性的
        // 產(chǎn)生一個(gè)煙花,我們也需要一個(gè)時(shí)間計(jì)數(shù)timerTick,在每次幀更新的時(shí)候加1,記下幀更新的次數(shù)。
        if(timerTick>=timerTotal)
        {
            fireworks.push(new Firework(clientw/2,clienth,random(0,clientw),random(0,clienth)));
            timerTick=0;
        }
        else{
            timerTick++;
        }
    }
    window.οnlοad=loop();
</script>
</body>
</html>

如果沒有黑夜背景圖,可以直接把背景顏色設(shè)置為黑色。

background-color: black;

以上就是用 JS 實(shí)現(xiàn)煙花效果的全部代碼。快點(diǎn)動(dòng)手操作這個(gè)有趣的代碼吧?。?/p>

推薦課程:JavaScript 實(shí)戰(zhàn):動(dòng)態(tài)網(wǎng)站開發(fā)



10 人點(diǎn)贊