105 lines
2.8 KiB
JavaScript
105 lines
2.8 KiB
JavaScript
import { System } from '../core/System.js';
|
|
import { Palette } from '../core/Palette.js';
|
|
import { SystemName, ComponentType, VFXType } from '../core/Constants.js';
|
|
|
|
export class VFXSystem extends System {
|
|
constructor() {
|
|
super(SystemName.VFX);
|
|
this.requiredComponents = [];
|
|
this.priority = 40;
|
|
this.particles = [];
|
|
}
|
|
|
|
process(deltaTime, _entities) {
|
|
const playerController = this.engine.systems.find(s => s.name === SystemName.PLAYER_CONTROLLER);
|
|
const player = playerController ? playerController.getPlayerEntity() : null;
|
|
const playerPos = player ? player.getComponent(ComponentType.POSITION) : null;
|
|
|
|
for (let i = this.particles.length - 1; i >= 0; i--) {
|
|
const p = this.particles[i];
|
|
|
|
// Update lifetime
|
|
p.lifetime -= deltaTime;
|
|
if (p.lifetime <= 0) {
|
|
this.particles.splice(i, 1);
|
|
continue;
|
|
}
|
|
|
|
// Behavior logic
|
|
if (p.type === VFXType.ABSORPTION && playerPos) {
|
|
// Attract to player
|
|
const dx = playerPos.x - p.x;
|
|
const dy = playerPos.y - p.y;
|
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
if (dist > 5) {
|
|
p.vx += (dx / dist) * 800 * deltaTime;
|
|
p.vy += (dy / dist) * 800 * deltaTime;
|
|
// Add some drag to make it smooth
|
|
p.vx *= 0.95;
|
|
p.vy *= 0.95;
|
|
} else {
|
|
// Arrived
|
|
this.particles.splice(i, 1);
|
|
continue;
|
|
}
|
|
} else {
|
|
// Basic drag for impact particles
|
|
p.vx *= 0.9;
|
|
p.vy *= 0.9;
|
|
}
|
|
|
|
// Update position
|
|
p.x += p.vx * deltaTime;
|
|
p.y += p.vy * deltaTime;
|
|
}
|
|
}
|
|
|
|
createImpact(x, y, color = Palette.WHITE, angle = null) {
|
|
const count = 8;
|
|
for (let i = 0; i < count; i++) {
|
|
let vx, vy;
|
|
if (angle !== null) {
|
|
// Splash in the direction of hit + some spread
|
|
const spread = (Math.random() - 0.5) * 2;
|
|
const speed = 50 + Math.random() * 150;
|
|
vx = Math.cos(angle + spread) * speed;
|
|
vy = Math.sin(angle + spread) * speed;
|
|
} else {
|
|
vx = (Math.random() - 0.5) * 150;
|
|
vy = (Math.random() - 0.5) * 150;
|
|
}
|
|
|
|
this.particles.push({
|
|
x,
|
|
y,
|
|
vx,
|
|
vy,
|
|
lifetime: 0.2 + Math.random() * 0.3,
|
|
size: 1 + Math.random() * 2,
|
|
color: color,
|
|
type: VFXType.IMPACT
|
|
});
|
|
}
|
|
}
|
|
|
|
createAbsorption(x, y, color = Palette.CYAN) {
|
|
for (let i = 0; i < 12; i++) {
|
|
// Start with a small explosion then attract
|
|
this.particles.push({
|
|
x,
|
|
y,
|
|
vx: (Math.random() - 0.5) * 100,
|
|
vy: (Math.random() - 0.5) * 100,
|
|
lifetime: 1.5,
|
|
size: 2,
|
|
color: color,
|
|
type: VFXType.ABSORPTION
|
|
});
|
|
}
|
|
}
|
|
|
|
getParticles() {
|
|
return this.particles;
|
|
}
|
|
}
|