最近感觉canvas挺有意思的,在业余时间没事研究了一下,参考过网上一些思路,话不多说,开始啦。

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

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

图片效果如下:(右上角能显示FPS,是时候看看你电脑的性能了哈哈~)

先说一下思路吧,其实很简单,烟花分为两个部分:1.窜天猴。2.爆炸效果。  当穿天猴的竖直方向的速度为0的时候,让它爆炸。

下面是一些常量,后面类中会用到的

 const canvas = document.getElementById('canvasNode');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const CANVAS_WIDTH = canvas.width;
const CANVAS_HEIGHT = canvas.height;
const GRAVITATIONAL = 2.5; // 模拟重力加速度
const AIR_RESISTANCE = 1; // 模拟空气阻力
const EVERY_FIREWORK_TIME = 3; // 每个烟花的持续时间,单位:秒
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越来越低得到情况,画面会变卡,以后可能的话要在进行优化一下,也可以和大家讨论一下如何优化会更好,可以在评论区指导一下呀,感谢大家提出宝贵的意见~

canvas制作的烟花效果的更多相关文章

  1. 酷!使用 jQuery & Canvas 制作相机快门效果

    在今天的教程中,我们将使用 HTML5 的 Canvas 元素来创建一个简单的摄影作品集,它显示了一组精选照片与相机快门的效果.此功能会以一个简单的 jQuery 插件形式使用,你可以很容易地整合到任 ...

  2. 如何使用 HTML5 Canvas 制作水波纹效果

    今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果.水波效果以图片为背景,点击图片任意位置都会触发.有时候,我们使用普通的 Javasc ...

  3. canvas制作倒计时炫丽效果

    <!DOCTYPE html> <head> <title>canvas倒计时</title> <style> .canvas{ displ ...

  4. WEB烟花效果——Canvas实现

    摘要        本文主要介绍一种WEB形式的烟花(fireworks)效果(图1所示),该效果基于Canvas实现,巧妙地运用了canvas绘图的特性,并加入了物理力作用的模拟,使整体效果非常绚丽 ...

  5. 还在用canvas画格子吗?文字烟花效果更不错噢

    大家好,我是小丞同学,一名前端爱好者 欢迎访问博主的个人网站:一口奶盖 "在人间贩卖声音 等凑够满天星辰 放烟花给你看" 上次的烟花有些许平淡,这次来放大招了,让你的名字在天空绽放 ...

  6. 用Canvas制作简单的画图工具

    今天用Canvas制作了一个画图工具,非常简单,功能也不是很多,主要有背景网格,画线,画圆,画矩形和画圆角矩形,也用到了canvas的一些基本知识,在这里一一列举. 1.线段的绘制: 如何绘制真正的1 ...

  7. WPF设置VistualBrush的Visual属性制作图片放大镜效果

    原文:WPF设置VistualBrush的Visual属性制作图片放大镜效果 效果图片:原理:设置VistualBrush的Visual属性,利用它的Viewbox属性进行缩放. XAML代码:// ...

  8. H5上传图片并使用canvas制作海报

    马上就要"十一"国庆节了,又恰逢公司已经三周岁了,所以市场部和产品共同策划了一个"正青春,共成长"的主题代言活动,准备在国庆节以及中秋节期间让公司员工和用户为公 ...

  9. 使用Canvas制作时钟动画

    复习Javascript到Canvas的知识点,看到一个使用Canvas绘制的静态时钟例子,便想将其变成动态显示系统时间的时钟动画.另外再配上数字显示的时钟,一个小的时钟模块的诞生了!目前的界面还比较 ...

随机推荐

  1. Mybatis学习第二天——mapper的动态代理

    传统的Dao层开发通过接口与实现类的方式,Mybatis中通过mapper动态代理是需要定义接口. 1.传统Dao层封装 那么可以将公共资源提取出来,剩余的封装成方法来实现.下面是UserDaoImp ...

  2. Mac系统操作指南

    OSX 采用的Unix文件系统,所有文件都挂在跟目录“ /” 下面,所以不在要有Windows 下的盘符概念.比如什么“C:”你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做“XX” ...

  3. 搭建高可用mongodb集群(二)—— 副本集

    在上一篇文章<搭建高可用MongoDB集群(一)--配置MongoDB> 提到了几个问题还没有解决. 主节点挂了能否自动切换连接?目前需要手工切换. 主节点的读写压力过大如何解决? 从节点 ...

  4. spider-抓取网页内容

    使用urllib2抓取网页内容: import urllib2 from HTMLParser import HTMLParser request = urllib2.Request('http:// ...

  5. Java学习---传输安全设计

    1.计算机安全的概念 用于保护数据和阻止Hacker的工具统称为计算机安全(Computer Security).信息安全最基本的方法就是利用加密信息防止未授权的人窃听,加密是以某种特殊的算法改变原有 ...

  6. js的一道经典题目

    今天碰到一道题,里面既包含了匿名函数的知识,也包含了预编译,函数的传参(形参),感觉迷迷糊糊的,所以想着做个总结. var foo={n:1}; (function(foo){ console.log ...

  7. 如何让4年前的电脑装win10开机跑进15秒

    我是用我的电脑测试的.看看我电脑的配置 我的是windows10,机械硬盘. 在这里要说的是给电脑优化,让其开机更快.当然,因电脑配置而异,我的最快是11秒.标题可能有点夸张了,结果因电脑配置而异,高 ...

  8. Linux中脚本的使用方法

    Linux中脚本的使用方法 一.前言 关于Linux中的脚本的用法,一直没有时间去好好地总结,正好今天下雨,就好好的整理一下思路吧,其实精通了一门语言,比如C语言,学习其他语言需要的成本是非常少的,同 ...

  9. 内置模块之os

    os模块主要对操作系统进行调用的接口 一.os模块常用方法和属性 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("d:") 改变 ...

  10. December 31st 2016 Week 53rd Saturday

    In every triumph, there's a lot of try. 每个胜利背后都有许多尝试. This Year is over, and let it be. It would be ...