79 lines
2.5 KiB
JavaScript
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);
|
|
}
|
|
}
|