331 lines
10 KiB
JavaScript
331 lines
10 KiB
JavaScript
export class Player extends Phaser.GameObjects.Sprite {
|
|
constructor(scene, x, y, texture, frame) {
|
|
super(scene, x, y, 'player-tiles');
|
|
|
|
scene.add.existing(this);
|
|
scene.physics.world.enable(this);
|
|
this.body.setSize(50,100);
|
|
|
|
// Initialize variables
|
|
this.pauseMove = false;
|
|
this.isTakingDamage = false;
|
|
this.showHealth = false;
|
|
this.healthText;
|
|
this.healthImages;
|
|
this.numHearts = 3;
|
|
this.maxHearts = 3;
|
|
this.normalVelocityX = 260;
|
|
this.inventory = [];
|
|
this.facing = 'south';
|
|
this.isAttacking = false;
|
|
this.isFiring = false;
|
|
this.axe;
|
|
this.bullet;
|
|
this.texturePlus = 24;
|
|
|
|
// Create animations
|
|
this.anims.create({
|
|
key: 'north',
|
|
frames: this.anims.generateFrameNumbers('player-tiles', { start: 0+this.texturePlus, end: 1+this.texturePlus }),
|
|
frameRate: 5,
|
|
repeat: -1
|
|
});
|
|
|
|
this.anims.create({
|
|
key: 'side',
|
|
frames: this.anims.generateFrameNumbers('player-tiles', { start: 8+this.texturePlus, end: 9+this.texturePlus }),
|
|
frameRate: 5,
|
|
repeat: -1
|
|
});
|
|
|
|
this.anims.create({
|
|
key: 'south',
|
|
frames: this.anims.generateFrameNumbers('player-tiles', { start: 16+this.texturePlus, end: 17+this.texturePlus }),
|
|
frameRate: 5,
|
|
repeat: -1
|
|
});
|
|
|
|
this.anims.create({
|
|
key: 'death',
|
|
frames: [
|
|
{ key: 'player-tiles', frame: 3+this.texturePlus }
|
|
],
|
|
frameRate: 5,
|
|
duration: 1500,
|
|
repeat: -1
|
|
});
|
|
|
|
this.anims.create({
|
|
key: 'death2',
|
|
frames: [
|
|
{ key: 'player-tiles', frame: 4+this.texturePlus }
|
|
],
|
|
frameRate: 5,
|
|
duration: 1500,
|
|
repeat: -1
|
|
});
|
|
|
|
this.scene.input.keyboard.on('keydown-A', this.attack, this);
|
|
}
|
|
|
|
update() {
|
|
// Movement Debug:
|
|
// console.log(this.body.x + " " + this.body.y);
|
|
|
|
if (this.pauseMove === true) {
|
|
this.body.setVelocity(0);
|
|
} else {
|
|
// Movement: Left/Right:
|
|
if (this.scene.cursors.left.isDown) {
|
|
this.body.setVelocityX(-200);
|
|
this.setFlipX(false);
|
|
this.anims.play('side', true);
|
|
this.facing = 'west';
|
|
} else if (this.scene.cursors.right.isDown) {
|
|
this.body.setVelocityX(200);
|
|
this.setFlipX(true);
|
|
this.anims.play('side', true);
|
|
this.facing = 'east';
|
|
} else {
|
|
this.body.setVelocityX(0);
|
|
}
|
|
|
|
// Movement: Up/Down:
|
|
if (this.scene.cursors.up.isDown) {
|
|
this.body.setVelocityY(-200);
|
|
this.anims.play('south', true);
|
|
this.facing = 'south';
|
|
} else if (this.scene.cursors.down.isDown) {
|
|
this.body.setVelocityY(200);
|
|
this.anims.play('north', true);
|
|
this.facing = 'north';
|
|
} else {
|
|
this.body.setVelocityY(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
attack() {
|
|
if (this.isAttacking === true) {
|
|
return;
|
|
}
|
|
|
|
this.isAttacking = true;
|
|
this.pauseMove = true;
|
|
|
|
// Determine the direction the player is facing
|
|
let offsetX = 0;
|
|
let offsetY = 0;
|
|
let flip = false;
|
|
let rotate = 0;
|
|
let direction = 360;
|
|
let velocX = 0;
|
|
let velocY = 0;
|
|
|
|
|
|
if (this.facing === 'west') {
|
|
offsetX = -100;
|
|
flip = true;
|
|
direction = -360;
|
|
velocX = -1500;
|
|
} else if (this.facing === 'east') {
|
|
offsetX = +100;
|
|
velocX = 1500;
|
|
} else if (this.facing === 'north') {
|
|
offsetY = +100;
|
|
rotate = 90;
|
|
velocY = 1500;
|
|
} else if (this.facing === 'south') {
|
|
offsetY = -100;
|
|
rotate = 270;
|
|
velocY = -1500;
|
|
}
|
|
|
|
// Create a rectangle for the attack area in front of the player
|
|
const attackArea = new Phaser.Geom.Rectangle(
|
|
this.x + offsetX,
|
|
this.y + offsetY,
|
|
100, // width
|
|
100 // height
|
|
);
|
|
|
|
// Add Axe
|
|
this.axe = this.scene.physics.add.sprite(attackArea.x, attackArea.y, 'player-tiles', 2);
|
|
this.scene.axes.add(this.axe);
|
|
this.axe.setFlipX(flip);
|
|
this.axe.setAngle(rotate);
|
|
this.axe.setVelocity(velocX / 4, velocY / 4);
|
|
this.scene.tweens.add({
|
|
targets: this.axe,
|
|
scale: 1, // 110% of original size
|
|
angle: direction+rotate, // Spin clockwise once (360 degrees)
|
|
duration: 1000,
|
|
ease: 'Power2'
|
|
});
|
|
this.scene.sound.play('axeThrow');
|
|
|
|
// Add Bullet if hearts are full
|
|
if (this.numHearts >= 3 && this.isFiring === false) {
|
|
this.bullet = this.scene.physics.add.sprite(attackArea.x, attackArea.y, 'player-tiles', 10);
|
|
this.scene.bullets.add(this.bullet)
|
|
this.bullet.setFlip(flip);
|
|
this.bullet.setAngle(rotate);
|
|
this.bullet.setVelocity(velocX, velocY);
|
|
this.scene.sound.play('gunShot');
|
|
this.isFiring = true;
|
|
this.scene.physics.world.enable(this.bullet);
|
|
|
|
}
|
|
|
|
// Reset attack ability after a delay
|
|
this.scene.time.delayedCall(500, () => {
|
|
this.pauseMove = false;
|
|
this.axe.destroy();
|
|
this.isAttacking = false;
|
|
if (this.bullet) {
|
|
this.bullet.destroy();
|
|
}
|
|
});
|
|
if (this.isFiring === true) {
|
|
this.scene.time.delayedCall(2000, () => {
|
|
this.isFiring = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
healthBars(showHealth, Hearts, Lives) {
|
|
this.showHealth = showHealth;
|
|
if (this.showHealth === true) {
|
|
this.healthText = this.scene.add.text(16, 16, 'Health: ', { fontSize: '36px', fill: '#FFF' })
|
|
.setShadow(3,3, '#333', 5)
|
|
.setScrollFactor(0);
|
|
this.updateHealth();
|
|
this.livesText = this.scene.add.text(16, 64, 'Lives:', { fontSize: '36px', fill: '#FFF' })
|
|
.setShadow(3,3, '#333', 5)
|
|
.setScrollFactor(0);
|
|
}
|
|
}
|
|
|
|
takeDamage(fromObject) {
|
|
if (this.isTakingDamage) {
|
|
return;
|
|
}
|
|
this.isTakingDamage = true;
|
|
this.scene.sound.play('player-damage');
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
tint: 0xaaaaff,
|
|
duration: 1000,
|
|
repeat: 0,
|
|
yoyo: true,
|
|
ease: 'Power1'
|
|
});
|
|
|
|
this.numHearts -= 1;
|
|
if (this.numHearts > 0) {
|
|
this.updateHealth();
|
|
} else {
|
|
this.updateHealth();
|
|
this.pauseMove = true;
|
|
this.anims.play('death');
|
|
this.body.enable = false;
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
angle: 720, // Spin clockwise once (360 degrees)
|
|
duration: 1500,
|
|
ease: 'Power2',
|
|
onComplete: () => {
|
|
this.anims.play('death2');
|
|
// Add animation to lower player by 20px
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
y: '+=20',
|
|
duration: 1000,
|
|
ease: 'Power1'
|
|
});
|
|
// Fade out the camera and restart the scene
|
|
this.scene.cameras.main.fade(1500, 0, 0, 0, true);
|
|
this.scene.time.delayedCall(1500, () => {
|
|
this.scene.bgMusic.stop();
|
|
this.scene.scene.restart();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Knockback
|
|
|
|
// Reset taking damage state after a delay
|
|
this.scene.time.delayedCall(500, () => {
|
|
this.isTakingDamage = false;
|
|
this.pauseMove = false;
|
|
});
|
|
}
|
|
|
|
addHealth(amount) {
|
|
if (this.numHearts < 3) {
|
|
this.numHearts += 1;
|
|
this.updateHealth();
|
|
this.scene.sound.play('health-pickup');
|
|
}
|
|
}
|
|
|
|
updateHealth() {
|
|
if (!this.showHealth) {
|
|
return;
|
|
}
|
|
if (this.healthImages) {
|
|
this.healthImages.destroy(true);
|
|
}
|
|
if (this.lifeImages) {
|
|
this.lifeImages.destroy(true);
|
|
}
|
|
this.healthImages = this.scene.add.group();
|
|
this.lifeImages = this.scene.add.group();
|
|
let startX = 170;
|
|
let startLivesX = 165
|
|
|
|
// Add full hearts
|
|
for (let i = 0; i < this.numHearts; i++) {
|
|
this.healthImages.add(this.scene.add.image(startX, 15, 'heart-full').setOrigin(0, 0).setScale(.5).setScrollFactor(0));
|
|
startX += 48;
|
|
}
|
|
|
|
// Add empty hearts for the remaining slots
|
|
for (let i = this.numHearts; i < 3; i++) {
|
|
this.healthImages.add(this.scene.add.image(startX, 15, 'heart-empty').setOrigin(0, 0).setScale(.5).setScrollFactor(0));
|
|
startX += 48;
|
|
}
|
|
|
|
// Add Lives
|
|
for (let i = 0; i < this.numLives; i++) {
|
|
this.lifeImages.add(this.scene.add.image(startLivesX, 64, 'life').setOrigin(0, 0).setScale(.5).setScrollFactor(0));
|
|
startLivesX += 48;
|
|
}
|
|
}
|
|
|
|
addItemToInventory(itemKey) {
|
|
if (!this.inventory[itemKey]) {
|
|
this.inventory[itemKey] = 1; // Create the item with a quantity of 1
|
|
} else {
|
|
this.inventory[itemKey]++; // Increment the quantity if it already exists
|
|
}
|
|
}
|
|
|
|
removeItemFromInventory(itemKey) {
|
|
if (this.inventory[itemKey]) {
|
|
this.inventory[itemKey]--;
|
|
if (this.inventory[itemKey] <= 0) {
|
|
delete this.inventory[itemKey]; // Remove the item if its quantity is zero or less
|
|
}
|
|
}
|
|
}
|
|
|
|
hasItem(itemKey) {
|
|
return this.inventory[itemKey] && this.inventory[itemKey] > 0;
|
|
}
|
|
|
|
getInventory() {
|
|
return this.inventory; // Return a copy of the inventory to prevent direct modification
|
|
}
|
|
} |