threejs-test/src/systems/ParticleSystem.js
Juan Sebastian Montoya 4220e216e1
All checks were successful
Build and Publish Docker Image / Build and Validate (pull_request) Successful in 9s
feat: Introduce CoinType, ObstacleType, PowerUp components and systems
- Added CoinType component to define different coin types and their score values.
- Implemented ObstacleType component to manage various obstacle behaviors.
- Created PowerUp component to handle power-up types and durations.
- Integrated ParticleSystem for visual effects upon collecting coins and power-ups.
- Updated EntityFactory to create coins, obstacles, and power-ups with respective types.
- Enhanced Game class to manage power-up collection and effects, including score multipliers and health restoration.

This update enriches gameplay by adding collectible items with distinct behaviors and effects, enhancing player interaction and strategy.
2025-11-26 17:01:30 -05:00

106 lines
3.1 KiB
JavaScript

import { System } from '../ecs/System.js';
import { Transform } from '../components/Transform.js';
import { ParticleEmitter } from '../components/ParticleEmitter.js';
import { GameConfig } from '../game/GameConfig.js';
/**
* ParticleSystem - manages particle effects for visual feedback
*/
export class ParticleSystem extends System {
constructor(scene) {
super();
/** @type {import('three').Scene} */
this.scene = scene;
/** @type {Array<{mesh: import('three').Mesh, velocity: import('three').Vector3, lifetime: number, maxLifetime: number}>} */
this.particles = [];
}
/**
* Create particles at a position
* @param {import('three').Vector3} position - Position to emit from
* @param {number} count - Number of particles
* @param {number} color - Color (hex)
* @param {number} [speed=5] - Particle speed
*/
emit(position, count, color, speed = 5) {
for (let i = 0; i < count; i++) {
const geometry = new window.THREE.SphereGeometry(0.1, 8, 8);
const material = new window.THREE.MeshBasicMaterial({
color: color,
transparent: true,
opacity: 1.0
});
const mesh = new window.THREE.Mesh(geometry, material);
mesh.position.copy(position);
this.scene.add(mesh);
// Random velocity direction
const velocity = new window.THREE.Vector3(
(Math.random() - 0.5) * speed,
Math.random() * speed * 0.5 + speed * 0.5,
(Math.random() - 0.5) * speed
);
this.particles.push({
mesh: mesh,
velocity: velocity,
lifetime: GameConfig.PARTICLE_LIFETIME,
maxLifetime: GameConfig.PARTICLE_LIFETIME
});
}
}
/**
* Update particles
* @param {number} deltaTime - Time since last frame in seconds
*/
update(deltaTime) {
// Update existing particles
for (let i = this.particles.length - 1; i >= 0; i--) {
const particle = this.particles[i];
// Update position
particle.mesh.position.add(
particle.velocity.clone().multiplyScalar(deltaTime)
);
// Apply gravity
particle.velocity.y -= 9.8 * deltaTime;
// Update lifetime
particle.lifetime -= deltaTime;
// Fade out
const alpha = particle.lifetime / particle.maxLifetime;
particle.mesh.material.opacity = alpha;
// Remove dead particles
if (particle.lifetime <= 0) {
this.scene.remove(particle.mesh);
particle.mesh.geometry.dispose();
particle.mesh.material.dispose();
this.particles.splice(i, 1);
}
}
// Process particle emitters from entities
const entities = this.getEntities(Transform, ParticleEmitter);
for (const entityId of entities) {
const transform = this.getComponent(entityId, Transform);
const emitter = this.getComponent(entityId, ParticleEmitter);
if (emitter && emitter.active) {
this.emit(
transform.position,
emitter.count,
emitter.color,
emitter.speed
);
// Deactivate after emitting once
emitter.active = false;
}
}
}
}