You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.3 KiB
139 lines
4.3 KiB
|
6 years ago
|
import Vector from "./Vector"
|
||
|
|
import Time from "./Time"
|
||
|
|
import Particle from "./Particle"
|
||
|
|
import Trail from "./Trail"
|
||
|
|
import Rocket from "./Rocket"
|
||
|
|
|
||
|
|
Particle.GRAVITATION = new Vector(0, 9.81)
|
||
|
|
|
||
|
|
const getTrustParticleFactory = function () {
|
||
|
|
function getColor() {
|
||
|
|
const hue = Math.floor(Math.random() * 15 + 30)
|
||
|
|
return `hsl(${hue}, 100%, 75%`
|
||
|
|
}
|
||
|
|
|
||
|
|
return function () {
|
||
|
|
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 Vector(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 Vector(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()))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export default class Firework {
|
||
|
|
constructor(canvas) {
|
||
|
|
this.canvas = canvas
|
||
|
|
this.ctx = canvas.getContext('2d')
|
||
|
|
this.time = new Time()
|
||
|
|
this.rockets = []
|
||
|
|
this.rAF = null
|
||
|
|
this.timer = null
|
||
|
|
this.stopSign = false
|
||
|
|
this.resize = this.resize.bind(this)
|
||
|
|
this.loop = this.loop.bind(this)
|
||
|
|
this.addRocket = this.addRocket.bind(this)
|
||
|
|
this.start()
|
||
|
|
}
|
||
|
|
|
||
|
|
start() {
|
||
|
|
window.addEventListener('resize', this.resize)
|
||
|
|
document.addEventListener('click', this.addRocket)
|
||
|
|
this.timer = window.setInterval(this.addRocket, 1000)
|
||
|
|
this.resize()
|
||
|
|
this.loop()
|
||
|
|
}
|
||
|
|
|
||
|
|
stop() {
|
||
|
|
window.removeEventListener('resize', this.resize)
|
||
|
|
window.removeEventListener('click', this.addRocket)
|
||
|
|
this.stopSign = true
|
||
|
|
this.rockets = []
|
||
|
|
this.time = undefined
|
||
|
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||
|
|
}
|
||
|
|
|
||
|
|
loop() {
|
||
|
|
if (this.stopSign) {
|
||
|
|
this.rAF && window.cancelAnimationFrame(this.rAF)
|
||
|
|
this.timer && window.clearInterval(this.timer)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
this.draw()
|
||
|
|
this.rAF = window.requestAnimationFrame(this.loop)
|
||
|
|
}
|
||
|
|
|
||
|
|
draw() {
|
||
|
|
this.time.update()
|
||
|
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||
|
|
|
||
|
|
for (let i = 0; i < this.rockets.length; i++) {
|
||
|
|
this.rockets[i].update(this.time)
|
||
|
|
this.rockets[i].render(this.canvas, this.ctx)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
addRocket() {
|
||
|
|
const trustParticleFactory = getTrustParticleFactory()
|
||
|
|
const explosionFactory = getExplosionFactory(Math.random() * 360)
|
||
|
|
|
||
|
|
const position = new Vector(Math.random() * this.canvas.width, this.canvas.height)
|
||
|
|
const thrust = window.innerHeight * .75
|
||
|
|
const angle = Math.PI / -2 + (Math.random() - .5) * Math.PI / 8
|
||
|
|
const velocity = new Vector(Math.cos(angle) * thrust, Math.sin(angle) * thrust)
|
||
|
|
const lifetime = 3
|
||
|
|
|
||
|
|
this.rockets.push(new Rocket(trustParticleFactory, explosionFactory, position, velocity, lifetime))
|
||
|
|
|
||
|
|
this.rockets = this.rockets.filter(rocket => rocket.isAlive)
|
||
|
|
}
|
||
|
|
|
||
|
|
resize() {
|
||
|
|
this.canvas.width = window.innerWidth
|
||
|
|
this.canvas.height = window.innerHeight
|
||
|
|
}
|
||
|
|
}
|