diff --git a/assets/nextWave.png b/assets/nextWave.png new file mode 100644 index 0000000..4c849c2 Binary files /dev/null and b/assets/nextWave.png differ diff --git a/assets/nextWave.psd b/assets/nextWave.psd new file mode 100644 index 0000000..e88fc58 Binary files /dev/null and b/assets/nextWave.psd differ diff --git a/assets/towers.png b/assets/towers.png index bc32efa..80ff321 100644 Binary files a/assets/towers.png and b/assets/towers.png differ diff --git a/assets/towers.psd b/assets/towers.psd index 26d33d7..c99c0f5 100644 Binary files a/assets/towers.psd and b/assets/towers.psd differ diff --git a/src/levels/level.js b/src/levels/level.js index e352a30..faa9ba4 100644 --- a/src/levels/level.js +++ b/src/levels/level.js @@ -43,9 +43,6 @@ export class Level extends Phaser.Scene { this.enemies = this.physics.add.group(); this.towers = this.physics.add.group(); - this.towerManager.createTower('gun', 2, 1); - this.towerManager.createTower('gun', 4, 2); - this.physics.add.collider(this.enemies, this.mainLayer); this.physics.add.collider(this.enemies, this.platformsLayer); } diff --git a/src/support/interfaceManager.js b/src/support/interfaceManager.js index 1c3cdc7..c05dee5 100644 --- a/src/support/interfaceManager.js +++ b/src/support/interfaceManager.js @@ -7,6 +7,11 @@ export class InterfaceManager { this.gold = 100; this.cores = 20; this.interfaceOpen = false; + this.selectedTower = false; + this.selectedTowerPos = { + x: 0, + y: 0 + } this.paintInterface(); } @@ -123,18 +128,83 @@ export class InterfaceManager { this.interfaceUp.on('pointerdown', () => { if (!this.interfaceOpen) { this.openInterface(); - this.interfaceOpen = true; // Disable further clicks this.interfaceUp.disableInteractive(); } else { this.closeInterface(); - this.interfaceOpen = false; this.interfaceUp.disableInteractive(); } }); + + // Next Wave Button + this.waveStart = this.scene.add.container().setScrollFactor(0); + const nextWaveBack = this.scene.add.rectangle(1250, 200, 235, 100, 0x000000, 1).setOrigin(0, 0.5).setScrollFactor(0); + this.buttonBack = this.scene.add.sprite(1250, 200, 'nextWave', 0).setOrigin(0.5).setScrollFactor(0); + this.buttonBack.on('pointerdown', () => { + const waveManager = this.scene.levelScene.waveManager + waveManager.waveActive = true; + waveManager.nextWave(); + this.hideNextWave(); + }) + const button = this.scene.add.sprite(1250, 200, 'nextWave', 1).setOrigin(0.5).setScrollFactor(0); + button.preFX.addGlow(0xffd900, 10); + const nextWaveText = this.scene.add.text(1300, 200, 'Start\nNext Wave', { + fontFamily: 'neuropol, arial', + fontSize: '28px', + fill: '#ffd900ff', + stroke: '#c48f00ff', + strokeThickness: 2, + shadow: { + offsetX: 5, + offsetY: 5, + color: '#000000', + blur: 5, + stroke: false, + fill: true + } + }).setOrigin(0, 0.5).setScrollFactor(0); + + this.scene.tweens.add({ + targets: this.buttonBack, + angle: -360, + duration: 20000, + repeat: -1 + }) + this.scene.tweens.add({ + targets: button.preFX.list[0], + outerStrength: 0, + duration: 2000, + yoyo: true, + repeat: -1 + }); + + this.waveStart.add(nextWaveBack); + this.waveStart.add(this.buttonBack); + this.waveStart.add(button); + this.waveStart.add(nextWaveText); + this.waveStart.setAlpha(0); + } + + hideNextWave() { + this.buttonBack.disableInteractive() + this.scene.tweens.add({ + targets: this.waveStart, + alpha: 0, + duration: 500 + }); + } + + showNextWave() { + this.buttonBack.setInteractive() + this.scene.tweens.add({ + targets: this.waveStart, + alpha: 1, + duration: 1000 + }); } openInterface() { + this.interfaceOpen = true; this.upLeft.setAlpha(0).setRotation(Math.PI); this.upRight.setAlpha(0).setRotation(Math.PI); this.interfaceText.setAlpha(0).setText('Click to Close'); @@ -154,6 +224,7 @@ export class InterfaceManager { } closeInterface() { + this.interfaceOpen = false; this.upLeft.setAlpha(0).setRotation(0); this.upRight.setAlpha(0).setRotation(0); this.interfaceText.setAlpha(0).setText('Click to Open'); @@ -177,7 +248,7 @@ export class InterfaceManager { 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, 'gun'); + this.gridAdd(1, 1, 'Cannon', 200, 'cannon'); } gridAdd(x, y, text, cost, type) { @@ -196,6 +267,9 @@ export class InterfaceManager { .setScrollFactor(0); slot.add(slotBack); slotBack.setInteractive(); + slotBack.on('pointerdown', () => { + this.selectTower(type); + }); // Add gold text display const slotText = this.scene.add.text(startX-95, startY+75, `${text}`, { @@ -276,7 +350,105 @@ export class InterfaceManager { } } - update(time, delta) { + selectTower(type) { + this.selectedTower = this.scene.levelScene.add.container(); + const towerInteractive = this.scene.add.rectangle(0, 0, 200, 200, 0x000000, 0); + this.selectedTower.add(towerInteractive); + + const towerBase = this.scene.add.sprite(0, 0, 'towers', 7) + .setOrigin(0.5) + .setScrollFactor(0) + .setTint(0xa32a00); + this.selectedTower.add(towerBase); + + const towerTop = this.scene.add.sprite(0, 0, 'towers', TOWERS_CONFIG[type].spriteStart) + .setOrigin(0.5) + .setScrollFactor(0) + .setTint(0xa32a00); + this.selectedTower.add(towerTop); + + towerInteractive.on('pointerdown', () => { + this.placeTower(type); + }); + towerInteractive.setInteractive(); + + this.closeInterface(); + } + + placeTower(type) { + if (this.selectedTower.safe === true) { + //Bring up Next Wave on first tower: + if (this.scene.levelScene.towers.countActive() === 0) { + this.showNextWave(); + } + + // Snap to current mouse position + const mouse = this.scene.input.activePointer; + const worldX = mouse.worldX; + const worldY = mouse.worldY; + + // Convert world coordinates to tile coordinates + const tileX = Math.floor(worldX / 200); // Assuming 200px tile width + const tileY = Math.floor(worldY / 200); // Assuming 200px tile height + + this.scene.levelScene.towerManager.createTower(type, tileX, tileY); + this.scene.removeGold(TOWERS_CONFIG[type].cost); + console.log(this.scene.levelScene.towers.countActive()); + } + + // Clear Tower Selection Regardless + this.selectedTower.destroy(); + this.selectedTower = false; + } + + update(time, delta) { + if (this.selectedTower) { + // Snap to current mouse position + const mouse = this.scene.input.activePointer; + const worldX = mouse.worldX; + const worldY = mouse.worldY; + + // Convert world coordinates to tile coordinates + const tileX = Math.floor(worldX / 200); // Assuming 200px tile width + const tileY = Math.floor(worldY / 200); // Assuming 200px tile height + + if (tileX !== this.selectedTowerPos.x || tileY !== this.selectedTowerPos.y) { + this.selectedTowerPos = { + x: tileX, + y: tileY + }; + // Convert back to world position for proper snapping + const snappedX = tileX * 200 + 100; // Center the tower on the tile (assuming 200px tiles) + const snappedY = tileY * 200 + 100; + + this.selectedTower.setPosition(snappedX, snappedY); + + const platformsLayer = this.scene.levelScene.platformsLayer; + if (platformsLayer) { + const tile = platformsLayer.getTileAt(tileX, tileY); + if (tile) { + this.selectedTower.iterate((child) => { + if (child.type !== 'Rectangle') { + child.setTint(0x89ff5b); + } + }); + this.selectedTower.safe = true; + } else { + this.selectedTower.iterate((child) => { + if (child.type !== 'Rectangle') { + child.setTint(0xa32a00); + } + }); + this.selectedTower.safe = false; + } + } + } + + if (mouse.rightButtonDown()) { + this.selectedTower.destroy(); + this.selectedTower = false; + } + } } } \ No newline at end of file diff --git a/src/support/towerConfig.js b/src/support/towerConfig.js index 0c7c25b..8a187d6 100644 --- a/src/support/towerConfig.js +++ b/src/support/towerConfig.js @@ -1,6 +1,10 @@ export const TOWERS_CONFIG = { 'gun': { + 'name': 'Gatlin Gun', + 'cost': 100, 'spriteStart': 0, + 'type': 'direct', + 'aoe': 0, 'level1': { 'dmgLow': 10, 'dmgHigh': 30, @@ -22,5 +26,33 @@ export const TOWERS_CONFIG = { 'duration': 1000, 'range': 325 } + }, + 'cannon': { + 'name': 'Cannon', + 'cost': 200, + 'spriteStart': 10, + 'type': 'aoe', + 'aoe': 50, + 'level1': { + 'dmgLow': 15, + 'dmgHigh': 35, + 'rate': 2000, + 'duration': 200, + 'range': 400 + }, + 'level2': { + 'dmgLow': 25, + 'dmgHigh': 45, + 'rate': 2000, + 'duration': 500, + 'range': 450 + }, + 'level3': { + 'dmgLow': 35, + 'dmgHigh': 65, + 'rate': 2000, + 'duration': 500, + 'range': 500 + } } } \ No newline at end of file diff --git a/src/support/towerManager.js b/src/support/towerManager.js index a989843..1416073 100644 --- a/src/support/towerManager.js +++ b/src/support/towerManager.js @@ -36,39 +36,6 @@ export class TowerManager { } } - createAnims() { - this.scene.anims.create({ - key: 'gun-level1-fire', - frames: this.scene.anims.generateFrameNumbers('towers', { - start: 0, - end: 1, - }), - frameRate: 15, - repeat: 5, - yoyo: true - }); - this.scene.anims.create({ - key: 'gun-level2-fire', - frames: this.scene.anims.generateFrameNumbers('towers', { - start: 2, - end: 3, - }), - frameRate: 15, - repeat: 10, - yoyo: true - }); - this.scene.anims.create({ - key: 'gun-level3-fire', - frames: this.scene.anims.generateFrameNumbers('towers', { - start: 4, - end: 5, - }), - frameRate: 15, - repeat: 15, - yoyo: true - }); - } - update(time, delta) { // Iterate through all towers this.scene.towers.children.iterate((tower) => { @@ -134,6 +101,7 @@ export class TowerManager { 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; @@ -143,7 +111,7 @@ export class TowerManager { const angle = Phaser.Math.Angle.Between(tower.x, tower.y, enemy.x, enemy.y); tower.rotation = angle; - tower.play(`${type}-${level}-fire`, { duration: 500 }); + tower.play(`${type}-${level}-fire`, { 'duration': duration }); // Calculate damage (random between low and high) const damage = Phaser.Math.Between(dmgLow, dmgHigh); @@ -215,6 +183,9 @@ export class TowerManager { // Calculate end position (100px away from original position in the calculated direction) const endX = dieX + Math.cos(angle) * 50; const endY = dieY + Math.sin(angle) * 50; + + // Get coords of Gold Interface + const cam = this.scene.cameras.main; // Animate the cash drop moving to the new position this.scene.tweens.add({ @@ -227,8 +198,8 @@ export class TowerManager { cashDrop.postFX.addGlow(); this.scene.tweens.add({ targets: cashDrop, - x: 1300, - y: 100, + x: 1300 + cam.scrollX, + y: 100 + cam.scrollY, alpha: 0, duration: 500, onComplete: () => { @@ -258,4 +229,47 @@ export class TowerManager { this.following[tower.id] = null; } + createAnims() { + this.scene.anims.create({ + key: 'gun-level1-fire', + frames: this.scene.anims.generateFrameNumbers('towers', { + start: 0, + end: 1, + }), + frameRate: 15, + repeat: 5, + yoyo: true + }); + this.scene.anims.create({ + key: 'gun-level2-fire', + frames: this.scene.anims.generateFrameNumbers('towers', { + start: 2, + end: 3, + }), + frameRate: 15, + repeat: 10, + yoyo: true + }); + this.scene.anims.create({ + key: 'gun-level3-fire', + frames: this.scene.anims.generateFrameNumbers('towers', { + start: 4, + end: 5, + }), + frameRate: 15, + repeat: 15, + yoyo: true + }); + this.scene.anims.create({ + key: 'cannon-level1-fire', + frames: this.scene.anims.generateFrameNumbers('towers', { + start: 10, + end: 11 + }), + frameRate:3, + repeat: 0, + yoyo: true + }) + } + } \ No newline at end of file diff --git a/src/support/waveConfig.js b/src/support/waveConfig.js index f73e449..17bb968 100644 --- a/src/support/waveConfig.js +++ b/src/support/waveConfig.js @@ -15,13 +15,11 @@ export const WAVE_CONFIG = { }, 2: { begin: 15, - basic1: 5, - basic2: 2 + basic1: 8, }, 3: { begin: 30, - basic1: 4, - basic2: 3 + basic1: 10, } }, // Wave @@ -29,15 +27,18 @@ export const WAVE_CONFIG = { // Schedule 1: { begin: 0, - basic1: 5 + basic1: 8, + basic2: 1 }, 2: { begin: 15, - basic1: 5 + basic1: 5, + basic2: 2 }, 3: { begin: 30, - basic1: 5 + basic1: 5, + basic2: 4 } } } diff --git a/src/support/waveManager.js b/src/support/waveManager.js index b4a2464..4c21602 100644 --- a/src/support/waveManager.js +++ b/src/support/waveManager.js @@ -6,7 +6,7 @@ export class WaveManager { constructor(scene, level, wave) { this.scene = scene; this.level = level; - this.wave = wave; + this.wave = wave-1; this.schedule = 0; this.scheduleInfo = null; this.spawnX = WAVE_CONFIG[this.level].spawnX; @@ -15,9 +15,9 @@ export class WaveManager { this.endY = WAVE_CONFIG[this.level].endY; this.path = null; this.levelActive = true; + this.waveActive = false; this.waveTimer = 0; - this.waveScheduleStartTime(); this.placeCore(); } @@ -28,10 +28,13 @@ export class WaveManager { } nextWave() { - this.wave++; - this.waveTimer = 0; - this.schedule = 0; - this.waveScheduleStartTime(); + // Next Wave will be started in the interfaceManager + if (this.waveActive === true) { + this.wave++; + this.waveTimer = 0; + this.schedule = 0; + this.waveScheduleStartTime(); + } } placeCore() { @@ -146,7 +149,7 @@ export class WaveManager { // Handle Waves and Schedules this.waveTimer += delta; - if (this.waveTimer >= this.waveStart && this.levelActive === true) { + if (this.waveTimer >= this.waveStart && this.levelActive === true && this.waveActive===true) { console.log('Wave',this.wave,'Schedule',this.schedule); // Make path synchronous this.makePath().then(() => { @@ -155,8 +158,10 @@ export class WaveManager { if (WAVE_CONFIG[this.level][this.wave].hasOwnProperty(this.schedule + 1)) { this.waveScheduleStartTime(); - } else if (WAVE_CONFIG[this.level].hasOwnProperty(this.wave+1)) { - this.nextWave(); + } else if (WAVE_CONFIG[this.level].hasOwnProperty(this.wave+1)) { + this.waveActive = false; + this.scene.UIScene.interfaceManager.showNextWave(); + //this.nextWave(); } else { console.log('LEVEL COMPLETE'); this.levelActive = false; diff --git a/src/uiScene.js b/src/uiScene.js index 1b634ba..e6c56d4 100644 --- a/src/uiScene.js +++ b/src/uiScene.js @@ -16,6 +16,10 @@ export class UIScene extends Phaser.Scene { this.load.image('redArrow', 'assets/redArrow.png'); this.load.image('intTop', 'assets/intTop.png'); this.load.image('gold', 'assets/gold.png'); + this.load.spritesheet('nextWave', 'assets/nextWave.png', { + frameHeight: 150, + frameWidth: 150 + }); } create() { @@ -33,6 +37,11 @@ export class UIScene extends Phaser.Scene { this.updateGold(); } + removeGold(amount) { + this.interfaceManager.gold -= amount; + this.updateGold(); + } + updateGold() { this.interfaceManager.goldText.setText(`${this.interfaceManager.gold}`); }