Add AOE tower support, implement flamethrower and cannon towers with animations, enhance tower targeting logic, and update tower configurations including damage types and ranges.

This commit is contained in:
Brian Fertig 2025-09-02 21:16:20 -06:00
parent 7180612aab
commit 37a292c022
8 changed files with 189 additions and 42 deletions

BIN
assets/ammo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/ammo.psd Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

View File

@ -13,6 +13,10 @@ export class Level extends Phaser.Scene {
preload() {
this.load.tilemapTiledJSON('level1', 'assets/level1.json');
this.load.image('terrain', 'assets/terrain.png');
this.load.spritesheet('ammo', 'assets/ammo.png', {
frameWidth: 50,
frameHeight: 50
});
this.load.spritesheet('basic-enemies', 'assets/basic-enemies.png', {
frameWidth: 50,
frameHeight: 50
@ -57,23 +61,23 @@ export class Level extends Phaser.Scene {
}
addControls() {
this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY) => {
const zoomSpeed = 0.1;
if (deltaY < 0) {
// Zoom in
this.cameras.main.zoom += zoomSpeed;
} else if (deltaY > 0) {
// Zoom out
this.cameras.main.zoom -= zoomSpeed;
}
// this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY) => {
// const zoomSpeed = 0.1;
// if (deltaY < 0) {
// // Zoom in
// this.cameras.main.zoom += zoomSpeed;
// } else if (deltaY > 0) {
// // Zoom out
// this.cameras.main.zoom -= zoomSpeed;
// }
// Limit zoom range to prevent extreme zoom levels
this.cameras.main.zoom = Phaser.Math.Clamp(this.cameras.main.zoom, 0.5, 2);
// // Limit zoom range to prevent extreme zoom levels
// this.cameras.main.zoom = Phaser.Math.Clamp(this.cameras.main.zoom, 0.5, 2);
// Zoom toward mouse position
const worldPoint = this.input.activePointer.positionToCamera(this.cameras.main);
this.cameras.main.centerOn(worldPoint.x, worldPoint.y);
});
// // Zoom toward mouse position
// const worldPoint = this.input.activePointer.positionToCamera(this.cameras.main);
// this.cameras.main.centerOn(worldPoint.x, worldPoint.y);
// });
// Add camera panning functionality
this.input.on('pointerdown', (pointer) => {

View File

@ -256,10 +256,6 @@ export class InterfaceManager {
x = 0;
}
}
// this.gridAdd(0, 0, 'Gatlin Gun', 100, 'gun');
// this.gridAdd(0, 1, 'Flamethrower', 150, 'gun');
// this.gridAdd(1, 0, 'Laser', 200, 'gun');
// this.gridAdd(1, 1, 'Cannon', 200, 'cannon');
}
gridAdd(x, y, text, cost, type) {
@ -367,6 +363,11 @@ export class InterfaceManager {
const towerInteractive = this.scene.add.rectangle(0, 0, 200, 200, 0x000000, 0);
this.selectedTower.add(towerInteractive);
const rangeCircle = this.scene.add.circle(0, 0, TOWERS_CONFIG[type].level1.range, 0xc0b15c, 0.2)
.setOrigin(0.5)
.setScrollFactor(0);
this.selectedTower.add(rangeCircle);
const towerBase = this.scene.add.sprite(0, 0, 'towers', 7)
.setOrigin(0.5)
.setScrollFactor(0)
@ -442,14 +443,15 @@ export class InterfaceManager {
const tile = platformsLayer.getTileAt(tileX, tileY);
if (tile) {
this.selectedTower.iterate((child) => {
if (child.type !== 'Rectangle') {
child.setTint(0x89ff5b);
if (child.type !== 'Rectangle' && child.type !== 'Arc') {
child.setTint(0x48ff00);
}
});
this.selectedTower.safe = true;
} else {
this.selectedTower.iterate((child) => {
if (child.type !== 'Rectangle') {
if (child.type !== 'Rectangle' && child.type !== 'Arc') {
console.log(child.type);
child.setTint(0xa32a00);
}
});

View File

@ -3,56 +3,87 @@ export const TOWERS_CONFIG = {
'name': 'Gatlin Gun',
'cost': 100,
'spriteStart': 0,
'type': 'direct',
'aoe': 0,
'dmgType': 'direct',
'level1': {
'dmgLow': 10,
'dmgHigh': 30,
'rate': 2000,
'duration': 500,
'range': 275
'range': 300
},
'level2': {
'dmgLow': 15,
'dmgHigh': 35,
'rate': 1500,
'duration': 750,
'range': 300
'range': 350
},
'level3': {
'dmgLow': 25,
'dmgHigh': 50,
'rate': 1000,
'duration': 1000,
'range': 325
'range': 400
}
},
'cannon': {
'name': 'Cannon',
'cost': 200,
'spriteStart': 10,
'type': 'aoe',
'aoe': 50,
'dmgType': 'aoe',
'level1': {
'dmgLow': 15,
'dmgHigh': 35,
'rate': 2000,
'rate': 2500,
'duration': 200,
'range': 400
'range': 400,
'aoe': 50,
},
'level2': {
'dmgLow': 25,
'dmgHigh': 45,
'rate': 2000,
'rate': 2500,
'duration': 500,
'range': 450
'range': 450,
'aoe': 25,
},
'level3': {
'dmgLow': 35,
'dmgHigh': 65,
'rate': 2000,
'rate': 2500,
'duration': 500,
'range': 500
'range': 500,
'aoe': 25,
}
},
'flame': {
'name': 'Flamethrower',
'cost': 150,
'spriteStart': 20,
'dmgType': 'aoe',
'level1': {
'dmgLow': 1,
'dmgHigh': 5,
'rate': 1000,
'duration': 1000,
'range': 300,
'aoe': 100,
},
'level2': {
'dmgLow': 3,
'dmgHigh': 8,
'rate': 1000,
'duration': 1000,
'range': 350,
'aoe': 100,
},
'level3': {
'dmgLow': 5,
'dmgHigh': 12,
'rate': 1000,
'duration': 1000,
'range': 400,
'aoe': 100,
}
}
}

View File

@ -89,13 +89,19 @@ export class TowerManager {
});
this.following[tower.id] = furthestEnemy.props.id;
const dmgType = TOWERS_CONFIG[tower.props.type].dmgType;
if (dmgType === 'aoe') {
this.aoeAttackTarget(tower, furthestEnemy);
} else {
this.attackTarget(tower, furthestEnemy);
}
this.lastFired[tower.id] = time;
}
}
});
}
attackTarget(tower, enemy) {
// Tower Properties
const type = tower.props.type;
@ -121,11 +127,98 @@ export class TowerManager {
if (enemy.props.health > 0) {
this.createHealthBar(enemy);
if (type === 'gun') {
const gunfire = this.scene.physics.add.sprite(enemy.x, enemy.y, 'ammo', 0);
gunfire.play('gunfire');
gunfire.setVelocity(enemy.body.velocity.x, enemy.body.velocity.y);
this.scene.time.delayedCall(config.duration, () => {
gunfire.destroy();
});
}
} else {
this.destroyEnemy(enemy, tower);
}
}
aoeAttackTarget(tower, enemy) {
// Tower Properties
const type = tower.props.type;
const level = 'level'+tower.props.level;
const config = TOWERS_CONFIG[type][level];
const duration = TOWERS_CONFIG[type][level].duration;
if (!config) return;
const dmgLow = config.dmgLow;
const dmgHigh = config.dmgHigh;
const angle = Phaser.Math.Angle.Between(tower.x, tower.y, enemy.x, enemy.y);
tower.rotation = angle;
if (type === 'cannon') {
const projDistance = 50;
const projX = tower.x + Math.cos(angle) * projDistance;
const projY = tower.y + Math.sin(angle) * projDistance;
const projectile = this.scene.add.sprite(projX, projY, 'ammo', 3);
this.scene.tweens.add({
targets: projectile,
x: enemy.x,
y: enemy.y,
duration: 100,
onComplete: () => {
projectile.setTexture('ammo', 4);
this.scene.time.delayedCall(200, () => {
projectile.destroy();
});
}
});
tower.play(`${type}-${level}-fire`, { 'duration': duration });
}
if (type === 'flame') {
const projDistance = 185;
const projDistance2 = 220;
const projX = tower.x + Math.cos(angle) * projDistance;
const projY = tower.y + Math.sin(angle) * projDistance;
const proj2X = tower.x + Math.cos(angle) * projDistance2;
const proj2Y = tower.y + Math.sin(angle) * projDistance2;
const projectile = this.scene.add.sprite(projX, projY, 'towers', 23).setScale(1.5).setAlpha(.5);
projectile.rotation = angle;
projectile.play(`flamethrower`);
this.scene.tweens.add({
targets: projectile,
x: proj2X,
y: proj2Y,
duration:1000,
onComplete: () => {
projectile.destroy();
}
});
}
// Calculate damage (random between low and high)
const damage = Phaser.Math.Between(dmgLow, dmgHigh);
// Get AOE distance
const aoeDistance = config.aoe;
// Apply damage to all enemies in range
const enemiesInRange = this.scene.enemies.getChildren().filter(e => {
return Phaser.Math.Distance.Between(e.x, e.y, enemy.x, enemy.y) <= aoeDistance;
});
enemiesInRange.forEach(targetEnemy => {
targetEnemy.props.health -= damage;
if (targetEnemy.props.health > 0) {
this.createHealthBar(targetEnemy);
} else {
this.destroyEnemy(targetEnemy, tower);
}
});
}
createHealthBar(enemy) {
const barWidth = 30;
const barHeight = 5;
@ -230,6 +323,15 @@ export class TowerManager {
}
createAnims() {
this.scene.anims.create({
key: 'gunfire',
frames: this.scene.anims.generateFrameNumbers('ammo', {
start:0,
end:2
}),
framerate: 15,
repeat: -1
});
this.scene.anims.create({
key: 'gun-level1-fire',
frames: this.scene.anims.generateFrameNumbers('towers', {
@ -237,7 +339,7 @@ export class TowerManager {
end: 1,
}),
frameRate: 15,
repeat: 5,
repeat: 6,
yoyo: true
});
this.scene.anims.create({
@ -263,12 +365,20 @@ export class TowerManager {
this.scene.anims.create({
key: 'cannon-level1-fire',
frames: this.scene.anims.generateFrameNumbers('towers', {
start: 10,
end: 11
start: 11,
end: 10
}),
frameRate:3,
repeat: 0,
yoyo: true
frameRate: 5,
repeat: 0
});
this.scene.anims.create({
key: 'flamethrower',
frames: this.scene.anims.generateFrameNumbers('towers', {
start: 23,
end:25
}),
framerate: 4,
repeat: -1
})
}