feat: migrate JavaScript files to TypeScript, enhancing type safety and maintainability across the codebase

This commit is contained in:
Juan Sebastián Montoya 2026-01-06 21:51:00 -05:00
parent 3db2bb9160
commit c582f2004e
107 changed files with 5876 additions and 3588 deletions

View file

@ -0,0 +1,107 @@
import { System } from '../core/System.ts';
import { Events } from '../core/EventBus.ts';
import { Palette } from '../core/Palette.ts';
import { SystemName, ComponentType } from '../core/Constants.ts';
import type { Entity } from '../core/Entity.ts';
import type { Health } from '../components/Health.ts';
import type { Position } from '../components/Position.ts';
import type { Velocity } from '../components/Velocity.ts';
import type { VFXSystem } from './VFXSystem.ts';
/**
* System responsible for managing projectile movement, range limits, lifetimes, and collisions.
*/
export class ProjectileSystem extends System {
constructor() {
super(SystemName.PROJECTILE);
this.requiredComponents = [ComponentType.POSITION, ComponentType.VELOCITY];
this.priority = 18;
}
/**
* Process logic for all projectiles, checking for range, lifetime, and target collisions.
* @param deltaTime - Time elapsed since last frame in seconds
* @param entities - Entities matching system requirements
*/
process(deltaTime: number, entities: Entity[]): void {
entities.forEach((entity) => {
const health = entity.getComponent<Health>(ComponentType.HEALTH);
if (!health || !health.isProjectile) return;
const position = entity.getComponent<Position>(ComponentType.POSITION);
if (!position) return;
if (
entity.startX !== undefined &&
entity.startY !== undefined &&
entity.maxRange !== undefined
) {
const dx = position.x - entity.startX;
const dy = position.y - entity.startY;
const distanceTraveled = Math.sqrt(dx * dx + dy * dy);
if (distanceTraveled >= entity.maxRange) {
this.engine.removeEntity(entity);
return;
}
}
if (entity.lifetime !== undefined) {
entity.lifetime -= deltaTime;
if (entity.lifetime <= 0) {
this.engine.removeEntity(entity);
return;
}
}
const allEntities = this.engine.getEntities();
allEntities.forEach((target) => {
if (target.id === entity.owner) return;
if (target.id === entity.id) return;
if (!target.hasComponent(ComponentType.HEALTH)) return;
const targetHealth = target.getComponent<Health>(ComponentType.HEALTH);
if (targetHealth && targetHealth.isProjectile) return;
const targetPos = target.getComponent<Position>(ComponentType.POSITION);
if (!targetPos) return;
const dx = targetPos.x - position.x;
const dy = targetPos.y - position.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 8) {
const targetHealthComp = target.getComponent<Health>(ComponentType.HEALTH);
const damage = entity.damage || 10;
if (targetHealthComp) {
targetHealthComp.takeDamage(damage);
const vfxSystem = this.engine.systems.find((s) => s.name === SystemName.VFX) as
| VFXSystem
| undefined;
const velocity = entity.getComponent<Velocity>(ComponentType.VELOCITY);
if (vfxSystem) {
const angle = velocity ? Math.atan2(velocity.vy, velocity.vx) : null;
vfxSystem.createImpact(position.x, position.y, Palette.CYAN, angle);
}
if (targetHealthComp.isDead()) {
this.engine.emit(Events.ENTITY_DIED, { entity: target });
}
}
this.engine.removeEntity(entity);
}
});
const canvas = this.engine.canvas;
if (
position.x < 0 ||
position.x > canvas.width ||
position.y < 0 ||
position.y > canvas.height
) {
this.engine.removeEntity(entity);
}
});
}
}