canvas製作的煙花效果

来源:https://www.cnblogs.com/zxsm/archive/2019/04/07/10666643.html
-Advertisement-
Play Games

最近感覺canvas挺有意思的,在業餘時間沒事研究了一下,參考過網上一些思路,話不多說,開始啦。 github地址:https://github.com/aWhiteBear/fireworks 演示地址:https://awhitebear.github.io/fireworks/ 圖片效果如下: ...


最近感覺canvas挺有意思的,在業餘時間沒事研究了一下,參考過網上一些思路,話不多說,開始啦。

github地址:https://github.com/aWhiteBear/fireworks

演示地址:https://awhitebear.github.io/fireworks/

圖片效果如下:(右上角能顯示FPS,是時候看看你電腦的性能了哈哈~)

 

先說一下思路吧,其實很簡單,煙花分為兩個部分:1.竄天猴。2.爆炸效果。  當穿天猴的豎直方向的速度為0的時候,讓它爆炸。

下麵是一些常量,後面類中會用到的

 1 const canvas = document.getElementById('canvasNode');
 2 const ctx = canvas.getContext('2d');
 3 canvas.width = window.innerWidth;
 4 canvas.height = window.innerHeight;
 5 const CANVAS_WIDTH = canvas.width;
 6 const CANVAS_HEIGHT = canvas.height;
 7 const GRAVITATIONAL = 2.5; // 模擬重力加速度
 8 const AIR_RESISTANCE = 1; // 模擬空氣阻力
 9 const EVERY_FIREWORK_TIME = 3; // 每個煙花的持續時間,單位:秒
10 const FRAME = 60;
class FlyingMonkey{ // 竄天猴,發射升空的,目前只能垂直發射
    constructor(x,y,speedX,speedY){
        this.x = x; // x,y 是竄天猴的位置坐標
        this.y = y;
        this.speedX = speedX;
        this.speedY = speedY;
        this.opacity = 1;
        this.count = 50; // 竄天猴和其尾巴由這50個圓繪製而成
        for(let i=0;i<this.count;i++){
            this.createCircle(i);
        }
    }
    createCircle(i) { // 創建竄天猴的圈圈尾巴
        ctx.beginPath();
        ctx.save();
        ctx.globalCompositeOperation = 'lighter';
        ctx.fillStyle = `rgba(245,123,63,${this.opacity})`;
        ctx.arc(this.x + (Math.random()-0.5) * i/10 + i/this.count * this.speedX, this.y + i/this.count * this.speedY ,8 - (6 * i/this.count),0,2 * Math.PI);
        ctx.fill();
        ctx.restore();
        ctx.closePath();
    }
}

上面是竄天猴類,就是最開始向上發射的煙花,下麵煙花類

class Firework { // 煙花,爆炸的
    constructor(x,y,speedX,speedY){
        this.x = x;
        this.y = y;
        this.speedX = speedX;
        this.speedY = speedY;
        this.opacity = 1;
        this.count = 500; // 煙花的爆炸效果由500個點組成
        this.AllFireworks = [];

        this.createAllFirework();
        Launch.arrFirework.push(this);
    }
    createAllFirework(){
        let r = Math.floor(Math.random()*256), g = Math.floor(Math.random()*256) , b =Math.floor(Math.random()*256);
        for(let i=0;i<this.count;i++){
            this.AllFireworks.push({
                r,g,b,
                x:this.x,
                y:this.y,
                opacity:1,
                speedX:this.speedX * i/this.count*10 *(Math.random()-0.5),
                speedY:this.speedY * i/this.count*10 *(Math.random()-0.5)
            });
        }
        this.updateAllFirework();
    }
    updateAllFirework(){
        for(let i=0;i<this.AllFireworks.length;i++){
            let {r,g,b,x,y,speedX,speedY,opacity} = this.AllFireworks[i];
            this.AllFireworks[i].y = y - speedY/FRAME;
            this.AllFireworks[i].x = x - speedX/FRAME;
            this.AllFireworks[i].opacity = opacity - 1/ FRAME / EVERY_FIREWORK_TIME;
            this.AllFireworks[i].speedY = speedY - GRAVITATIONAL;
            if(Math.abs(speedX)>3/FRAME) { // 速度<= 3/FRAME 認為停止了
                this.AllFireworks[i].speedX = speedX - (speedX>0?AIR_RESISTANCE:(AIR_RESISTANCE*(-1)));
            } else {
                this.AllFireworks[i].speedX = 0;
            }
            ctx.beginPath();
            ctx.save();
            ctx.globalCompositeOperation = 'lighter';
            ctx.fillStyle = `rgba(${r},${g},${b},${this.AllFireworks[i].opacity})`;
            ctx.arc(this.AllFireworks[i].x , this.AllFireworks[i].y  ,2,0,2 * Math.PI);
            ctx.fill();
            ctx.restore();
            ctx.closePath();
        }
    }
}

下麵是start類,用來發射竄天猴

class Start{
    constructor(x,y,speedX,speedY){
        Launch.arrFlyingMonkey.push(this);
        this.x = x;
        this.y = y;
        this.speedX = speedX;
        this.speedY = speedY;
        this.begin();
    }
    begin(){
        this.y = this.y - this.speedY/FRAME; // 速度減小
        this.x = this.x - this.speedX/FRAME;
        this.speedY = this.speedY - GRAVITATIONAL;
        new FlyingMonkey(this.x, this.y, this.speedX, this.speedY);
    }
}

下麵是發射類,是用【requestAnimationFrame】來渲染的動畫

class Launch{ // 發射
    constructor(){
        this.fps=0;
        this.sum=0;// 幀數計數器 60幀一迴圈
        this.draw = this.draw.bind(this);
        this.draw();
    }
    draw(){
        ctx.clearRect(0,0,CANVAS_WIDTH,CANVAS_HEIGHT);
        this.updateFps();
        Launch.arrFlyingMonkey.forEach((item,i)=>{
            item.begin();
            if(item.speedY < 0){
                Launch.arrFlyingMonkey.splice(i,1);
                new Firework(item.x,item.y,7*7,5*7); // 煙花寬高比:7:5
            }
        });
        Launch.arrFirework.forEach((item,i)=>{
            item.updateAllFirework();
        });
        if(Launch.arrFirework.length>5){ // 清理arrFirework,避免占用過多記憶體,其實還可以通過 EVERY_FIREWORK_TIME 和 Launch.timer 更及時清理。length > EVERY_FIREWORK_TIME/Launch.timer
            Launch.arrFirework.shift();
        }
        requestAnimationFrame(this.draw);
    }
    updateFps(){
        if(this.sum++>=60){
            this.sum = 0;
            let nowTime = new Date().getTime();
            this.fps = 60/(nowTime - Launch.lastTime) *1000;
            Launch.lastTime = nowTime;
        }
        ctx.save();
        ctx.fillStyle = 'red';
        ctx.font="20px Arial";
        ctx.fillText(`FPS: ${~~this.fps}`,CANVAS_WIDTH - 100,50);
        ctx.restore();
    }
}

然後添加Launch靜態屬性

/** 添加Launch靜態屬性*/
Launch.arrFlyingMonkey = [];
Launch.arrFirework = [];
Launch.timer = setInterval(()=>{
    new Start(CANVAS_WIDTH * (Math.random() * 0.8 + 0.1),CANVAS_HEIGHT * 0.9,0,300 *(Math.random()*0.5 + 1));
},1500);
Launch.lastTime = new Date().getTime();

最後在  new Launch(); 就能發射出去啦。

代碼還有好多可以優化的地方,在一些手機瀏覽器上會出現fps越來越低得到情況,畫面會變卡,以後可能的話要在進行優化一下,也可以和大家討論一下如何優化會更好,可以在評論區指導一下呀,感謝大家提出寶貴的意見~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 文章大綱 一、什麼是Material Dialogs二、Material Dialogs實戰三、項目源碼下載 一、什麼是Material Dialogs Material Dialogs是一個漂亮、流暢、可定製的對話框,核心模塊包含創建基本、列表、單/多選項、進度、輸入等對話框。 二、Materia ...
  • 文章大綱 一、Lottie介紹二、Lottie實戰三、項目源碼下載四、參考文章 一、Lottie介紹 1. 什麼是Lottie Lottie是Android和iOS的移動庫,用於解析Adobe After Effects動畫與Bodymovin一起導出為json 併在移動設備上呈現它們!其實在移動端 ...
  • 文章大綱 一、Android崩潰日誌管理簡介二、崩潰日誌管理實戰三、項目源碼下載 一、Android崩潰日誌管理簡介 1. 什麼是android崩潰日誌管理 開發中有些地方未註意可能造成異常拋出未能caught到,然後彈出系統對話框強制退出。這種交互不好,而且開發者也不能及時獲取到底哪裡出問題。因此 ...
  • 本文是前端系列的開篇,以重覆造輪子做為引子,用本人的一個javascript類庫向初入門的前端小伙伴分享一下我對前端開發的積累,要求熟悉基礎的html和css,熟悉javascript語法,該前端系列包含基礎知識:節點的選擇與過濾,事件維護(綁定及解除及觸屏端的點擊模擬),模塊拖動,基礎動效(位置及... ...
  • 本篇是《你不知道的JavaScript》的讀書筆記 什麼是作用域? 程式離不變數,那麼變數存儲在哪裡?程式需要時如何找到他們? 這些問題說明需要一套設計良好的 規則 來存儲變數, 並且之後可以方便地找到這些變數。這套規則被稱為 作用域 。 作用域負責收集並維護由所有聲明的標識符(變數) 組成的一系列 ...
  • 項目需求: 實現一個購物車 全選框實現對商家和商品的全選 商家全選框實現對當前商家所有商品的全選 取消其中一個商品則取消對應商家全選和全選框 選中一個商家下的所有商品則勾選對應商家的全選框,不勾選全選框 選中所有商品則勾選所有商家全選框和全選框 我的思路: 1、通過對數據的簡單操作可實現更深層次的全 ...
  • 在本地測試的json沒有問題,但是打包後,發現json 的路徑不對了,變成了絕對路徑 解決方法: 建立的json文件需要放置 根目錄/static下。如項目名/static/data.json,這邊打包後就不會報路徑問題了。(請用起服務的方法來打開打包後的index.html,如anywhere來打 ...
  • 1、我在打包完成後,打開index.html文件發現地址並沒有攜帶路由。 config下的 index.js 中的build命令的配置有一個屬性叫assetsPublicPath,它的值為‘/’。意思是根目錄,這時會從index.html所在的硬碟的根目錄下開始查找,自然無法找到。 解決辦法: 改為 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...