95 lines
2.6 KiB
JavaScript
95 lines
2.6 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;
|
|
this._deathSound = 'sfx-death-shooter';
|
|
}
|
|
|
|
_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() {
|
|
this.scene.sound.play('sfx-shooter-shoot', { volume: 0.35 });
|
|
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();
|
|
}
|
|
}
|