← Public packages
@kentcdodds/pirate-side-scroller
Left-to-right pirate ship shooter on the open sea, built with Three.js for phone or desktop
src/explosions.ts
79 lines · 2.3 KB · TypeScriptimport * as THREE from 'three'
type Burst = {
points: THREE.Points<THREE.BufferGeometry, THREE.PointsMaterial>
velocities: Float32Array
life: number
maxLife: number
}
export class Explosions {
private bursts: Burst[] = []
constructor(private readonly scene: THREE.Scene) {}
spawn(position: THREE.Vector3, color: number, count = 24, speed = 8) {
const positions = new Float32Array(count * 3)
const velocities = new Float32Array(count * 3)
for (let i = 0; i < count; i++) {
positions[i * 3] = position.x
positions[i * 3 + 1] = position.y
positions[i * 3 + 2] = position.z
const angle = Math.random() * Math.PI * 2
const magnitude = THREE.MathUtils.randFloat(0.3, 1) * speed
velocities[i * 3] = Math.cos(angle) * magnitude
velocities[i * 3 + 1] = Math.sin(angle) * magnitude
velocities[i * 3 + 2] = THREE.MathUtils.randFloatSpread(magnitude * 0.5)
}
const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
const points = new THREE.Points(
geometry,
new THREE.PointsMaterial({
color,
size: 0.45,
transparent: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
}),
)
this.scene.add(points)
const maxLife = THREE.MathUtils.randFloat(0.5, 0.8)
this.bursts.push({ points, velocities, life: maxLife, maxLife })
}
update(dt: number) {
const damping = Math.exp(-3 * dt)
for (const burst of this.bursts) {
burst.life -= dt
const attribute = burst.points.geometry.attributes.position!
const positions = attribute.array as Float32Array
for (let i = 0; i < positions.length; i++) {
positions[i]! += burst.velocities[i]! * dt
burst.velocities[i]! *= damping
}
attribute.needsUpdate = true
burst.points.material.opacity = Math.max(0, burst.life / burst.maxLife)
}
this.bursts = this.bursts.filter((burst) => {
if (burst.life > 0) return true
this.dispose(burst)
return false
})
}
clear() {
for (const burst of this.bursts) this.dispose(burst)
this.bursts = []
}
private dispose(burst: Burst) {
this.scene.remove(burst.points)
burst.points.geometry.dispose()
burst.points.material.dispose()
}
}