overrun/js/entities/enemies/ShooterEnemy.js

93 lines
2.5 KiB
JavaScript

import { BaseEnemy } from './BaseEnemy.js';
const PREFERRED_DIST = 300;
const SHOOT_INTERVAL = 2000; // ms
const PROJECTILE_SPEED = 200;
const PROJECTILE_DAMAGE = 10;
const PROJECTILE_COLOR = 0xff00ff;
export class ShooterEnemy extends BaseEnemy {
constructor(scene, x, y, player) {
super(scene, x, y, player, {
frameOffset: 6,
radius: 16,
hp: 60,
speed: 50,
xp: 30,
contactDamage: 8,
});
this._shootTimer = SHOOT_INTERVAL * Math.random(); // stagger first shot
this.projectiles = scene.add.group();
this._deathPulseColor = 0x9900ff;
}
_die() {
this._gridDeathPulse();
super._die();
}
update(delta) {
super.update(delta);
this._strafe();
this._handleShoot(delta);
this._updateProjectiles();
}
_strafe() {
const dist = Phaser.Math.Distance.Between(this.x, this.y, this.player.x, this.player.y);
const angle = Phaser.Math.Angle.Between(this.x, this.y, this.player.x, this.player.y);
let vx = 0, vy = 0;
if (dist > PREFERRED_DIST + 30) {
// Move closer
vx = Math.cos(angle) * this.speed;
vy = Math.sin(angle) * this.speed;
} else if (dist < PREFERRED_DIST - 30) {
// Move away
vx = -Math.cos(angle) * this.speed;
vy = -Math.sin(angle) * this.speed;
} else {
// Strafe perpendicular
const perp = angle + Math.PI / 2;
vx = Math.cos(perp) * this.speed;
vy = Math.sin(perp) * this.speed;
}
this.sprite.body.setVelocity(vx, vy);
}
_handleShoot(delta) {
this._shootTimer -= delta;
if (this._shootTimer <= 0) {
this._shootTimer = SHOOT_INTERVAL;
this._fireProjectile();
}
}
_fireProjectile() {
const angle = Phaser.Math.Angle.Between(this.x, this.y, this.player.x, this.player.y);
const proj = this.scene.add.circle(this.x, this.y, 6, PROJECTILE_COLOR);
this.scene.physics.add.existing(proj);
proj.body.setVelocity(
Math.cos(angle) * PROJECTILE_SPEED,
Math.sin(angle) * PROJECTILE_SPEED
);
proj.damage = PROJECTILE_DAMAGE;
this.projectiles.add(proj);
// Register with scene for collision
this.scene.events.emit('enemy-projectile-spawned', proj);
}
_updateProjectiles() {
const W = this.scene.scale.width;
const H = this.scene.scale.height;
this.projectiles.getChildren().forEach(p => {
if (p.x < -30 || p.x > W + 30 || p.y < -30 || p.y > H + 30) p.destroy();
});
}
destroy() {
this.projectiles.clear(true, true);
super.destroy();
}
}