Files
2026-09-24 17:57:54 +02:00

79 lines
2.5 KiB
JavaScript

/**
* Wiederverwendbare Projektile (Object Pooling).
*
* Bei Dauerfeuer entstehen Hunderte Projektile pro Minute. Statt sie jedes Mal neu
* zu erzeugen und zu zerstören (Garbage-Collector-Ruckler), werden deaktivierte
* Projektile wiederverwendet.
* @module entities/ProjectilePool
*/
export class ProjectilePool {
/**
* @param {Phaser.Scene} scene
* @param {string} textureKey
* @param {number} maxSize Obergrenze gleichzeitig fliegender Projektile.
* @param {number} depth
*/
constructor(scene, textureKey, maxSize, depth) {
this.scene = scene;
this.textureKey = textureKey;
this.depth = depth;
this.group = scene.physics.add.group({
classType: Phaser.Physics.Arcade.Image,
maxSize,
allowGravity: false,
});
}
/**
* Feuert ein Projektil ab.
* @param {number} x
* @param {number} y
* @param {number} angle Bogenmaß.
* @param {number} speed px/s
* @param {number} damage
* @param {number} range Maximale Flugstrecke in px.
* @param {string} [textureKey] Abweichende Textur (z. B. Geschütz).
* @returns {Phaser.Physics.Arcade.Image|null} null, wenn der Pool erschöpft ist.
*/
fire(x, y, angle, speed, damage, range, textureKey) {
const projectile = this.group.get(x, y, textureKey ?? this.textureKey);
if (!projectile) return null;
projectile.enableBody(true, x, y, true, true);
projectile.setTexture(textureKey ?? this.textureKey);
projectile.setDepth(this.depth);
projectile.setRotation(angle);
this.scene.physics.velocityFromRotation(angle, speed, projectile.body.velocity);
projectile.damage = damage;
projectile.spawnX = x;
projectile.spawnY = y;
projectile.maxTravelSq = range * range;
return projectile;
}
/**
* Deaktiviert Projektile, die ihre Reichweite überschritten oder die Welt verlassen haben.
* @param {Phaser.Geom.Rectangle} bounds
*/
update(bounds) {
for (const projectile of this.group.getChildren()) {
if (!projectile.active) continue;
const dx = projectile.x - projectile.spawnX;
const dy = projectile.y - projectile.spawnY;
if (dx * dx + dy * dy > projectile.maxTravelSq || !bounds.contains(projectile.x, projectile.y)) {
this.kill(projectile);
}
}
}
/** @param {Phaser.Physics.Arcade.Image} projectile */
kill(projectile) {
projectile.disableBody(true, true);
}
/** @returns {number} Aktive Projektile. */
get activeCount() {
return this.group.countActive(true);
}
}