Implement enemy movement tracking, health system, and tower attack mechanics
- Added distance traveled tracking to enemies for progression metrics - Implemented enemy health system with damage calculation and health bars - Created tower attack functionality with damage application and enemy destruction - Enhanced wave manager to track enemy movement distances during path traversal - Updated enemy configuration with full health values and drop ranges - Modified tower manager to support dynamic tower properties and level-based configurations This commit introduces core combat mechanics including enemy health tracking, visual health bars, tower damage system, and proper distance calculation for enemy progression through paths.
This commit is contained in:
parent
cbbe6d51ed
commit
dc1eef50dc
|
|
@ -39,27 +39,6 @@ export class Level1 extends Phaser.Scene {
|
||||||
this.physics.add.collider(this.enemies, this.platformsLayer);
|
this.physics.add.collider(this.enemies, this.platformsLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveJoshAlongPath(path) {
|
|
||||||
let currentIndex = 0;
|
|
||||||
|
|
||||||
const moveNextStep = () => {
|
|
||||||
if (currentIndex >= path.length - 1) return; // Reached target
|
|
||||||
|
|
||||||
const nextPoint = path[++currentIndex];
|
|
||||||
|
|
||||||
// Move josh to the next point
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.josh,
|
|
||||||
x: nextPoint.x * 200 + 100,
|
|
||||||
y: nextPoint.y * 200 + 100,
|
|
||||||
duration: 2000,
|
|
||||||
onComplete: moveNextStep
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
moveNextStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
gridToLocation(num, offset = 0) {
|
gridToLocation(num, offset = 0) {
|
||||||
return num * 200 + 100 + offset;
|
return num * 200 + 100 + offset;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ export class Enemies {
|
||||||
'pathPhase': 0,
|
'pathPhase': 0,
|
||||||
'speed': randSpeed,
|
'speed': randSpeed,
|
||||||
'health': ENEMIES_CONFIG[this.type].health,
|
'health': ENEMIES_CONFIG[this.type].health,
|
||||||
'type': this.type
|
'type': this.type,
|
||||||
|
'distanceTraveled': 0
|
||||||
};
|
};
|
||||||
|
|
||||||
this.scene.enemies.add(enemy);
|
this.scene.enemies.add(enemy);
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,23 @@ export const ENEMIES_CONFIG = {
|
||||||
'basic1': {
|
'basic1': {
|
||||||
'spread': 25,
|
'spread': 25,
|
||||||
'health': 100,
|
'health': 100,
|
||||||
|
'fullHealth': 100,
|
||||||
'speedLow': 25,
|
'speedLow': 25,
|
||||||
'speedHigh': 35,
|
'speedHigh': 35,
|
||||||
'spriteStart': 0,
|
'spriteStart': 0,
|
||||||
'spriteSheet': 'basic-enemies'
|
'spriteSheet': 'basic-enemies',
|
||||||
|
'dropLow': 1,
|
||||||
|
'dropHigh': 2
|
||||||
},
|
},
|
||||||
'basic2': {
|
'basic2': {
|
||||||
'spread': 0,
|
'spread': 0,
|
||||||
'health': 300,
|
'health': 300,
|
||||||
|
'fullHealth': 100,
|
||||||
'speedLow': 45,
|
'speedLow': 45,
|
||||||
'speedHigh': 55,
|
'speedHigh': 55,
|
||||||
'spriteStart': 0,
|
'spriteStart': 0,
|
||||||
'spriteSheet': 'basic-enemies'
|
'spriteSheet': 'basic-enemies',
|
||||||
|
'dropLow': 1,
|
||||||
|
'dropHigh': 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +12,10 @@ export class TowerManager {
|
||||||
const posY = this.scene.gridToLocation(y);
|
const posY = this.scene.gridToLocation(y);
|
||||||
|
|
||||||
const tower = this.scene.add.image(posX, posY, 'josh');
|
const tower = this.scene.add.image(posX, posY, 'josh');
|
||||||
|
tower.props = {
|
||||||
|
'type': type,
|
||||||
|
'level': 1
|
||||||
|
}
|
||||||
this.scene.towers.add(tower);
|
this.scene.towers.add(tower);
|
||||||
|
|
||||||
// Draw range circle
|
// Draw range circle
|
||||||
|
|
@ -29,8 +33,9 @@ export class TowerManager {
|
||||||
const towerY = tower.y;
|
const towerY = tower.y;
|
||||||
|
|
||||||
// Get tower config
|
// Get tower config
|
||||||
const type = 'gun'; // Assuming gun towers for now
|
const type = tower.props.type;
|
||||||
const config = TOWERS_CONFIG[type].level1;
|
const level = 'level'+tower.props.level;
|
||||||
|
const config = TOWERS_CONFIG[type][level];
|
||||||
|
|
||||||
if (!config) return;
|
if (!config) return;
|
||||||
|
|
||||||
|
|
@ -44,6 +49,7 @@ export class TowerManager {
|
||||||
// Check for enemies in range
|
// Check for enemies in range
|
||||||
let inRange = false;
|
let inRange = false;
|
||||||
this.scene.enemies.children.iterate((enemy) => {
|
this.scene.enemies.children.iterate((enemy) => {
|
||||||
|
const distanceTraveled = enemy.props.distanceTraveled;
|
||||||
const distance = Phaser.Math.Distance.Between(
|
const distance = Phaser.Math.Distance.Between(
|
||||||
towerX, towerY,
|
towerX, towerY,
|
||||||
enemy.x, enemy.y
|
enemy.x, enemy.y
|
||||||
|
|
@ -51,6 +57,7 @@ export class TowerManager {
|
||||||
|
|
||||||
if (distance <= range) {
|
if (distance <= range) {
|
||||||
inRange = true;
|
inRange = true;
|
||||||
|
this.attackTarget(tower, enemy);
|
||||||
return false; // Stop iterating once we find one enemy
|
return false; // Stop iterating once we find one enemy
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -64,4 +71,84 @@ export class TowerManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attackTarget(tower, enemy) {
|
||||||
|
// Tower Properties
|
||||||
|
const type = tower.props.type;
|
||||||
|
const level = 'level'+tower.props.level;
|
||||||
|
const config = TOWERS_CONFIG[type][level];
|
||||||
|
|
||||||
|
if (!config) return;
|
||||||
|
|
||||||
|
const dmgLow = config.dmgLow;
|
||||||
|
const dmgHigh = config.dmgHigh;
|
||||||
|
|
||||||
|
// Enemy Information
|
||||||
|
const fullHealth = enemy.props.fullHealth;
|
||||||
|
const currentHealth = enemy.props.health;
|
||||||
|
|
||||||
|
// Calculate damage (random between low and high)
|
||||||
|
const damage = Phaser.Math.Between(dmgLow, dmgHigh);
|
||||||
|
|
||||||
|
// Apply damage to enemy
|
||||||
|
enemy.props.health -= damage;
|
||||||
|
|
||||||
|
// Create or update health bar
|
||||||
|
if (!enemy.healthBar) {
|
||||||
|
this.createHealthBar(enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update health bar display
|
||||||
|
this.updateHealthBar(enemy);
|
||||||
|
|
||||||
|
// Check if enemy should be destroyed
|
||||||
|
if (enemy.props.health <= 0) {
|
||||||
|
this.destroyEnemy(enemy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createHealthBar(enemy) {
|
||||||
|
const barWidth = 30;
|
||||||
|
const barHeight = 5;
|
||||||
|
const barX = enemy.x - barWidth/2;
|
||||||
|
const barY = enemy.y - enemy.displayHeight/2 - 10;
|
||||||
|
|
||||||
|
// Create health bar container
|
||||||
|
enemy.healthBar = this.scene.add.container(enemy.x, enemy.y - enemy.displayHeight/2 - 10);
|
||||||
|
|
||||||
|
// Background bar (gray)
|
||||||
|
const background = this.scene.add.rectangle(0, 0, barWidth, barHeight, 0x808080);
|
||||||
|
|
||||||
|
// Health fill (green)
|
||||||
|
const healthFill = this.scene.add.rectangle(0, 0, barWidth, barHeight, 0x00ff00);
|
||||||
|
|
||||||
|
// Position the fill relative to background
|
||||||
|
healthFill.x = -barWidth/2 + (barWidth * (enemy.props.health / enemy.props.fullHealth)) / 2;
|
||||||
|
|
||||||
|
enemy.healthBar.add([background, healthFill]);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHealthBar(enemy) {
|
||||||
|
if (!enemy.healthBar) return;
|
||||||
|
|
||||||
|
const barWidth = 30;
|
||||||
|
const healthPercentage = enemy.props.health / enemy.props.fullHealth;
|
||||||
|
|
||||||
|
// Update the fill width based on current health
|
||||||
|
enemy.healthBar.list[1].width = barWidth * healthPercentage;
|
||||||
|
|
||||||
|
// Position the container correctly
|
||||||
|
enemy.healthBar.x = enemy.x;
|
||||||
|
enemy.healthBar.y = enemy.y - enemy.displayHeight/2 - 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyEnemy(enemy) {
|
||||||
|
// Remove health bar if exists
|
||||||
|
if (enemy.healthBar) {
|
||||||
|
enemy.healthBar.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the enemy sprite
|
||||||
|
enemy.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +42,11 @@ export class WaveManager {
|
||||||
const offsetX = enemy.props.offsetX;
|
const offsetX = enemy.props.offsetX;
|
||||||
const offsetY = enemy.props.offsetY;
|
const offsetY = enemy.props.offsetY;
|
||||||
|
|
||||||
|
// Initialize distance tracking if not exists
|
||||||
|
if (enemy.props.distanceTraveled === undefined) {
|
||||||
|
enemy.props.distanceTraveled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Only move if we have a valid path and pathPhase
|
// Only move if we have a valid path and pathPhase
|
||||||
if (path && pathPhase !== undefined) {
|
if (path && pathPhase !== undefined) {
|
||||||
// Calculate movement for this frame
|
// Calculate movement for this frame
|
||||||
|
|
@ -64,6 +69,11 @@ export class WaveManager {
|
||||||
|
|
||||||
const velocX = normalizedDx * segmentSpeed;
|
const velocX = normalizedDx * segmentSpeed;
|
||||||
const velocY = normalizedDy * segmentSpeed;
|
const velocY = normalizedDy * segmentSpeed;
|
||||||
|
|
||||||
|
// Calculate actual movement this frame
|
||||||
|
const movementDistance = Math.sqrt(velocX * velocX + velocY * velocY) * (delta / 1000);
|
||||||
|
enemy.props.distanceTraveled += movementDistance;
|
||||||
|
|
||||||
// Move towards next point
|
// Move towards next point
|
||||||
enemy.body.setVelocity(velocX, velocY);
|
enemy.body.setVelocity(velocX, velocY);
|
||||||
|
|
||||||
|
|
@ -130,8 +140,6 @@ export class WaveManager {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spawnSchedule() {
|
spawnSchedule() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue