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:
parent
7180612aab
commit
37a292c022
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 366 KiB |
Binary file not shown.
|
|
@ -13,6 +13,10 @@ export class Level extends Phaser.Scene {
|
||||||
preload() {
|
preload() {
|
||||||
this.load.tilemapTiledJSON('level1', 'assets/level1.json');
|
this.load.tilemapTiledJSON('level1', 'assets/level1.json');
|
||||||
this.load.image('terrain', 'assets/terrain.png');
|
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', {
|
this.load.spritesheet('basic-enemies', 'assets/basic-enemies.png', {
|
||||||
frameWidth: 50,
|
frameWidth: 50,
|
||||||
frameHeight: 50
|
frameHeight: 50
|
||||||
|
|
@ -57,23 +61,23 @@ export class Level extends Phaser.Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
addControls() {
|
addControls() {
|
||||||
this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY) => {
|
// this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY) => {
|
||||||
const zoomSpeed = 0.1;
|
// const zoomSpeed = 0.1;
|
||||||
if (deltaY < 0) {
|
// if (deltaY < 0) {
|
||||||
// Zoom in
|
// // Zoom in
|
||||||
this.cameras.main.zoom += zoomSpeed;
|
// this.cameras.main.zoom += zoomSpeed;
|
||||||
} else if (deltaY > 0) {
|
// } else if (deltaY > 0) {
|
||||||
// Zoom out
|
// // Zoom out
|
||||||
this.cameras.main.zoom -= zoomSpeed;
|
// this.cameras.main.zoom -= zoomSpeed;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Limit zoom range to prevent extreme zoom levels
|
// // Limit zoom range to prevent extreme zoom levels
|
||||||
this.cameras.main.zoom = Phaser.Math.Clamp(this.cameras.main.zoom, 0.5, 2);
|
// this.cameras.main.zoom = Phaser.Math.Clamp(this.cameras.main.zoom, 0.5, 2);
|
||||||
|
|
||||||
// Zoom toward mouse position
|
// // Zoom toward mouse position
|
||||||
const worldPoint = this.input.activePointer.positionToCamera(this.cameras.main);
|
// const worldPoint = this.input.activePointer.positionToCamera(this.cameras.main);
|
||||||
this.cameras.main.centerOn(worldPoint.x, worldPoint.y);
|
// this.cameras.main.centerOn(worldPoint.x, worldPoint.y);
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Add camera panning functionality
|
// Add camera panning functionality
|
||||||
this.input.on('pointerdown', (pointer) => {
|
this.input.on('pointerdown', (pointer) => {
|
||||||
|
|
|
||||||
|
|
@ -256,10 +256,6 @@ export class InterfaceManager {
|
||||||
x = 0;
|
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) {
|
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);
|
const towerInteractive = this.scene.add.rectangle(0, 0, 200, 200, 0x000000, 0);
|
||||||
this.selectedTower.add(towerInteractive);
|
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)
|
const towerBase = this.scene.add.sprite(0, 0, 'towers', 7)
|
||||||
.setOrigin(0.5)
|
.setOrigin(0.5)
|
||||||
.setScrollFactor(0)
|
.setScrollFactor(0)
|
||||||
|
|
@ -442,14 +443,15 @@ export class InterfaceManager {
|
||||||
const tile = platformsLayer.getTileAt(tileX, tileY);
|
const tile = platformsLayer.getTileAt(tileX, tileY);
|
||||||
if (tile) {
|
if (tile) {
|
||||||
this.selectedTower.iterate((child) => {
|
this.selectedTower.iterate((child) => {
|
||||||
if (child.type !== 'Rectangle') {
|
if (child.type !== 'Rectangle' && child.type !== 'Arc') {
|
||||||
child.setTint(0x89ff5b);
|
child.setTint(0x48ff00);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.selectedTower.safe = true;
|
this.selectedTower.safe = true;
|
||||||
} else {
|
} else {
|
||||||
this.selectedTower.iterate((child) => {
|
this.selectedTower.iterate((child) => {
|
||||||
if (child.type !== 'Rectangle') {
|
if (child.type !== 'Rectangle' && child.type !== 'Arc') {
|
||||||
|
console.log(child.type);
|
||||||
child.setTint(0xa32a00);
|
child.setTint(0xa32a00);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,56 +3,87 @@ export const TOWERS_CONFIG = {
|
||||||
'name': 'Gatlin Gun',
|
'name': 'Gatlin Gun',
|
||||||
'cost': 100,
|
'cost': 100,
|
||||||
'spriteStart': 0,
|
'spriteStart': 0,
|
||||||
'type': 'direct',
|
'dmgType': 'direct',
|
||||||
'aoe': 0,
|
|
||||||
'level1': {
|
'level1': {
|
||||||
'dmgLow': 10,
|
'dmgLow': 10,
|
||||||
'dmgHigh': 30,
|
'dmgHigh': 30,
|
||||||
'rate': 2000,
|
'rate': 2000,
|
||||||
'duration': 500,
|
'duration': 500,
|
||||||
'range': 275
|
'range': 300
|
||||||
},
|
},
|
||||||
'level2': {
|
'level2': {
|
||||||
'dmgLow': 15,
|
'dmgLow': 15,
|
||||||
'dmgHigh': 35,
|
'dmgHigh': 35,
|
||||||
'rate': 1500,
|
'rate': 1500,
|
||||||
'duration': 750,
|
'duration': 750,
|
||||||
'range': 300
|
'range': 350
|
||||||
},
|
},
|
||||||
'level3': {
|
'level3': {
|
||||||
'dmgLow': 25,
|
'dmgLow': 25,
|
||||||
'dmgHigh': 50,
|
'dmgHigh': 50,
|
||||||
'rate': 1000,
|
'rate': 1000,
|
||||||
'duration': 1000,
|
'duration': 1000,
|
||||||
'range': 325
|
'range': 400
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'cannon': {
|
'cannon': {
|
||||||
'name': 'Cannon',
|
'name': 'Cannon',
|
||||||
'cost': 200,
|
'cost': 200,
|
||||||
'spriteStart': 10,
|
'spriteStart': 10,
|
||||||
'type': 'aoe',
|
'dmgType': 'aoe',
|
||||||
'aoe': 50,
|
|
||||||
'level1': {
|
'level1': {
|
||||||
'dmgLow': 15,
|
'dmgLow': 15,
|
||||||
'dmgHigh': 35,
|
'dmgHigh': 35,
|
||||||
'rate': 2000,
|
'rate': 2500,
|
||||||
'duration': 200,
|
'duration': 200,
|
||||||
'range': 400
|
'range': 400,
|
||||||
|
'aoe': 50,
|
||||||
},
|
},
|
||||||
'level2': {
|
'level2': {
|
||||||
'dmgLow': 25,
|
'dmgLow': 25,
|
||||||
'dmgHigh': 45,
|
'dmgHigh': 45,
|
||||||
'rate': 2000,
|
'rate': 2500,
|
||||||
'duration': 500,
|
'duration': 500,
|
||||||
'range': 450
|
'range': 450,
|
||||||
|
'aoe': 25,
|
||||||
},
|
},
|
||||||
'level3': {
|
'level3': {
|
||||||
'dmgLow': 35,
|
'dmgLow': 35,
|
||||||
'dmgHigh': 65,
|
'dmgHigh': 65,
|
||||||
'rate': 2000,
|
'rate': 2500,
|
||||||
'duration': 500,
|
'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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -89,13 +89,19 @@ export class TowerManager {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.following[tower.id] = furthestEnemy.props.id;
|
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.attackTarget(tower, furthestEnemy);
|
||||||
|
}
|
||||||
|
|
||||||
this.lastFired[tower.id] = time;
|
this.lastFired[tower.id] = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
attackTarget(tower, enemy) {
|
attackTarget(tower, enemy) {
|
||||||
// Tower Properties
|
// Tower Properties
|
||||||
const type = tower.props.type;
|
const type = tower.props.type;
|
||||||
|
|
@ -121,11 +127,98 @@ export class TowerManager {
|
||||||
|
|
||||||
if (enemy.props.health > 0) {
|
if (enemy.props.health > 0) {
|
||||||
this.createHealthBar(enemy);
|
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 {
|
} else {
|
||||||
this.destroyEnemy(enemy, tower);
|
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) {
|
createHealthBar(enemy) {
|
||||||
const barWidth = 30;
|
const barWidth = 30;
|
||||||
const barHeight = 5;
|
const barHeight = 5;
|
||||||
|
|
@ -230,6 +323,15 @@ export class TowerManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
createAnims() {
|
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({
|
this.scene.anims.create({
|
||||||
key: 'gun-level1-fire',
|
key: 'gun-level1-fire',
|
||||||
frames: this.scene.anims.generateFrameNumbers('towers', {
|
frames: this.scene.anims.generateFrameNumbers('towers', {
|
||||||
|
|
@ -237,7 +339,7 @@ export class TowerManager {
|
||||||
end: 1,
|
end: 1,
|
||||||
}),
|
}),
|
||||||
frameRate: 15,
|
frameRate: 15,
|
||||||
repeat: 5,
|
repeat: 6,
|
||||||
yoyo: true
|
yoyo: true
|
||||||
});
|
});
|
||||||
this.scene.anims.create({
|
this.scene.anims.create({
|
||||||
|
|
@ -263,12 +365,20 @@ export class TowerManager {
|
||||||
this.scene.anims.create({
|
this.scene.anims.create({
|
||||||
key: 'cannon-level1-fire',
|
key: 'cannon-level1-fire',
|
||||||
frames: this.scene.anims.generateFrameNumbers('towers', {
|
frames: this.scene.anims.generateFrameNumbers('towers', {
|
||||||
start: 10,
|
start: 11,
|
||||||
end: 11
|
end: 10
|
||||||
}),
|
}),
|
||||||
frameRate:3,
|
frameRate: 5,
|
||||||
repeat: 0,
|
repeat: 0
|
||||||
yoyo: true
|
});
|
||||||
|
this.scene.anims.create({
|
||||||
|
key: 'flamethrower',
|
||||||
|
frames: this.scene.anims.generateFrameNumbers('towers', {
|
||||||
|
start: 23,
|
||||||
|
end:25
|
||||||
|
}),
|
||||||
|
framerate: 4,
|
||||||
|
repeat: -1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue