专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员的那些事  ·  GPU:DeepSeek ... ·  7 小时前  
程序员的那些事  ·  OpenAI ... ·  2 天前  
程序员小灰  ·  清华大学《DeepSeek学习手册》(全5册) ·  3 天前  
程序猿  ·  “未来 3 年内,Python 在 AI ... ·  5 天前  
51好读  ›  专栏  ›  SegmentFault思否

程序员的小浪漫----烟火

SegmentFault思否  · 公众号  · 程序员  · 2018-02-25 09:01

正文

多代码,慎读!!!

预览

完整项目预览----预览地址;

属性设计

烟花状态 :烟花应有三个状态:

  1. 升空

  2. 等待炸裂

  3. 炸裂后

烟花 :发射点(x, y),爆炸点(xEnd, yEnd),升空后等待炸裂时间(wait),炸裂后微粒个数(count),烟花半径(radius)

烟花炸裂后微粒 :自身位置(x, y),自身大小(size),自身速度(rate),最大烟花半径(radius)。

config :为全局变量,以及控制参数,包括画布宽高,设定烟花属性等。

设定全局变量

  1. const config = {

  2.    width: 360,

  3.    height: 600,

  4.    canvases: ['bg', 'firework'],

  5.    skyColor: '210, 60%, 5%, 0.2)',

  6.    fireworkTime:{min:30,max:60},

  7.    //烟花参数本身有默认值 传入undefined则使用默认参数

  8.    fireworkOpt:{

  9.        x: undefined,

  10.        y: undefined,

  11.        xEnd : undefined,

  12.        yEnd: undefined,

  13.        count: 300,   //炸裂后粒子数

  14.        wait: undefined,  //消失后 => 炸裂  等待时间

  15.    }

  16. }

构建微粒类

  1. class Particle{

  2.    //默认值写法

  3.    constructor({x, y, size = 1, radius = 1.2} = {}){

  4.        this.x = x;

  5.        this.y = y;

  6.        this.size = size;

  7.        this.rate = Math.random(); //每个微粒移动的速度都是随机不同的

  8.        this.angle = Math.PI * 2 * Math.random(); //每个微粒的偏移角度

  9.        //每次微粒移动速度分解为横纵坐标的移动。

  10.        this.vx = radius * Math.cos(this.angle) * this.rate;

  11.        this.vy = radius * Math.sin(this.angle) * this.rate;

  12.    }

  13.    go(){

  14.        this.x += this.vx;

  15.        this.y += this.vy;

  16.        this.vy += 0.02; //重力影响 y越大实际越偏下

  17.        //空气阻力

  18.        this.vx *= 0.98;

  19.        this.vy *= 0.98;

  20.    }

  21.    //画出微粒的位置

  22.    render(ctx){

  23.        this.go();

  24.        ctx .beginPath();

  25.        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);

  26.        ctx.fill();

  27.    }

  28. }

构建烟花类

  1. class Firework{

  2.    constructor({x, y = config.height, xEnd, yEnd, count = 300, wait} = {}){

  3.        //烟花自身属性

  4.        this.x = x || config.width / 8 + Math.random() * config.width * 3 / 4;

  5.        this.y = y;

  6.        this.xEnd = xEnd || this.x;

  7.        this.yEnd = yEnd || config.width / 8 + Math.random() * config.width * 3 / 8;

  8.        this.size = 2;

  9.        this.velocity = -3;

  10.         this.opacity = 0.8;

  11.        this.color = `hsla(${360 * Math.random() | 0},80%,60%,1)`;

  12.        this.wait = wait || 30 + Math.random() * 30;

  13.        //微粒个数等

  14.        this.count = count;

  15.        this.particles = [];

  16.        this.createParticles();

  17.        this.status = 1 ;

  18.    }

  19.    //创建微粒

  20.    createParticles(){

  21.        for(let i = 0;i < this.count; ++i){

  22.            this.particles.push(new Particle({x:this.xEnd, y:this.yEnd}));

  23.        }

  24.    }

  25.    //升空

  26.    rise(){

  27.        this.y += this.velocity * 1;

  28.        this.velocity += 0.005 ; //升空时产生的阻力

  29.        //烟花升空到目标位置开始渐隐

  30.        if(this.y - this.yEnd <= 50){

  31.            this.opacity = (this.y - this.yEnd) / 50;

  32.        }

  33.        //如果到了目标位置 就开始第二个状态

  34.        if(this.y <= this.yEnd){

  35.            this.status = 2;

  36.        }

  37.    }

  38.    //渲染烟花  烟花所有动作完成之后返回false

  39.    render( ctx){

  40.        switch(this.status){

  41.            case 1: //升空

  42.            ctx.save();

  43.            ctx.beginPath();

  44.            ctx.globalCompositeOperation = 'lighter';

  45.            ctx.globalAlpha = this.opacity;

  46.            ctx.translate(this.x, this.y);

  47.            ctx.scale(0.8, 2.3);

  48.            ctx.translate(-this.x, -this.y);

  49.            ctx.fillStyle = this.color;

  50.            ctx.arc(this.x + Math.sin(Math.PI * 2 * Math.random()) / 1.2, this.y, this.size, 0, Math.PI * 2, false);

  51.            ctx.fill();

  52.            ctx.restore();

  53.            this.rise();

  54.            return true;

  55.            break;

  56.            case 2: //烟花消失阶段,等待炸裂

  57.            if(--this.wait <= 0){

  58.                this.opacity = 1;

  59.                this.status = 3;

  60.            }

  61.            return true;

  62.            break;

  63.            case 3: //炸裂之后 渲染烟花微粒

  64.            ctx.save();

  65.            ctx.globalCompositeOperation = 'lighter';

  66.            ctx.globalAlpha = this.opacity;

  67.            ctx.fillStyle = this.color;

  68.             for(let i = 0;i < this.particles.length;++i){

  69.            this.particles[i].render(ctx);

  70.            }

  71.            ctx.restore();

  72.            this.opacity -= 0.01;

  73.            return this.opacity > 0;

  74.            break;

  75.            default:

  76.            return false;

  77.        }

  78.    }

  79. }

放烟花

  1. const canvas = {

  2.    init: function(){

  3.        //一些属性的设定 可以不用管

  4.        this.setProperty();

  5.        this.renderBg();

  6.        //循环体 **主要

  7.        this.loop();

  8.    },

  9.    setProperty: function(){

  10.        this.fireworks = [];

  11.        this.width = config.width;

  12.        this.height = config.height;

  13.        this.fireworkTime = ( config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0;

  14.        this.bgCtx = document.querySelector('#bg').getContext('2d');

  15.        this.fireworkCtx = document.querySelector('#firework').getContext('2d');

  16.    },

  17.    renderBg(){

  18.        this.bgCtx.fillStyle = 'hsla(210, 60%, 5%, 0.9)'

  19.        this.bgCtx.fillRect(0, 0, this.width, this.height);

  20.    },

  21.    loop(){

  22.        requestAnimationFrame(this.loop.bind(this));

  23.        this.fireworkCtx.clearRect(0, 0, this.width, this.height);

  24.        //随机创建烟花

  25.        if(--this.fireworkTime <= 0){

  26.            







请到「今天看啥」查看全文