Tower Defense Game - Major Update
- Refactored level system from Level1 to Level with improved camera controls (zoom/pan) - Enhanced tower management with new animations and firing mechanics - Updated enemy configurations with increased health, damage, and drop rates - Implemented comprehensive UI interface with tower selection and resource management - Added wave progression system with multiple enemy types and spawn scheduling - Improved visual effects including glowing cores, particle effects, and animated gold drops - Integrated new assets including font files, spritesheets, and interface elements This update transforms the basic tower defense game into a more polished experience with enhanced gameplay mechanics, better visuals, and improved user interface.
|
After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 887 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 192 KiB |
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { WaveManager } from '../support/waveManager.js';
|
||||||
|
import { TowerManager } from '../support/towerManager.js';
|
||||||
|
|
||||||
|
export class Level extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'Level' });
|
||||||
|
}
|
||||||
|
|
||||||
|
init(data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
this.load.tilemapTiledJSON('level1', 'assets/level1.json');
|
||||||
|
this.load.image('terrain', 'assets/terrain.png');
|
||||||
|
this.load.spritesheet('basic-enemies', 'assets/basic-enemies.png', {
|
||||||
|
frameWidth: 50,
|
||||||
|
frameHeight: 50
|
||||||
|
});
|
||||||
|
this.load.spritesheet('towers', 'assets/towers.png', {
|
||||||
|
frameHeight: 150,
|
||||||
|
frameWidth: 150
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
this.levelMap = this.make.tilemap({ key: 'level1' });
|
||||||
|
const terrainTiles = this.levelMap.addTilesetImage('terrain', 'terrain');
|
||||||
|
this.mainLayer = this.levelMap.createLayer('main', terrainTiles)
|
||||||
|
.setCollisionByProperty({ collides: true });
|
||||||
|
this.platformsLayer = this.levelMap.createLayer('platforms', terrainTiles);
|
||||||
|
|
||||||
|
// Add camera zoom functionality
|
||||||
|
this.cameras.main.setBounds(0, 0, 2000, 2000);
|
||||||
|
this.addControls();
|
||||||
|
|
||||||
|
this.waveManager = new WaveManager(this, 1, 1);
|
||||||
|
this.towerManager = new TowerManager(this);
|
||||||
|
|
||||||
|
this.scene.launch('UIScene');
|
||||||
|
this.UIScene = this.scene.get('UIScene');
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
gridToLocation(num, offset = 0) {
|
||||||
|
return num * 200 + 100 + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
this.waveManager.update(time, delta);
|
||||||
|
this.towerManager.update(time, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add camera panning functionality
|
||||||
|
this.input.on('pointerdown', (pointer) => {
|
||||||
|
if (pointer.button === 0) { // Left mouse button
|
||||||
|
this.isPanning = true;
|
||||||
|
this.panStartX = pointer.x;
|
||||||
|
this.panStartY = pointer.y;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.input.on('pointermove', (pointer) => {
|
||||||
|
if (this.isPanning && pointer.isDown) {
|
||||||
|
const dx = pointer.x - this.panStartX;
|
||||||
|
const dy = pointer.y - this.panStartY;
|
||||||
|
|
||||||
|
// Pan the camera
|
||||||
|
this.cameras.main.scrollX -= dx;
|
||||||
|
this.cameras.main.scrollY -= dy;
|
||||||
|
|
||||||
|
// Update start position for next move
|
||||||
|
this.panStartX = pointer.x;
|
||||||
|
this.panStartY = pointer.y;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.input.on('pointerup', (pointer) => {
|
||||||
|
if (pointer.button === 0) { // Left mouse button
|
||||||
|
this.isPanning = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
import { WaveManager } from '../support/waveManager.js';
|
|
||||||
import { TowerManager } from '../support/towerManager.js';
|
|
||||||
|
|
||||||
export class Level1 extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Level1' });
|
|
||||||
}
|
|
||||||
|
|
||||||
init(data) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
preload() {
|
|
||||||
this.load.tilemapTiledJSON('level1', 'assets/level1.json');
|
|
||||||
this.load.image('terrain', 'assets/terrain.png');
|
|
||||||
this.load.spritesheet('basic-enemies', 'assets/basic-enemies.png', {
|
|
||||||
frameWidth: 50,
|
|
||||||
frameHeight: 50
|
|
||||||
});
|
|
||||||
this.load.spritesheet('towers', 'assets/towers.png', {
|
|
||||||
frameHeight: 100,
|
|
||||||
frameWidth: 100
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.levelMap = this.make.tilemap({ key: 'level1' });
|
|
||||||
const terrainTiles = this.levelMap.addTilesetImage('terrain', 'terrain');
|
|
||||||
this.mainLayer = this.levelMap.createLayer('main', terrainTiles)
|
|
||||||
.setCollisionByProperty({ collides: true });
|
|
||||||
this.platformsLayer = this.levelMap.createLayer('platforms', terrainTiles);
|
|
||||||
|
|
||||||
this.waveManager = new WaveManager(this, 1, 1);
|
|
||||||
this.towerManager = new TowerManager(this);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
gridToLocation(num, offset = 0) {
|
|
||||||
return num * 200 + 100 + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(time, delta) {
|
|
||||||
this.waveManager.update(time, delta);
|
|
||||||
this.towerManager.update(time, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Level1 } from './levels/level1.js';
|
import { Level } from './levels/level.js';
|
||||||
|
import { UIScene } from './uiScene.js';
|
||||||
|
|
||||||
const GAME_CONFIG = {
|
const GAME_CONFIG = {
|
||||||
type: Phaser.AUTO,
|
type: Phaser.AUTO,
|
||||||
|
|
@ -12,7 +13,8 @@ const GAME_CONFIG = {
|
||||||
parent: 'game-container',
|
parent: 'game-container',
|
||||||
backgroundColor: '#bb7432ff',
|
backgroundColor: '#bb7432ff',
|
||||||
scene: [
|
scene: [
|
||||||
Level1
|
Level,
|
||||||
|
UIScene
|
||||||
],
|
],
|
||||||
physics: {
|
physics: {
|
||||||
default: 'arcade',
|
default: 'arcade',
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,14 @@ export const ENEMIES_CONFIG = {
|
||||||
'dropHigh': 2
|
'dropHigh': 2
|
||||||
},
|
},
|
||||||
'basic2': {
|
'basic2': {
|
||||||
'spread': 0,
|
'spread': 25,
|
||||||
'health': 50,
|
'health': 100,
|
||||||
'fullHealth': 50,
|
'fullHealth': 100,
|
||||||
'speedLow': 45,
|
'speedLow': 45,
|
||||||
'speedHigh': 55,
|
'speedHigh': 55,
|
||||||
'spriteStart': 0,
|
'spriteStart': 10,
|
||||||
'spriteSheet': 'basic-enemies',
|
'spriteSheet': 'basic-enemies',
|
||||||
'dropLow': 1,
|
'dropLow': 5,
|
||||||
'dropHigh': 2
|
'dropHigh': 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,282 @@
|
||||||
|
import { TOWERS_CONFIG } from './towerConfig.js';
|
||||||
|
|
||||||
|
export class InterfaceManager {
|
||||||
|
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.gold = 100;
|
||||||
|
this.cores = 20;
|
||||||
|
this.interfaceOpen = false;
|
||||||
|
|
||||||
|
this.paintInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
paintInterface() {
|
||||||
|
this.intTop = this.scene.add.image(1300, -50, 'intTop').setOrigin(0.5).setScrollFactor(0);
|
||||||
|
this.intCore = this.scene.add.sprite(1320, 60, 'towers', 9).setScale(.50).setOrigin(0.5).setScrollFactor(0).setAlpha(0);
|
||||||
|
|
||||||
|
// Add gold text display
|
||||||
|
this.goldText = this.scene.add.text(1200, 25, `${this.gold}`, {
|
||||||
|
fontFamily: 'neuropol, arial',
|
||||||
|
fontSize: '36px',
|
||||||
|
fill: '#ffd900ff',
|
||||||
|
stroke: '#c48f00ff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 5,
|
||||||
|
offsetY: 5,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 5,
|
||||||
|
stroke: false,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
}).setScrollFactor(0).setAlpha(0);
|
||||||
|
|
||||||
|
this.coreText = this.scene.add.text(1350, 25, `${this.cores}`, {
|
||||||
|
fontFamily: 'neuropol, arial',
|
||||||
|
fontSize: '36px',
|
||||||
|
fill: '#00eeffff',
|
||||||
|
stroke: '#2a338aff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 5,
|
||||||
|
offsetY: 5,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 5,
|
||||||
|
stroke: false,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
}).setScrollFactor(0).setAlpha(0);
|
||||||
|
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.intTop,
|
||||||
|
y: 50,
|
||||||
|
duration: 2000,
|
||||||
|
delay: 2000,
|
||||||
|
ease: 'Back.easeOut',
|
||||||
|
onComplete: () => {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: [this.coreText, this.goldText, this.intCore],
|
||||||
|
angle: 360,
|
||||||
|
alpha: 1,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.intCore,
|
||||||
|
angle: 360,
|
||||||
|
duration: 5000,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.intMain = this.scene.add.image(800, 1300, 'intMain').setOrigin(0.5).setScrollFactor(0);
|
||||||
|
// NOTE ^^ Fully up is at Y 475
|
||||||
|
|
||||||
|
// Add gold text display
|
||||||
|
this.interfaceText = this.scene.add.text(800, 850, `Click to Open`, {
|
||||||
|
fontFamily: 'neuropol, arial',
|
||||||
|
fontSize: '36px',
|
||||||
|
fill: '#ff5353ff',
|
||||||
|
stroke: '#581a1aff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 5,
|
||||||
|
offsetY: 5,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 5,
|
||||||
|
stroke: false,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
}).setOrigin(0.5).setScrollFactor(0).setAlpha(0);
|
||||||
|
|
||||||
|
this.upLeft = this.scene.add.image(650, 850, 'redArrow').setOrigin(0.5).setScale(0.25).setAlpha(0);
|
||||||
|
this.upRight = this.scene.add.image(950, 850, 'redArrow').setOrigin(0.5).setScale(0.25).setAlpha(0);
|
||||||
|
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.intMain,
|
||||||
|
y: 1150,
|
||||||
|
duration: 2000,
|
||||||
|
delay: 2000,
|
||||||
|
ease: 'Back.easeOut',
|
||||||
|
onComplete: () => {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: [this.interfaceText, this.upLeft, this.upRight],
|
||||||
|
alpha: 1,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: [this.upLeft, this.upRight],
|
||||||
|
y: { from: 860, to: 840},
|
||||||
|
duration: 2000,
|
||||||
|
repeat: -1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.interfaceUp = this.scene.add.rectangle(800, 840, 800, 120, 0x000000, 0).setOrigin(0.5);
|
||||||
|
this.interfaceUp.setInteractive();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openInterface() {
|
||||||
|
this.upLeft.setAlpha(0).setRotation(Math.PI);
|
||||||
|
this.upRight.setAlpha(0).setRotation(Math.PI);
|
||||||
|
this.interfaceText.setAlpha(0).setText('Click to Close');
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.intMain,
|
||||||
|
y: {from: 1150, to: 475},
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Quant',
|
||||||
|
onComplete: () => {
|
||||||
|
this.upLeft.setAlpha(1);
|
||||||
|
this.upRight.setAlpha(1);
|
||||||
|
this.interfaceText.setAlpha(1);
|
||||||
|
this.interfaceUp.setInteractive();
|
||||||
|
this.showTowers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeInterface() {
|
||||||
|
this.upLeft.setAlpha(0).setRotation(0);
|
||||||
|
this.upRight.setAlpha(0).setRotation(0);
|
||||||
|
this.interfaceText.setAlpha(0).setText('Click to Open');
|
||||||
|
this.towerDisplay.destroy();
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.intMain,
|
||||||
|
y: {from: 475, to: 1150},
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Quant',
|
||||||
|
onComplete: () => {
|
||||||
|
this.upLeft.setAlpha(1);
|
||||||
|
this.upRight.setAlpha(1);
|
||||||
|
this.interfaceText.setAlpha(1);
|
||||||
|
this.interfaceUp.setInteractive();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showTowers() {
|
||||||
|
this.towerDisplay = this.scene.add.container();
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
gridAdd(x, y, text, cost, type) {
|
||||||
|
const xAdd = 325;
|
||||||
|
const yAdd = 375;
|
||||||
|
const startX = (x * 225) + xAdd;
|
||||||
|
const startY = (y * 225) + yAdd;
|
||||||
|
|
||||||
|
const slot = this.scene.add.container();
|
||||||
|
slot.props = {
|
||||||
|
cost: cost
|
||||||
|
}
|
||||||
|
|
||||||
|
const slotBack = this.scene.add.rectangle(startX, startY, 200, 200, 0xAAAAAA, 0.5)
|
||||||
|
.setOrigin(0.5)
|
||||||
|
.setScrollFactor(0);
|
||||||
|
slot.add(slotBack);
|
||||||
|
slotBack.setInteractive();
|
||||||
|
|
||||||
|
// Add gold text display
|
||||||
|
const slotText = this.scene.add.text(startX-95, startY+75, `${text}`, {
|
||||||
|
fontFamily: 'neuropol, arial',
|
||||||
|
fontSize: '25px',
|
||||||
|
fill: '#ffffffff',
|
||||||
|
stroke: '#5f4719ff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 5,
|
||||||
|
stroke: false,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
}).setOrigin(0).setScrollFactor(0);
|
||||||
|
slot.add(slotText);
|
||||||
|
|
||||||
|
// Add gold text display
|
||||||
|
const slotCost = this.scene.add.text(startX+100, startY-100, `Gold: ${cost}`, {
|
||||||
|
fontFamily: 'neuropol, arial',
|
||||||
|
fontSize: '25px',
|
||||||
|
fill: '#ffd900ff',
|
||||||
|
stroke: '#c48f00ff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 5,
|
||||||
|
stroke: false,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
}).setOrigin(1, 0).setScrollFactor(0);
|
||||||
|
slot.add(slotCost);
|
||||||
|
|
||||||
|
const towerBase = this.scene.add.sprite(startX, startY, 'towers', 7)
|
||||||
|
.setOrigin(0.5)
|
||||||
|
.setScrollFactor(0);
|
||||||
|
slot.add(towerBase);
|
||||||
|
|
||||||
|
const towerTop = this.scene.add.sprite(startX, startY, 'towers', TOWERS_CONFIG[type].spriteStart)
|
||||||
|
.setOrigin(0.5)
|
||||||
|
.setScrollFactor(0);
|
||||||
|
slot.add(towerTop);
|
||||||
|
|
||||||
|
this.towerDisplay.add(slot);
|
||||||
|
this.updateTowerAvail();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTowerAvail() {
|
||||||
|
if (this.interfaceOpen === true && this.towerDisplay) {
|
||||||
|
this.towerDisplay.iterate((slot) => {
|
||||||
|
// Not Enough Gold
|
||||||
|
if (slot.props.cost > this.gold) {
|
||||||
|
slot.iterate((child) => {
|
||||||
|
if (child.type === 'Rectangle') {
|
||||||
|
child.disableInteractive();
|
||||||
|
child.setFillStyle(0x333333);
|
||||||
|
} else {
|
||||||
|
child.setTint(0x888888);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Is Enough Gold
|
||||||
|
else {
|
||||||
|
slot.iterate((child) => {
|
||||||
|
if (child.type === 'Rectangle') {
|
||||||
|
child.setInteractive();
|
||||||
|
child.setFillStyle(0xAAAAAA);
|
||||||
|
} else {
|
||||||
|
child.setTint(0xFFFFFF);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,15 +9,15 @@ export const TOWERS_CONFIG = {
|
||||||
'range': 275
|
'range': 275
|
||||||
},
|
},
|
||||||
'level2': {
|
'level2': {
|
||||||
'dmgLow': 12,
|
'dmgLow': 15,
|
||||||
'dmgHigh': 33,
|
'dmgHigh': 35,
|
||||||
'rate': 1500,
|
'rate': 1500,
|
||||||
'duration': 750,
|
'duration': 750,
|
||||||
'range': 300
|
'range': 300
|
||||||
},
|
},
|
||||||
'level3': {
|
'level3': {
|
||||||
'dmgLow': 15,
|
'dmgLow': 25,
|
||||||
'dmgHigh': 35,
|
'dmgHigh': 50,
|
||||||
'rate': 1000,
|
'rate': 1000,
|
||||||
'duration': 1000,
|
'duration': 1000,
|
||||||
'range': 325
|
'range': 325
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ export class TowerManager {
|
||||||
const posX = this.scene.gridToLocation(x);
|
const posX = this.scene.gridToLocation(x);
|
||||||
const posY = this.scene.gridToLocation(y);
|
const posY = this.scene.gridToLocation(y);
|
||||||
|
|
||||||
|
const towerBase = this.scene.add.sprite(posX, posY, 'towers', 7);
|
||||||
const tower = this.scene.add.sprite(posX, posY, 'towers', TOWERS_CONFIG[type].spriteStart);
|
const tower = this.scene.add.sprite(posX, posY, 'towers', TOWERS_CONFIG[type].spriteStart);
|
||||||
tower.props = {
|
tower.props = {
|
||||||
'type': type,
|
'type': type,
|
||||||
|
|
@ -25,7 +26,6 @@ export class TowerManager {
|
||||||
const uniqueId = Phaser.Math.Between(100000, 999999);
|
const uniqueId = Phaser.Math.Between(100000, 999999);
|
||||||
tower.id = uniqueId;
|
tower.id = uniqueId;
|
||||||
|
|
||||||
tower.setScale(1.5);
|
|
||||||
this.scene.towers.add(tower);
|
this.scene.towers.add(tower);
|
||||||
|
|
||||||
// Draw range circle
|
// Draw range circle
|
||||||
|
|
@ -44,8 +44,27 @@ export class TowerManager {
|
||||||
end: 1,
|
end: 1,
|
||||||
}),
|
}),
|
||||||
frameRate: 15,
|
frameRate: 15,
|
||||||
duration: 500,
|
repeat: 5,
|
||||||
repeat: 1,
|
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
|
yoyo: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +121,7 @@ export class TowerManager {
|
||||||
return current.props.distanceTraveled > max.props.distanceTraveled ? current : max;
|
return current.props.distanceTraveled > max.props.distanceTraveled ? current : max;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.followTarget(tower, furthestEnemy);
|
this.following[tower.id] = furthestEnemy.props.id;
|
||||||
this.attackTarget(tower, furthestEnemy);
|
this.attackTarget(tower, furthestEnemy);
|
||||||
|
|
||||||
this.lastFired[tower.id] = time;
|
this.lastFired[tower.id] = time;
|
||||||
|
|
@ -110,11 +129,6 @@ export class TowerManager {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
followTarget(tower, enemy) {
|
|
||||||
this.following[tower.id] = enemy.props.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
attackTarget(tower, enemy) {
|
attackTarget(tower, enemy) {
|
||||||
// Tower Properties
|
// Tower Properties
|
||||||
const type = tower.props.type;
|
const type = tower.props.type;
|
||||||
|
|
@ -126,8 +140,11 @@ export class TowerManager {
|
||||||
const dmgLow = config.dmgLow;
|
const dmgLow = config.dmgLow;
|
||||||
const dmgHigh = config.dmgHigh;
|
const dmgHigh = config.dmgHigh;
|
||||||
|
|
||||||
tower.play(`${type}-${level}-fire`, true);
|
const angle = Phaser.Math.Angle.Between(tower.x, tower.y, enemy.x, enemy.y);
|
||||||
|
tower.rotation = angle;
|
||||||
|
|
||||||
|
tower.play(`${type}-${level}-fire`, { duration: 500 });
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
|
|
@ -152,8 +169,8 @@ export class TowerManager {
|
||||||
// Create health bar container
|
// Create health bar container
|
||||||
const healthBar = this.scene.add.container(enemy.x, barY);
|
const healthBar = this.scene.add.container(enemy.x, barY);
|
||||||
|
|
||||||
// Background bar (gray)
|
// Background bar (red)
|
||||||
const background = this.scene.add.rectangle(0, 0, barWidth, barHeight, 0x808080);
|
const background = this.scene.add.rectangle(0, 0, barWidth, barHeight, 0xe83829);
|
||||||
|
|
||||||
// Health fill (green)
|
// Health fill (green)
|
||||||
const healthFill = this.scene.add.rectangle(0, 0, barWidth, barHeight, 0x00ff00);
|
const healthFill = this.scene.add.rectangle(0, 0, barWidth, barHeight, 0x00ff00);
|
||||||
|
|
@ -185,7 +202,43 @@ export class TowerManager {
|
||||||
const type = enemy.props.type;
|
const type = enemy.props.type;
|
||||||
const sprite = enemy.texture.key;
|
const sprite = enemy.texture.key;
|
||||||
const firstFrame = enemy.texture.firstFrame;
|
const firstFrame = enemy.texture.firstFrame;
|
||||||
const id = enemy.props.id;
|
const velocX = enemy.body.velocity.x;
|
||||||
|
const velocY = enemy.body.velocity.y;
|
||||||
|
|
||||||
|
// Add some Gold
|
||||||
|
const drop = Phaser.Math.Between(ENEMIES_CONFIG[type].dropLow, ENEMIES_CONFIG[type].dropHigh) * 5;
|
||||||
|
|
||||||
|
// Show the Gold
|
||||||
|
const cashDrop = this.scene.add.image(dieX, dieY, 'gold').setScale(0.5);
|
||||||
|
const angle = Phaser.Math.Angle.Between(tower.x, tower.y, dieX, dieY);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Animate the cash drop moving to the new position
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: cashDrop,
|
||||||
|
x: endX,
|
||||||
|
y: endY,
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Bounce',
|
||||||
|
onComplete: () => {
|
||||||
|
cashDrop.postFX.addGlow();
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: cashDrop,
|
||||||
|
x: 1300,
|
||||||
|
y: 100,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 500,
|
||||||
|
onComplete: () => {
|
||||||
|
cashDrop.destroy();
|
||||||
|
this.scene.UIScene.addGold(drop);
|
||||||
|
this.scene.UIScene.interfaceManager.updateTowerAvail();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
enemy.destroy();
|
enemy.destroy();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,13 @@ export const WAVE_CONFIG = {
|
||||||
},
|
},
|
||||||
2: {
|
2: {
|
||||||
begin: 15,
|
begin: 15,
|
||||||
basic1: 20
|
basic1: 5,
|
||||||
|
basic2: 2
|
||||||
},
|
},
|
||||||
3: {
|
3: {
|
||||||
begin: 30,
|
begin: 30,
|
||||||
basic1: 5
|
basic1: 4,
|
||||||
|
basic2: 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Wave
|
// Wave
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ export class WaveManager {
|
||||||
|
|
||||||
this.waveTimer = 0;
|
this.waveTimer = 0;
|
||||||
this.waveScheduleStartTime();
|
this.waveScheduleStartTime();
|
||||||
|
this.placeCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
waveScheduleStartTime() {
|
waveScheduleStartTime() {
|
||||||
|
|
@ -33,6 +34,28 @@ export class WaveManager {
|
||||||
this.waveScheduleStartTime();
|
this.waveScheduleStartTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
placeCore() {
|
||||||
|
this.scene.add.sprite(this.scene.gridToLocation(this.endX), this.scene.gridToLocation(this.endY), 'towers', 8);
|
||||||
|
const rotatingCore = this.scene.add.sprite(this.scene.gridToLocation(this.endX), this.scene.gridToLocation(this.endY), 'towers', 9);
|
||||||
|
const glowingCore = this.scene.add.sprite(this.scene.gridToLocation(this.endX), this.scene.gridToLocation(this.endY), 'towers', 19).setAlpha(0);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: rotatingCore,
|
||||||
|
duration: 5000,
|
||||||
|
angle: 360,
|
||||||
|
alpha: [0.5, 1, 0.5],
|
||||||
|
repeat: -1,
|
||||||
|
yoyo: false
|
||||||
|
});
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: glowingCore,
|
||||||
|
duration: 5000,
|
||||||
|
alpha: .4,
|
||||||
|
scale: 2,
|
||||||
|
repeat: -1,
|
||||||
|
yoyo: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
update(time, delta) {
|
update(time, delta) {
|
||||||
// Handle Enemy Pathing
|
// Handle Enemy Pathing
|
||||||
this.scene.enemies.children.iterate((enemy) => {
|
this.scene.enemies.children.iterate((enemy) => {
|
||||||
|
|
@ -149,6 +172,12 @@ export class WaveManager {
|
||||||
const enemy = new Enemies(this.scene, 'basic1', this.spawnX, this.spawnY, this.path);
|
const enemy = new Enemies(this.scene, 'basic1', this.spawnX, this.spawnY, this.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.scheduleInfo.hasOwnProperty('basic2')) {
|
||||||
|
console.log('Spawn',this.scheduleInfo.basic2,'Basic2 enemies');
|
||||||
|
for (let e = 0; e < this.scheduleInfo.basic2; e++) {
|
||||||
|
const enemy = new Enemies(this.scene, 'basic2', this.spawnX, this.spawnY, this.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makePath() {
|
makePath() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { InterfaceManager } from './support/interfaceManager.js';
|
||||||
|
|
||||||
|
export class UIScene extends Phaser.Scene {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'UIScene' });
|
||||||
|
}
|
||||||
|
|
||||||
|
init(data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
this.load.font('neuropol', 'assets/NEUROPOL.ttf');
|
||||||
|
this.load.image('intMain', 'assets/intMain.png');
|
||||||
|
this.load.image('redArrow', 'assets/redArrow.png');
|
||||||
|
this.load.image('intTop', 'assets/intTop.png');
|
||||||
|
this.load.image('gold', 'assets/gold.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
this.interfaceManager = new InterfaceManager(this);
|
||||||
|
this.levelScene = this.scene.get('Level');
|
||||||
|
this.cameras.main.setBounds(0, 0, 1600, 900);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
this.interfaceManager.update(time, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
addGold(amount) {
|
||||||
|
this.interfaceManager.gold += amount;
|
||||||
|
this.updateGold();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGold() {
|
||||||
|
this.interfaceManager.goldText.setText(`${this.interfaceManager.gold}`);
|
||||||
|
}
|
||||||
|
}
|
||||||