烟花

版权声明:(๑╹◡╹)ノ""" https://blog.csdn.net/qq_41218152/article/details/82696686

烟花

一、相关补充

  1. 首先,烟花分为两个部分。分别是烟花运行轨迹和烟花的爆炸效果
  2. 先实现烟花的运动轨迹;再实现烟花的爆炸效果

二、运行轨迹

(一).判断计时器

  1. 首先,烟花需要支持计时器来实现循环地调用函数以生成烟花
  2. 重写requestAnimationFrame()方法,使得该方法兼容浏览器
window.requestAnimationFrame=(function(){
        return window.requestAnimationFrame||
                        window.webkitRequestAnimationFrame||
                        window.mozRequestAnimationFrame||
                        function(callback){
                            window.setTimeout(callback,10);
                        }
    })();

(二).预备工作

  1. 获取元素
  2. 定义变量
  3. 功能函数
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=window.innerWidth;//可视区域的宽度
var ch=window.innerHeight;//可是区域额高度
// 定义烟花数组
var fireworks=[];
//定义烟花屑数组
var particles=[];
var hue=120;
var timerTotal = 10;
/*每隔20下释放一次烟花*/
var timerTick = 0;
canvas.width=cw;//设置画布宽度
canvas.height=ch;//设置画布高度

//生成min到max之间的随机数
function random(min,max){
    return Math.random()*(max-min)+min;
}

//计算(sx,sy)到(tx,ty)之间的距离
function caculateDistance(sx, sy, tx, ty) {
     var xDistance = sx - tx;
     var yDistance = sy - ty;
     return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
}

补充
这里写图片描述

(三).定义烟花对象

  1. 定义烟花的基本属性:初始位置、目标位置、位置变量、运行距离、已运动轨迹、角度、速度、加速度、明度和半径
  2. 随机生成(50,70)之间的明度值
  3. 计算起点到终点之间的夹角及距离
//定义烟花对象
function Firework(sx, sy, tx, ty){
     this.x=sx;
     this.y=sy;
     this.sx=sx;
     this.sy=sy;
     this.tx=tx;
     this.ty=ty;
     this.distanceToTarget=caculateDistance(sx,sy,tx,ty);
     this.distanceTraveled = 0;
     //定义变量生运动轨迹
     this.coordinates = [];
     this.coordinatesCount = 3;
     while (this.coordinatesCount--) {
         this.coordinates.push([this.x, this.y]);
     }
     //初始位置到目标位置的角度
     this.angle = Math.atan2(ty - sy, tx - sx);
     this.speed = 2;//初始速度
     this.acceleration = 1.05;//加速度
     this.brightness = random(50, 70); //明度
     this.targetRadius = 5; //目标位置标示圆圈的初始半径
}

补充

angle=arctan[(ty-sy)/(tx-sx)].

(四).更新烟花位置

  1. 初始烟花半径为5,如果半径小于8,每次递增0.3;否则半径为1
  2. 新速度=加速度*原速度
  3. 将速度分解为水平速度可竖直速度
  4. 计算已经运动过的轨迹距离。如果大于总距离,则删除对应的烟花对象;否则给位置属性赋上新坐标
//开始更新烟花的位置
Firework.prototype.update = function (index) {
     this.coordinates.pop();
     this.coordinates.push([this.x, this.y]);
     //让目标圆圈动起来
     if (this.targetRadius < 8) {
         this.targetRadius += 0.3;
     }
     else {
         this.targetRadius = 1;
     }
     //根据加速度来确定速度
     this.speed *= this.acceleration;
     //计算水平方向速度
     var vx = Math.cos(this.angle) * this.speed;
     var vy = Math.sin(this.angle) * this.speed;
     //重新计算烟花运行的距离
     this.distanceTraveled = caculateDistance(this.sx, this.sy, this.x + vx, this.y + vy);
     //如果烟花运行距离大于或等于初始位置到目标位置之间的距离,生成新烟花并移除当前烟花,否则更新烟花位置
     if (this.distanceTraveled >= this.distanceToTarget) {
         createParticles(this.tx, this.ty);//创建烟花屑对象
         fireworks.splice(index, 1);
     }
     else {
        this.x += vx;
        this.y += vy;
     }
}

补充
这里写图片描述

(五).烟花的运行轨迹

  1. 将起始点移动到运动轨迹的起始位置
  2. 移动到计算出来的位置属性坐标
  3. 同时绘制烟花的圆形
//烟花运行轨迹
Firework.prototype.draw = function () {
     ctx.beginPath();
	 ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1]);
     ctx.lineTo(this.x, this.y);
     ctx.strokeStyle = 'hsl(' + hue + ',100%,' + this.brightness + '%)';
     ctx.stroke();
     //画出目标位置的小圆圈
     ctx.beginPath();
     ctx.arc(this.tx, this.ty, this.targetRadius, 0, Math.PI * 2);
     ctx.stroke();
}

(六).循环生成烟花

  1. 使用计时器循环生成烟花对象,及控制烟花的运动和爆炸效果
  2. 用循环将页面上的每一个烟花运动,缩放和爆炸
function loop() {
        hue += 0.5;
        ctx.globalCompositeOperation = 'destination-out';
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, cw, ch);
        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);
        }
        if (timerTick >= timerTotal) {
            fireworks.push(new Firework(cw / 2, ch, random(0, cw), random(0, ch / 2)));
            timerTick = 0;
        } else {
            timerTick++;
        }
        requestAnimationFrame(loop);
}
window.onload = loop();

这里写图片描述

三、爆炸效果

(一).定义烟花屑对象

  1. 定义烟花碎屑的基本属性:位置数组、角度、速度、摩擦力、重力、碎屑色调、明度、透明度和随机一个不透明度递减值
//定义烟花屑对象
    function Particle(x, y) {
        this.x = x;
        this.y = y;
        this.coordinates = [];
        this.coordinatesCount = 10;
        while (this.coordinatesCount--) {
            this.coordinates.push([this.x, this.y]);
        }
        //生成任意方向的碎屑
        this.angle = random(0, 2 * Math.PI);
        this.speed = random(1, 10);//随机速度
        this.friction = 0.95;//摩擦力
        this.gravity = 1;//重力
        this.hue = random(hue - 20, hue + 20);//生成色彩相近的碎屑
        this.brightness = random(50, 80);//随机明度
        this.alpha = 1;//初始化透明度
        this.decay = random(0.015, 0.03);//随机生成一个(0.015~0.03)之间的透明度递减值
    }

(二).循环创建烟花屑对象

  1. 当已运动过的轨迹大于等于距离时,创建烟花屑对象
  2. 封装函数,以便于方便调用
  3. 以烟花的终点位置为烟花屑移动轨迹的初始位置
function createParticles(x, y) {
        //生成300个烟花碎屑
        var particleCount = 300;
        while (particleCount--) {
            particles.push(new Particle(x, y));
        }
    }

(三).更新烟花屑位置

  1. 速度可以分解为水平速度和竖直速度,竖直方向上的速度还应该考虑重力
  2. 每次更新位置的时候,不透明度递减,直至不透明度小于不透明度递减值时,删除对应的烟花屑对象
//更新烟花屑位置
Particle.prototype.update = function (index) {
        this.coordinates.pop();
        this.coordinates.unshift([this.x, this.y]);
        this.speed *= this.friction;
        this.x += Math.cos(this.angle) * this.speed;
        this.y += Math.sin(this.angle) * this.speed + this.gravity;
        this.alpha -= this.decay;
        //当透明度小于透明度递减值时,删除烟花屑对象
        if (this.alpha <= this.decay) {
            particles.splice(index, 1);
        }
    }

(四).绘制烟花屑运动轨迹

  1. 移动烟花屑的起点坐标,移动到计算出来的烟花屑的运动轨迹
  2. hsla值
    • H:Hue(色调)。0(或360)表示红色,120表示绿色,240表示蓝色,也可取其他数值来指定颜色。取值为:0 ~ 360
    • S:Saturation(饱和度)。取值为:0.0% -~100.0%
    • L:Lightness(亮度)。取值为:0.0% ~ 100.0%
    • A:Alpha透明度。取值0~1之间
//画碎屑轨迹
    Particle.prototype.draw = function () {
        ctx.beginPath();
        ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1]);
        ctx.lineTo(this.x, this.y);
        ctx.strokeStyle = 'hsla(' + this.hue + ',100%,' + this.brightness + '%,' + this.alpha + ')';
        ctx.stroke();
    }

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_41218152/article/details/82696686