feat(towers): Implement tower system with gun towers, range visualization, and basic firing logic
This commit introduces a complete tower management system including: - Added TowerManager class to handle tower creation, updates, and firing logic - Implemented gun tower configuration with damage, rate, duration, and range stats - Created visual range circles for towers - Integrated tower placement in level1 scene - Added basic enemy detection and firing mechanics - Updated wave manager to support level completion state The changes enable the core tower defense functionality where towers automatically detect enemies in range and fire at them based on configured rates.
This commit is contained in:
parent
9bf0b55f33
commit
cbbe6d51ed
|
|
@ -1,4 +1,5 @@
|
||||||
import { WaveManager } from '../support/waveManager.js';
|
import { WaveManager } from '../support/waveManager.js';
|
||||||
|
import { TowerManager } from '../support/towerManager.js';
|
||||||
|
|
||||||
export class Level1 extends Phaser.Scene {
|
export class Level1 extends Phaser.Scene {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -12,6 +13,7 @@ export class Level1 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.image('josh', 'assets/josh-life.png');
|
||||||
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
|
||||||
|
|
@ -26,8 +28,12 @@ export class Level1 extends Phaser.Scene {
|
||||||
this.platformsLayer = this.levelMap.createLayer('platforms', terrainTiles);
|
this.platformsLayer = this.levelMap.createLayer('platforms', terrainTiles);
|
||||||
|
|
||||||
this.waveManager = new WaveManager(this, 1, 1);
|
this.waveManager = new WaveManager(this, 1, 1);
|
||||||
|
this.towerManager = new TowerManager(this);
|
||||||
|
|
||||||
this.enemies = this.physics.add.group();
|
this.enemies = this.physics.add.group();
|
||||||
|
this.towers = this.physics.add.group();
|
||||||
|
|
||||||
|
this.towerManager.createTower('gun', 4, 2);
|
||||||
|
|
||||||
this.physics.add.collider(this.enemies, this.mainLayer);
|
this.physics.add.collider(this.enemies, this.mainLayer);
|
||||||
this.physics.add.collider(this.enemies, this.platformsLayer);
|
this.physics.add.collider(this.enemies, this.platformsLayer);
|
||||||
|
|
@ -54,7 +60,12 @@ export class Level1 extends Phaser.Scene {
|
||||||
moveNextStep();
|
moveNextStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gridToLocation(num, offset = 0) {
|
||||||
|
return num * 200 + 100 + offset;
|
||||||
|
}
|
||||||
|
|
||||||
update(time, delta) {
|
update(time, delta) {
|
||||||
this.waveManager.update(time, delta);
|
this.waveManager.update(time, delta);
|
||||||
|
this.towerManager.update(time, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
export const TOWERS_CONFIG = {
|
||||||
|
'gun': {
|
||||||
|
'level1': {
|
||||||
|
'dmgLow': 10,
|
||||||
|
'dmgHigh': 30,
|
||||||
|
'rate': 2000,
|
||||||
|
'duration': 500,
|
||||||
|
'range': 275
|
||||||
|
},
|
||||||
|
'level2': {
|
||||||
|
'dmgLow': 12,
|
||||||
|
'dmgHigh': 33,
|
||||||
|
'rate': 1500,
|
||||||
|
'duration': 750,
|
||||||
|
'range': 300
|
||||||
|
},
|
||||||
|
'level3': {
|
||||||
|
'dmgLow': 15,
|
||||||
|
'dmgHigh': 35,
|
||||||
|
'rate': 1000,
|
||||||
|
'duration': 1000,
|
||||||
|
'range': 325
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { TOWERS_CONFIG } from './towerConfig.js';
|
||||||
|
|
||||||
|
export class TowerManager {
|
||||||
|
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.lastFired = {}; // Track last fire time for each tower
|
||||||
|
}
|
||||||
|
|
||||||
|
createTower(type, x, y) {
|
||||||
|
const posX = this.scene.gridToLocation(x);
|
||||||
|
const posY = this.scene.gridToLocation(y);
|
||||||
|
|
||||||
|
const tower = this.scene.add.image(posX, posY, 'josh');
|
||||||
|
this.scene.towers.add(tower);
|
||||||
|
|
||||||
|
// Draw range circle
|
||||||
|
const config = TOWERS_CONFIG[type].level1;
|
||||||
|
if (config) {
|
||||||
|
const range = config.range;
|
||||||
|
const circle = this.scene.add.circle(posX, posY, range, 0x00ff00, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
// Iterate through all towers
|
||||||
|
this.scene.towers.children.iterate((tower) => {
|
||||||
|
const towerX = tower.x;
|
||||||
|
const towerY = tower.y;
|
||||||
|
|
||||||
|
// Get tower config
|
||||||
|
const type = 'gun'; // Assuming gun towers for now
|
||||||
|
const config = TOWERS_CONFIG[type].level1;
|
||||||
|
|
||||||
|
if (!config) return;
|
||||||
|
|
||||||
|
const range = config.range;
|
||||||
|
const rate = config.rate;
|
||||||
|
|
||||||
|
// Check if enough time has passed since last fire
|
||||||
|
if (this.lastFired[tower.id] === undefined ||
|
||||||
|
time - this.lastFired[tower.id] >= rate) {
|
||||||
|
|
||||||
|
// Check for enemies in range
|
||||||
|
let inRange = false;
|
||||||
|
this.scene.enemies.children.iterate((enemy) => {
|
||||||
|
const distance = Phaser.Math.Distance.Between(
|
||||||
|
towerX, towerY,
|
||||||
|
enemy.x, enemy.y
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance <= range) {
|
||||||
|
inRange = true;
|
||||||
|
return false; // Stop iterating once we find one enemy
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fire if enemies are in range
|
||||||
|
if (inRange) {
|
||||||
|
console.log('fire');
|
||||||
|
this.lastFired[tower.id] = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ export class WaveManager {
|
||||||
this.endX = WAVE_CONFIG[this.level].endX;
|
this.endX = WAVE_CONFIG[this.level].endX;
|
||||||
this.endY = WAVE_CONFIG[this.level].endY;
|
this.endY = WAVE_CONFIG[this.level].endY;
|
||||||
this.path = null;
|
this.path = null;
|
||||||
|
this.levelActive = true;
|
||||||
|
|
||||||
this.waveTimer = 0;
|
this.waveTimer = 0;
|
||||||
this.waveScheduleStartTime();
|
this.waveScheduleStartTime();
|
||||||
|
|
@ -32,13 +33,7 @@ export class WaveManager {
|
||||||
this.waveScheduleStartTime();
|
this.waveScheduleStartTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
gridToLocation(num, offset = 0) {
|
|
||||||
return num * 200 + 100 + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(time, delta) {
|
update(time, delta) {
|
||||||
this.waveTimer += delta;
|
|
||||||
|
|
||||||
// Handle Enemy Pathing
|
// Handle Enemy Pathing
|
||||||
this.scene.enemies.children.iterate((enemy) => {
|
this.scene.enemies.children.iterate((enemy) => {
|
||||||
const path = enemy.props.path;
|
const path = enemy.props.path;
|
||||||
|
|
@ -58,8 +53,8 @@ export class WaveManager {
|
||||||
|
|
||||||
if (currentPoint && nextPoint) {
|
if (currentPoint && nextPoint) {
|
||||||
// Calculate direction vector from current to next point
|
// Calculate direction vector from current to next point
|
||||||
const dx = this.gridToLocation(nextPoint.x, offsetX) - this.gridToLocation(currentPoint.x, offsetX);
|
const dx = this.scene.gridToLocation(nextPoint.x, offsetX) - this.scene.gridToLocation(currentPoint.x, offsetX);
|
||||||
const dy = this.gridToLocation(nextPoint.y, offsetY) - this.gridToLocation(currentPoint.y, offsetY);
|
const dy = this.scene.gridToLocation(nextPoint.y, offsetY) - this.scene.gridToLocation(currentPoint.y, offsetY);
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
// Normalize the direction
|
// Normalize the direction
|
||||||
|
|
@ -90,8 +85,8 @@ export class WaveManager {
|
||||||
|
|
||||||
// Check if we've reached the next point
|
// Check if we've reached the next point
|
||||||
const distToNextPoint = Math.sqrt(
|
const distToNextPoint = Math.sqrt(
|
||||||
Math.pow(enemy.x - this.gridToLocation(nextPoint.x, offsetX), 2) +
|
Math.pow(enemy.x - this.scene.gridToLocation(nextPoint.x, offsetX), 2) +
|
||||||
Math.pow(enemy.y - this.gridToLocation(nextPoint.y, offsetY), 2)
|
Math.pow(enemy.y - this.scene.gridToLocation(nextPoint.y, offsetY), 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (distToNextPoint < segmentSpeed * 0.5) { // Threshold for reaching point
|
if (distToNextPoint < segmentSpeed * 0.5) { // Threshold for reaching point
|
||||||
|
|
@ -116,7 +111,9 @@ export class WaveManager {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle Waves and Schedules
|
// Handle Waves and Schedules
|
||||||
if (this.waveTimer >= this.waveStart) {
|
this.waveTimer += delta;
|
||||||
|
|
||||||
|
if (this.waveTimer >= this.waveStart && this.levelActive === true) {
|
||||||
console.log('Wave',this.wave,'Schedule',this.schedule);
|
console.log('Wave',this.wave,'Schedule',this.schedule);
|
||||||
// Make path synchronous
|
// Make path synchronous
|
||||||
this.makePath().then(() => {
|
this.makePath().then(() => {
|
||||||
|
|
@ -129,6 +126,7 @@ export class WaveManager {
|
||||||
this.nextWave();
|
this.nextWave();
|
||||||
} else {
|
} else {
|
||||||
console.log('LEVEL COMPLETE');
|
console.log('LEVEL COMPLETE');
|
||||||
|
this.levelActive = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue