546 lines
18 KiB
JavaScript
546 lines
18 KiB
JavaScript
export class ProEdgeEnemy extends Phaser.GameObjects.Sprite {
|
|
constructor(scene, x, y, texture, frame) {
|
|
super(scene, x, y, texture, frame);
|
|
|
|
// Add the enemy to the scene
|
|
scene.add.existing(this);
|
|
|
|
// Enable physics for the enemy (if using Arcade Physics)
|
|
scene.physics.world.enable(this);
|
|
|
|
this.speed = 100;
|
|
this.isFollowing = false;
|
|
this.onPatrol = false;
|
|
this.leftBoundary = 0;
|
|
this.rightBoundary = 0;
|
|
this.topBoundary = 0;
|
|
this.bottomBoundary = 0;
|
|
|
|
this.shoots = false;
|
|
this.stars = false;
|
|
this.sword = false;
|
|
this.lightningCast = false;
|
|
this.caster = false;
|
|
this.shootTimer = 0;
|
|
this.scytheSpeed = 550;
|
|
this.starSpeed = 700;
|
|
this.fireballSpeed = 300;
|
|
this.exploding = false;
|
|
this.reloadVariance = 4000;
|
|
this.reloadCalc = 1000;
|
|
this.reload = 0;
|
|
this.bulletsGroup = scene.add.group();
|
|
this.dropHeartOneIn = 3;
|
|
this.garbage = false;
|
|
this.onPause = false;
|
|
this.health = 1;
|
|
this.takingDamage = false;
|
|
this.boss = false;
|
|
this.follows = false;
|
|
|
|
// Create animations
|
|
this.anims.create({
|
|
key: 'walk99',
|
|
frames: this.anims.generateFrameNumbers(texture, { start: frame, end: frame+1 }),
|
|
frameRate: 5,
|
|
repeat: -1
|
|
});
|
|
}
|
|
|
|
setPatrolX(leftBoundary, rightBoundary) {
|
|
this.onPatrol = true;
|
|
this.leftBoundary = leftBoundary;
|
|
this.rightBoundary = rightBoundary;
|
|
}
|
|
|
|
setPatrolY(topBoundary, bottomBoundary) {
|
|
this.onPatrol = true;
|
|
this.topBoundary = topBoundary;
|
|
this.bottomBoundary = bottomBoundary;
|
|
}
|
|
|
|
setSpeed(spd) {
|
|
this.speed = spd;
|
|
}
|
|
|
|
// Example: Basic patrolling movement
|
|
patrol() {
|
|
if (this.onPause === true) {
|
|
return;
|
|
}
|
|
// Horizontal boundaries
|
|
if (this.leftBoundary !== 0) {
|
|
if (this.body.blocked.left || this.body.x <= this.leftBoundary) {
|
|
this.flipX = true;
|
|
this.body.setVelocityX(this.speed);
|
|
} else if (this.body.blocked.right || this.body.x >= this.rightBoundary) {
|
|
this.flipX = false;
|
|
this.body.setVelocityX(-this.speed);
|
|
}
|
|
}
|
|
|
|
// Vertical boundaries
|
|
if (this.topBoundary !== 0) {
|
|
if (this.body.touching.up || this.body.y <= this.topBoundary) {
|
|
this.body.setVelocityY(this.speed);
|
|
} else if (this.body.touching.down || this.body.y >= this.bottomBoundary) {
|
|
this.body.setVelocityY(-this.speed);
|
|
}
|
|
}
|
|
|
|
// Prevent falling off the platform
|
|
if (this.body.velocity.x === 0 && this.leftBoundary!== 0) {
|
|
this.body.setVelocityX(this.speed);
|
|
this.flipX = true;
|
|
}
|
|
if (this.body.velocity.y === 0 && this.bottomBoundary!== 0) {
|
|
this.body.setVelocityY(this.speed);
|
|
}
|
|
}
|
|
|
|
// Example: Following the player
|
|
follow() {
|
|
const camera = this.scene.cameras.main;
|
|
|
|
// Only follow if enemy is visible on screen
|
|
if (camera.worldView.contains(this.x, this.y)) {
|
|
this.isFollowing = true;
|
|
this.scene.physics.moveToObject(this, player, this.speed);
|
|
} else {
|
|
this.isFollowing = false;
|
|
this.body.setVelocity(0);
|
|
}
|
|
}
|
|
|
|
// Example: Enemy taking damage
|
|
takeDamage() {
|
|
if (this.takingDamage === true) {
|
|
return;
|
|
}
|
|
|
|
this.takingDamage = true;
|
|
|
|
// Set takingDamage back to false after 2000ms
|
|
this.scene.time.delayedCall(500, () => {
|
|
this.takingDamage = false;
|
|
});
|
|
|
|
if (this.health === 1) {
|
|
if (this.boss === true) {
|
|
//BOSS DEFEAT
|
|
this.scene.game.globalState.addScore(100);
|
|
this.scene.interface.showScore();
|
|
this.shoots = false;
|
|
this.stars = false;
|
|
this.sword = false;
|
|
this.onPatrol = false;
|
|
this.lightningCast = false;
|
|
this.anims.stop('walk99');
|
|
this.onPause = true;
|
|
this.setTexture('boss-tiles', 8);
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
scale: 1.5,
|
|
ease: 'Power1',
|
|
yoyo: true,
|
|
repeat: 2,
|
|
duration: 200,
|
|
onComplete: () => {
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
ease: 'Power1',
|
|
scale: 1.1,
|
|
duration: 200,
|
|
onComplete: () => {
|
|
this.scene.bossDefeated = true;
|
|
this.setTexture('boss-tiles', 9);
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
ease: 'Power1',
|
|
scale: 0,
|
|
duration: 2000,
|
|
delay: 2000,
|
|
onComplete: () => {
|
|
this.destroy();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
this.scene.game.globalState.addScore(25);
|
|
this.scene.interface.showScore();
|
|
//REGULAR ENEMY DEFEAT
|
|
let dropHeart = Math.floor(Math.random() * this.dropHeartOneIn);
|
|
if (dropHeart === 1) {
|
|
let heart = this.scene.physics.add.image(this.x, this.y, 'heart-full').setScale(.5);
|
|
this.scene.hearts.add(heart);
|
|
this.scene.tweens.add({
|
|
targets: heart,
|
|
scale: 0.8,
|
|
duration: 1000,
|
|
ease: 'Power1',
|
|
yoyo: true,
|
|
repeat: -1
|
|
});
|
|
}
|
|
// Create a tween that scales the enemy's body on Y-axis to 10
|
|
let variance = Math.floor(Math.random() * 2);
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
scaleY: .2,
|
|
duration: 200, // Duration of the animation in milliseconds
|
|
ease: 'Power1',
|
|
onComplete: () => {
|
|
// Destroy the enemy after the animation completes
|
|
this.destroy();
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
this.body.setVelocity(0, 0);
|
|
this.health --;
|
|
if (this.health === 3) {
|
|
this.speed += 100;
|
|
this.sword = true;
|
|
}
|
|
if (this.health === 2) {
|
|
this.stars = true;
|
|
this.bottleReload = 1200;
|
|
this.speed += 100;
|
|
}
|
|
if (this.health === 1) {
|
|
this.shoots = true;
|
|
this.bottleReload = 800;
|
|
this.speed += 200;
|
|
this.bottleReloadVariance = 1000;
|
|
}
|
|
if (this.boss === true) {
|
|
this.anims.stop('walk99');
|
|
this.setTexture('boss-tiles', 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
fireStars() {
|
|
this.fireStar();
|
|
this.scene.time.delayedCall(200, () => {
|
|
this.fireStar();
|
|
});
|
|
this.scene.time.delayedCall(400, () => {
|
|
this.fireStar();
|
|
});
|
|
}
|
|
|
|
fireStar() {
|
|
if (this.scene) {
|
|
const player = this.scene.player;
|
|
const star = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 14);
|
|
star.setSize(75, 75);
|
|
this.scene.attacks.add(star);
|
|
const angle = Phaser.Math.Angle.Between(this.x, this.y, player.x, player.y);
|
|
star.setVelocity(Math.cos(angle) * this.starSpeed, Math.sin(angle) * this.starSpeed);
|
|
this.scene.physics.world.enable(star);
|
|
this.scene.sound.play('swoosh');
|
|
this.scene.tweens.add({
|
|
targets: star,
|
|
angle: 1080,
|
|
duration: 1500,
|
|
ease: 'Linear',
|
|
onComplete: () => {
|
|
star.destroy();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
fireSword() {
|
|
const player = this.scene.player;
|
|
const sword = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 13);
|
|
sword.setSize(75, 75);
|
|
this.scene.attacks.add(sword);
|
|
const angle = Phaser.Math.Angle.Between(this.x, this.y, player.x, player.y);
|
|
sword.setVelocity(Math.cos(angle) * this.scytheSpeed, Math.sin(angle) * this.scytheSpeed);
|
|
this.scene.physics.world.enable(sword);
|
|
this.scene.sound.play('swoosh');
|
|
this.scene.tweens.add({
|
|
targets: sword,
|
|
angle: 360,
|
|
duration: 1500,
|
|
ease: 'Linear',
|
|
onComplete: () => {
|
|
sword.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
cast() {
|
|
let vari = Phaser.Math.Between(1, 3)
|
|
if (vari === 1) {
|
|
this.fireBalls();
|
|
} else {
|
|
this.fireFloor();
|
|
}
|
|
}
|
|
|
|
fireFloor() {
|
|
const player = this.scene.player;
|
|
const fire = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 12);
|
|
fire.setSize(150, 150).setScale(0.2);
|
|
this.scene.attacks.add(fire);
|
|
const angle = Phaser.Math.Angle.Between(this.x, this.y, player.x, player.y);
|
|
// Position the fire sprite 150 units away from player along the angle
|
|
fire.x = player.x + Math.cos(angle) * -150;
|
|
fire.y = player.y + Math.sin(angle) * -150;
|
|
this.scene.sound.play('fireSpell');
|
|
this.scene.physics.world.enable(fire);
|
|
this.scene.tweens.add({
|
|
targets: fire,
|
|
angle: -1080,
|
|
duration: 10000,
|
|
scale: 2.5,
|
|
ease: 'Linear',
|
|
onComplete: () => {
|
|
fire.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
lightningFloor() {
|
|
const player = this.scene.player;
|
|
const lightning = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 15);
|
|
const fire = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 16);
|
|
fire.setSize(150, 150).setScale(0.2);
|
|
this.scene.attacks.add(fire);
|
|
const angle = Phaser.Math.Angle.Between(this.x, this.y, player.x, player.y);
|
|
// Position the fire sprite 150 units away from player along the angle
|
|
fire.x = player.x + Math.cos(angle) * -150;
|
|
fire.y = player.y + Math.sin(angle) * -150;
|
|
lightning.x = (player.x + Math.cos(angle) * -150) + 10;
|
|
lightning.y = (player.y + Math.sin(angle) * -150) - 40;
|
|
// Add flashing animation to lightning sprite
|
|
this.scene.tweens.add({
|
|
targets: lightning,
|
|
alpha: 0,
|
|
duration: 100,
|
|
repeat: 3,
|
|
yoyo: true,
|
|
ease: 'Linear',
|
|
onComplete: () => {
|
|
lightning.destroy();
|
|
}
|
|
});
|
|
this.scene.sound.play('lightningVortex');
|
|
this.scene.physics.world.enable(fire);
|
|
this.scene.tweens.add({
|
|
targets: fire,
|
|
angle: -1080,
|
|
duration: 6000,
|
|
scale: 2,
|
|
ease: 'Linear',
|
|
onComplete: () => {
|
|
fire.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
fireBullet() {
|
|
// Fire the bottle
|
|
let variance = Math.floor(Math.random() * 2);
|
|
if (variance === 0) {
|
|
this.fireScythe();
|
|
} else {
|
|
this.fireBalls();
|
|
}
|
|
}
|
|
|
|
fireScythe() {
|
|
const player = this.scene.player;
|
|
const scythe = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 3);
|
|
scythe.setSize(75, 75);
|
|
this.scene.attacks.add(scythe);
|
|
const angle = Phaser.Math.Angle.Between(this.x, this.y, player.x, player.y);
|
|
scythe.setVelocity(Math.cos(angle) * this.scytheSpeed, Math.sin(angle) * this.scytheSpeed);
|
|
this.scene.physics.world.enable(scythe);
|
|
this.scene.sound.play('swoosh');
|
|
this.scene.tweens.add({
|
|
targets: scythe,
|
|
angle: 1080,
|
|
duration: 1500,
|
|
ease: 'Power1',
|
|
onComplete: () => {
|
|
scythe.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
fireBalls() {
|
|
// Get the player from the scene
|
|
const player = this.scene.player;
|
|
|
|
// Fire three garbage projectiles with different angles
|
|
const baseAngle = Phaser.Math.Angle.Between(this.x, this.y, player.x, player.y);
|
|
|
|
// Create and fire garbage at 0.5 radians less than the base angle
|
|
this.createFireballProjectile(baseAngle - 0.8);
|
|
|
|
// Create and fire garbage at 0.5 radians more than the base angle
|
|
this.createFireballProjectile(baseAngle + 0.8);
|
|
this.scene.sound.play('fireball-1');
|
|
this.scene.time.delayedCall(800, () => {
|
|
if (this.scene) {
|
|
this.scene.sound.play('fireball-2');
|
|
}
|
|
});
|
|
}
|
|
|
|
createFireballProjectile(angle) {
|
|
const player = this.scene.player;
|
|
const fireball = this.scene.physics.add.sprite(this.x, this.y, 'proedge-enemies', 2);
|
|
fireball.setSize(50, 50).setScale(.75);
|
|
this.scene.attacks.add(fireball);
|
|
fireball.setVelocity(Math.cos(angle) * this.scytheSpeed, Math.sin(angle) * this.scytheSpeed);
|
|
this.scene.physics.world.enable(fireball);
|
|
this.scene.tweens.add({
|
|
targets: fireball,
|
|
angle: 720,
|
|
duration: 800,
|
|
ease: 'Power1',
|
|
onComplete: () => {
|
|
const baseAngle = Phaser.Math.Angle.Between(fireball.x, fireball.y, player.x, player.y);
|
|
fireball.setVelocity(Math.cos(baseAngle) * this.fireballSpeed, Math.sin(baseAngle) * this.fireballSpeed);
|
|
if (this.scene) {
|
|
this.scene.tweens.add({
|
|
targets: fireball,
|
|
angle: -720,
|
|
duration: 1500,
|
|
ease: 'Power1',
|
|
onComplete: () => {
|
|
fireball.destroy();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
explode() {
|
|
const player = this.scene.player;
|
|
this.prepShot();
|
|
this.scene.time.delayedCall(1000, () => {
|
|
if (this.scene) {
|
|
const explosion = this.scene.physics.add.image(this.x, this.y, 'explosion');
|
|
this.scene.explosions.add(explosion);
|
|
this.scene.physics.world.enable(explosion);
|
|
this.scene.sound.play('explosion');
|
|
this.scene.tweens.add({
|
|
targets: explosion,
|
|
angle: 120,
|
|
duration: 500,
|
|
ease: 'Power1',
|
|
alpha: .3,
|
|
scale: 3,
|
|
onComplete: () => {
|
|
explosion.destroy();
|
|
}
|
|
});
|
|
}
|
|
this.destroy();
|
|
});
|
|
|
|
}
|
|
|
|
prepShot() {
|
|
this.scene.time.delayedCall(500, () => {
|
|
if(!this.body) {
|
|
return;
|
|
}
|
|
this.onPause = true;
|
|
const originalVelocity = this.body.velocity.clone();
|
|
this.body.setVelocity(0, 0);
|
|
|
|
this.scene.time.delayedCall(500, () => {
|
|
if(!this.body) {
|
|
return;
|
|
}
|
|
this.body.setVelocity(originalVelocity.x, originalVelocity.y);
|
|
this.onPause = false;
|
|
});
|
|
});
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
tint: 0xaaaaff,
|
|
duration: 1000,
|
|
repeat: 0,
|
|
yoyo: true,
|
|
ease: 'Power1'
|
|
});
|
|
}
|
|
|
|
//
|
|
update(time, delta) {
|
|
if (this.takingDamage === true) {
|
|
this.body.setVelocity(0, 0);
|
|
return;
|
|
}
|
|
|
|
if (this.follows === true) {
|
|
const camera = this.scene.cameras.main;
|
|
if (camera.worldView.contains(this.x, this.y)) {
|
|
this.isFollowing = true;
|
|
if (Phaser.Math.Distance.Between(this.x, this.y, this.scene.player.x, this.scene.player.y) < 200 && this.exploding === false) {
|
|
this.exploding = true;
|
|
this.explode();
|
|
} else {
|
|
this.scene.physics.moveToObject(this, this.scene.player, this.speed);
|
|
this.anims.play('walk99', true);
|
|
if (this.body.velocity.x < 0) {
|
|
this.flipX = false;
|
|
} else {
|
|
this.flipX = true;
|
|
}
|
|
}
|
|
} else {
|
|
this.isFollowing = false;
|
|
this.body.setVelocity(0);
|
|
}
|
|
}
|
|
|
|
if (this.onPatrol === true) {
|
|
this.patrol();
|
|
this.anims.play('walk99', true);
|
|
}
|
|
|
|
const camera = this.scene.cameras.main;
|
|
|
|
if (this.shoots || this.stars || this.sword || this.caster || this.boss) {
|
|
if (camera.worldView.contains(this.x, this.y)) {
|
|
this.shootTimer += delta;
|
|
if (this.shootTimer >= this.reloadCalc) {
|
|
this.shootTimer = 0;
|
|
let variance = Math.floor(Math.random() * this.reloadVariance);
|
|
this.reloadCalc = this.reload + variance;
|
|
this.prepShot();
|
|
this.scene.time.delayedCall(1000, () => {
|
|
if(!this.body) {
|
|
return;
|
|
}
|
|
if (this.shoots) {
|
|
this.fireBullet();
|
|
} else if (this.stars) {
|
|
this.fireStars();
|
|
} else if (this.sword) {
|
|
this.fireSword();
|
|
} else if (this.caster) {
|
|
this.cast();
|
|
}
|
|
if (this.lightningCast) {
|
|
this.lightningFloor();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |