JavaScript 用画布标签制作的烟花

JavaScript 用画布标签制作的烟花

HTML代码:

<div></div>

CSS代码:

body {
  background-image: linear-gradient(6deg, #214, #000);
  background-size: 100% 100%;overflow: hidden
}

canvas { display: block; }

JS代码:

class Vector2 {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  add(v) {
    this.x += v.x;
    this.y += v.y;
    return this;
  }

  multiplyScalar(s) {
    this.x *= s;
    this.y *= s;
    return this;
  }

  clone() {
    return new Vector2(this.x, this.y);
  }}


class Time {
  constructor() {
    const now = Time.now();

    this.delta = 0;
    this.elapsed = 0;
    this.start = now;
    this.previous = now;
  }

  update() {
    const now = Time.now();

    this.delta = now - this.previous;
    this.elapsed = now - this.start;
    this.previous = now;
  }

  static now() {
    return Date.now() / 1000;
  }}


class Particle {
  constructor(position, velocity = new Vector2(), color = 'white', radius = 1, lifetime = 1, mass = 1) {
    this.position = position;
    this.velocity = velocity;
    this.color = color;
    this.radius = radius;
    this.lifetime = lifetime;
    this.mass = mass;

    this.isInCanvas = true;
    this.createdOn = Time.now();
  }

  update(time) {
    if (!this.getRemainingLifetime()) {
      return;
    }

    this.velocity.add(Particle.GRAVITATION.clone().multiplyScalar(this.mass));
    this.position.add(this.velocity.clone().multiplyScalar(time.delta));
  }

  render(canvas, context) {
    const remainingLifetime = this.getRemainingLifetime();

    if (!remainingLifetime) return;

    const radius = this.radius * remainingLifetime;

    context.globalAlpha = remainingLifetime;
    context.globalCompositeOperation = 'lighter';
    context.fillStyle = this.color;

    context.beginPath();
    context.arc(this.position.x, this.position.y, radius, 0, Math.PI * 2);
    context.fill();
  }

  getRemainingLifetime() {
    const elapsedLifetime = Time.now() - this.createdOn;
    return Math.max(0, this.lifetime - elapsedLifetime) / this.lifetime;
  }}


Particle.GRAVITATION = new Vector2(0, 9.81);

class Trail extends Particle {
  constructor(childFactory, position, velocity = new Vector2(), lifetime = 1, mass = 1) {
    super(position, velocity);

    this.childFactory = childFactory;
    this.children = [];
    this.lifetime = lifetime;
    this.mass = mass;

    this.isAlive = true;
  }

  update(time) {
    super.update(time);

    // Add a new child on every frame
    if (this.isAlive && this.getRemainingLifetime()) {
      this.children.push(this.childFactory(this));
    }

    // Remove particles that are dead
    this.children = this.children.filter(function (child) {
      if (child instanceof Trail) {
        return child.isAlive;
      }

      return child.getRemainingLifetime();
    });

    // Kill trail if all particles fade away
    if (!this.children.length) {
      this.isAlive = false;
    }

    // Update particles
    this.children.forEach(function (child) {
      child.update(time);
    });
  }

  render(canvas, context) {
    // Render all children
    this.children.forEach(function (child) {
      child.render(canvas, context);
    });
  }}


class Rocket extends Trail {
  constructor(childFactory, explosionFactory, position, velocity = new Vector2()) {
    super(childFactory, position, velocity);

    this.explosionFactory = explosionFactory;
    this.lifetime = 10;
  }

  update(time) {
    if (this.getRemainingLifetime() && this.velocity.y > 0) {
      this.explosionFactory(this);
      this.lifetime = 0;
    }

    super.update(time);
  }}


const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const time = new Time();
let rockets = [];

const getTrustParticleFactory = function (baseHue) {
  function getColor() {
    const hue = Math.floor(Math.random() * 15 + 30);
    return `hsl(${hue}, 100%, 75%`;
  }

  return function (parent) {
    const position = this.position.clone();
    const velocity = this.velocity.clone().multiplyScalar(-.1);
    velocity.x += (Math.random() - .5) * 8;
    const color = getColor();
    const radius = 1 + Math.random();
    const lifetime = .5 + Math.random() * .5;
    const mass = .01;

    return new Particle(position, velocity, color, radius, lifetime, mass);
  };
};

const getExplosionFactory = function (baseHue) {
  function getColor() {
    const hue = Math.floor(baseHue + Math.random() * 15) % 360;
    const lightness = Math.floor(Math.pow(Math.random(), 2) * 50 + 50);
    return `hsl(${hue}, 100%, ${lightness}%`;
  }

  function getChildFactory() {
    return function (parent) {
      const direction = Math.random() * Math.PI * 2;
      const force = 8;
      const velocity = new Vector2(Math.cos(direction) * force, Math.sin(direction) * force);
      const color = getColor();
      const radius = 1 + Math.random();
      const lifetime = 1;
      const mass = .1;

      return new Particle(parent.position.clone(), velocity, color, radius, lifetime, mass);
    };
  }

  function getTrail(position) {
    const direction = Math.random() * Math.PI * 2;
    const force = Math.random() * 128;
    const velocity = new Vector2(Math.cos(direction) * force, Math.sin(direction) * force);
    const lifetime = .5 + Math.random();
    const mass = .075;

    return new Trail(getChildFactory(), position, velocity, lifetime, mass);
  }

  return function (parent) {
    let trails = 32;
    while (trails--) {
      parent.children.push(getTrail(parent.position.clone()));
    }
  };
};

const addRocket = function () {
  const trustParticleFactory = getTrustParticleFactory();
  const explosionFactory = getExplosionFactory(Math.random() * 360);

  const position = new Vector2(Math.random() * canvas.width, canvas.height);
  const thrust = window.innerHeight * .75;
  const angle = Math.PI / -2 + (Math.random() - .5) * Math.PI / 8;
  const velocity = new Vector2(Math.cos(angle) * thrust, Math.sin(angle) * thrust);
  const lifetime = 3;

  rockets.push(new Rocket(trustParticleFactory, explosionFactory, position, velocity, lifetime));

  rockets = rockets.filter(function (rocket) {
    return rocket.isAlive;
  });
};

const render = function () {
  requestAnimationFrame(render);

  time.update();
  context.clearRect(0, 0, canvas.width, canvas.height);

  rockets.forEach(function (rocket) {
    rocket.update(time);
    rocket.render(canvas, context);
  });
};

const resize = function () {
  canvas.height = window.innerHeight;
  canvas.width = window.innerWidth;
};

canvas.onclick = addRocket;
document.body.appendChild(canvas);

window.onresize = resize;
resize();

setInterval(addRocket, 2000);
render();

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:
1. 本站所有文章教程及资源素材均来源于网络与用户分享或为本站原创,仅限用于学习和研究。
2. 如果内容损害你的权益请联系客服QQ:1642748312给予处理。
码云笔记 » JavaScript 用画布标签制作的烟花

发表评论

IT互联网行业相关广告投放 更专业 更精准

立即查看 联系我们