Add Flak Cannon tower with AOE functionality, upgrade animations, and sound effects
This commit introduces a new Flak Cannon tower type with: - Complete tower configuration including cost, damage stats, and range for all 3 levels - Visual upgrades with rotating mid-sections for level 2/3 - Sound effects (flak.mp3) for firing and explosions - AOE shot mechanics that fire multiple projectiles in a spread pattern - Rotation handling to prevent conflicts with tower aiming logic The flak cannon uses a unique firing pattern where it shoots multiple projectiles in different directions within its AOE radius, creating an explosion effect. The upgrade system adds visual elements like rotating mid-sections and changes sprite textures for each level.
This commit is contained in:
parent
f843aee85f
commit
7976c35bfd
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 656 KiB After Width: | Height: | Size: 824 KiB |
Binary file not shown.
|
|
@ -17,11 +17,11 @@ export class Level extends Phaser.Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
init(data) {
|
init(data) {
|
||||||
console.log('Selected level:', data.level);
|
if (data.level && data.playerName) {
|
||||||
console.log('Player name:', data.playerName);
|
|
||||||
this.level = data.level;
|
this.level = data.level;
|
||||||
this.playerName = data.playerName;
|
this.playerName = data.playerName;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
this.load.tilemapTiledJSON(`level${this.level}`, `assets/level${this.level}.json`);
|
this.load.tilemapTiledJSON(`level${this.level}`, `assets/level${this.level}.json`);
|
||||||
|
|
@ -61,6 +61,7 @@ export class Level extends Phaser.Scene {
|
||||||
this.load.audio('portal', 'assets/sounds/portal.mp3');
|
this.load.audio('portal', 'assets/sounds/portal.mp3');
|
||||||
this.load.audio('laser', 'assets/sounds/laser.mp3');
|
this.load.audio('laser', 'assets/sounds/laser.mp3');
|
||||||
this.load.audio('upgrade', 'assets/sounds/upgrade.mp3');
|
this.load.audio('upgrade', 'assets/sounds/upgrade.mp3');
|
||||||
|
this.load.audio('flak', 'assets/sounds/flak.mp3');
|
||||||
|
|
||||||
// Music
|
// Music
|
||||||
this.load.audio('level-bg1', 'assets/music/level-bg1.mp3');
|
this.load.audio('level-bg1', 'assets/music/level-bg1.mp3');
|
||||||
|
|
|
||||||
|
|
@ -254,8 +254,8 @@ export class InterfaceManager {
|
||||||
const tower = TOWERS_CONFIG[type];
|
const tower = TOWERS_CONFIG[type];
|
||||||
this.gridAdd(x, y, tower.name, tower.cost, type);
|
this.gridAdd(x, y, tower.name, tower.cost, type);
|
||||||
x++;
|
x++;
|
||||||
if (x > 6) {
|
if (x > 4) {
|
||||||
y = 2;
|
y = 1;
|
||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,5 +175,39 @@ export const TOWERS_CONFIG = {
|
||||||
'aoe': 225,
|
'aoe': 225,
|
||||||
'anim': 'none'
|
'anim': 'none'
|
||||||
}
|
}
|
||||||
|
},'flak': {
|
||||||
|
'name': 'Flak Cannon',
|
||||||
|
'cost': 700,
|
||||||
|
'spriteStart': 50,
|
||||||
|
'dmgType': 'aoe',
|
||||||
|
'level1': {
|
||||||
|
'dmgLow': 5,
|
||||||
|
'dmgHigh': 10,
|
||||||
|
'rate': 350,
|
||||||
|
'duration': 350,
|
||||||
|
'range': 300,
|
||||||
|
'aoe': 300,
|
||||||
|
'anim': 'none'
|
||||||
|
},
|
||||||
|
'level2': {
|
||||||
|
'cost': 1400,
|
||||||
|
'dmgLow': 6,
|
||||||
|
'dmgHigh': 11,
|
||||||
|
'rate': 300,
|
||||||
|
'duration': 300,
|
||||||
|
'range': 350,
|
||||||
|
'aoe': 350,
|
||||||
|
'anim': 'none'
|
||||||
|
},
|
||||||
|
'level3': {
|
||||||
|
'cost': 2800,
|
||||||
|
'dmgLow': 7,
|
||||||
|
'dmgHigh': 12,
|
||||||
|
'rate': 250,
|
||||||
|
'duration': 250,
|
||||||
|
'range': 375,
|
||||||
|
'aoe': 375,
|
||||||
|
'anim': 'none'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +36,15 @@ export class TowerManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'flak') {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: tower,
|
||||||
|
angle: 360,
|
||||||
|
duration: 10000,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tower.towerBase = towerBase;
|
tower.towerBase = towerBase;
|
||||||
|
|
||||||
// Generate unique ID for enemy
|
// Generate unique ID for enemy
|
||||||
|
|
@ -189,6 +198,27 @@ export class TowerManager {
|
||||||
this.scene.sound.play('upgrade');
|
this.scene.sound.play('upgrade');
|
||||||
if (tower.props.type === 'icbm') {
|
if (tower.props.type === 'icbm') {
|
||||||
tower.towerBase.setTexture('towers', 29+tower.props.level);
|
tower.towerBase.setTexture('towers', 29+tower.props.level);
|
||||||
|
} else if (tower.props.type === 'flak') {
|
||||||
|
if (newLevel === 'level2') {
|
||||||
|
const towerMid = this.scene.add.sprite(tower.x, tower.y, 'towers', 51).setDepth(12);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: towerMid,
|
||||||
|
angle: -360,
|
||||||
|
duration: 12000,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
tower.towerMid = towerMid;
|
||||||
|
}
|
||||||
|
if (newLevel === 'level3') {
|
||||||
|
const towerMid = this.scene.add.sprite(tower.x, tower.y, 'towers', 52).setDepth(13);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: towerMid,
|
||||||
|
angle: 360,
|
||||||
|
duration: 6000,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
tower.towerMid = towerMid;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tower.setTexture('towers', TOWERS_CONFIG[tower.props.type][newLevel].sprite);
|
tower.setTexture('towers', TOWERS_CONFIG[tower.props.type][newLevel].sprite);
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +239,7 @@ export class TowerManager {
|
||||||
if (this.following.hasOwnProperty(tower.id)) {
|
if (this.following.hasOwnProperty(tower.id)) {
|
||||||
this.scene.enemies.children.iterate((enemy) => {
|
this.scene.enemies.children.iterate((enemy) => {
|
||||||
if (this.following[tower.id] === enemy.props.id
|
if (this.following[tower.id] === enemy.props.id
|
||||||
&& type !== 'icbm')
|
&& type !== 'icbm' && type !=='flak')
|
||||||
{
|
{
|
||||||
// Rotate tower to face the enemy
|
// Rotate tower to face the enemy
|
||||||
const angle = Phaser.Math.Angle.Between(towerX, towerY, enemy.x, enemy.y);
|
const angle = Phaser.Math.Angle.Between(towerX, towerY, enemy.x, enemy.y);
|
||||||
|
|
@ -368,7 +398,9 @@ export class TowerManager {
|
||||||
const dmgHigh = config.dmgHigh;
|
const dmgHigh = config.dmgHigh;
|
||||||
|
|
||||||
const angle = Phaser.Math.Angle.Between(tower.x, tower.y, enemy.x, enemy.y);
|
const angle = Phaser.Math.Angle.Between(tower.x, tower.y, enemy.x, enemy.y);
|
||||||
|
if (type !== 'flak') {
|
||||||
tower.rotation = angle;
|
tower.rotation = angle;
|
||||||
|
}
|
||||||
|
|
||||||
if (type === 'cannon') {
|
if (type === 'cannon') {
|
||||||
this.scene.sound.play('cannon');
|
this.scene.sound.play('cannon');
|
||||||
|
|
@ -416,15 +448,51 @@ export class TowerManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'flak') {
|
||||||
|
const shotAmt = Math.floor((400 - config.rate) / 50);
|
||||||
|
for (let i = 1; i <= shotAmt; i++) {
|
||||||
|
const shotAngle = Phaser.Math.Between(0, 360);
|
||||||
|
const shotDistance = Phaser.Math.Between(0, config.aoe);
|
||||||
|
const shotX = tower.x + Math.cos(shotAngle) * shotDistance;
|
||||||
|
const shotY = tower.y + Math.sin(shotAngle) * shotDistance;
|
||||||
|
const shotType = Phaser.Math.Between(53,55);
|
||||||
|
const shotDelay = i*100;
|
||||||
|
this.scene.time.delayedCall(shotDelay, () => {
|
||||||
|
const shot = this.scene.add.sprite(tower.x, tower.y, 'towers', shotType);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: shot,
|
||||||
|
x: shotX,
|
||||||
|
y: shotY,
|
||||||
|
angle: Phaser.Math.Between(0, 180),
|
||||||
|
duration: 2000,
|
||||||
|
onComplete: () => {
|
||||||
|
// Limit the times this sound plays to not overwhelm speakers
|
||||||
|
if (i === 1) {
|
||||||
|
this.scene.sound.play('flak');
|
||||||
|
}
|
||||||
|
shot.setTexture('towers', Phaser.Math.Between(56,57)).setScale(.4).setAlpha(.8);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: shot,
|
||||||
|
angle: Phaser.Math.Between(-90, 90),
|
||||||
|
alpha: .3,
|
||||||
|
scale: 1,
|
||||||
|
duration: 500,
|
||||||
|
onComplete: () => {
|
||||||
|
shot.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate damage (random between low and high)
|
// Calculate damage (random between low and high)
|
||||||
const damage = Phaser.Math.Between(dmgLow, dmgHigh);
|
const damage = Phaser.Math.Between(dmgLow, dmgHigh);
|
||||||
|
|
||||||
// Get AOE distance
|
|
||||||
const aoeDistance = config.aoe;
|
|
||||||
|
|
||||||
// Apply damage to all enemies in range
|
// Apply damage to all enemies in range
|
||||||
const enemiesInRange = this.scene.enemies.getChildren().filter(e => {
|
const enemiesInRange = this.scene.enemies.getChildren().filter(e => {
|
||||||
return Phaser.Math.Distance.Between(e.x, e.y, enemy.x, enemy.y) <= aoeDistance;
|
return Phaser.Math.Distance.Between(e.x, e.y, enemy.x, enemy.y) <= config.aoe;
|
||||||
});
|
});
|
||||||
|
|
||||||
enemiesInRange.forEach(targetEnemy => {
|
enemiesInRange.forEach(targetEnemy => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue