diff --git a/public/assets/Towers.json b/public/assets/Towers.json index 853ad1c..44b34c0 100644 --- a/public/assets/Towers.json +++ b/public/assets/Towers.json @@ -1,11 +1,12 @@ [ { "name": "Basic Tower", + "behaviour": "BasicTowerBehaviour", "sprite": "basic_tower", "description": "The building block of society, nothing more basic exists.", "stats": { "damage": 2, - "cooldown": 2, + "cooldown": 120, "gemSlotsAmount": 2, "cost": 100, "range": 3 diff --git a/public/assets/projectiles/basic_tower.png b/public/assets/projectiles/basic_tower.png new file mode 100644 index 0000000..272ad51 Binary files /dev/null and b/public/assets/projectiles/basic_tower.png differ diff --git a/src/classes/Assets.ts b/src/classes/Assets.ts index 848a00a..0bb3833 100644 --- a/src/classes/Assets.ts +++ b/src/classes/Assets.ts @@ -58,6 +58,10 @@ export default class GameAssets { src: '/assets/towers/basic_tower.png', }); + GameAssets.BasicProjectileTexture = await PIXI.Assets.load({ + src: '/assets/projectiles/basic_tower.png', + }); + await this.LoadMissions(); await this.LoadTowers(); await this.LoadCreepStats(); @@ -106,6 +110,8 @@ export default class GameAssets { public static BasicTowerTexture: PIXI.Texture; + public static BasicProjectileTexture: PIXI.Texture; + public static Frame01Texture: PIXI.Texture; public static Frame02Texture: PIXI.Texture; public static FrameBackground: PIXI.Texture; diff --git a/src/classes/Definitions.ts b/src/classes/Definitions.ts index a21cce9..a1328cf 100644 --- a/src/classes/Definitions.ts +++ b/src/classes/Definitions.ts @@ -45,6 +45,7 @@ export type CreepResistancesDefinition = { export type TowerDefinition = { name: string; + behaviour: string; sprite: string; description: string; stats: TowerStatsDefinition; diff --git a/src/classes/game/Creep.ts b/src/classes/game/Creep.ts index 87fb157..abda72b 100644 --- a/src/classes/game/Creep.ts +++ b/src/classes/game/Creep.ts @@ -22,7 +22,7 @@ export default class Creep extends GameObject { public maxHealth: number; public escaped: boolean = false; public died: boolean = false; - public x: number; // X and Y are local to the grid, not canvas + public x: number; public y: number; constructor(creepType: CreepType, path: PathDefinition) { super(); diff --git a/src/classes/game/Projectile.ts b/src/classes/game/Projectile.ts new file mode 100644 index 0000000..a0186eb --- /dev/null +++ b/src/classes/game/Projectile.ts @@ -0,0 +1,57 @@ +import * as PIXI from 'pixi.js'; +import GameObject from '../GameObject'; +import { Globals } from '../Bastion'; + +export function calculateAngleToPoint(x, y, targetX, targetY) { + const dx = targetX - x; + const dy = targetY - y; + return Math.atan2(dy, dx); +} + +export default class Projectile extends GameObject { + public sprite: PIXI.Sprite; + public x: number; + public y: number; + public angle: number; + public speed: number; + constructor(x, y, spriteTexture, angle) { + super(); + this.x = x; + this.y = y; + + this.sprite = new PIXI.Sprite({ texture: spriteTexture, scale: 0.5, rotation: angle }); + this.sprite.anchor.set(0.5); + this.container.x = this.x; + this.container.y = this.y; + this.container.addChild(this.sprite); + Globals.app.stage.addChild(this.container); + + this.angle = angle; + + this.speed = 0.9; + } + + public update(elapsedMS) { + if (this.x > 2000 || this.x < 0 || this.y > 2000 || this.y < 0) return this.destroy(); + this.x += Math.cos(this.angle) * this.speed * elapsedMS; + this.y += Math.sin(this.angle) * this.speed * elapsedMS; + + this.container.x = this.x; + this.container.y = this.y; + } + + public onCollide(otherSprite) { + console.log(`Collision detected with`, otherSprite); + } + + public checkCollision(otherSprite) { + const boundsA = this.sprite.getBounds(); + const boundsB = otherSprite.getBounds(); + return ( + boundsA.x < boundsB.x + boundsB.width && + boundsA.x + boundsA.width > boundsB.x && + boundsA.y < boundsB.y + boundsB.height && + boundsA.y + boundsA.height > boundsB.y + ); + } +} diff --git a/src/classes/game/Tower.ts b/src/classes/game/Tower.ts index 840a9aa..de989bd 100644 --- a/src/classes/game/Tower.ts +++ b/src/classes/game/Tower.ts @@ -3,6 +3,10 @@ import * as PIXI from 'pixi.js'; import GameObject from '../GameObject'; import { TowerDefinition } from '../Definitions'; import { Cell } from './Grid'; +import { TowerBehaviours } from './TowerManager'; +import Projectile, { calculateAngleToPoint } from './Projectile'; +import GameAssets from '../Assets'; +import Creep from './Creep'; function distance(x1, y1, x2, y2) { return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); @@ -30,15 +34,16 @@ export enum TowerEvents { export class Tower extends GameObject { public row: number; public column: number; + private projectiles: Projectile[] = []; + private behaviour: string; private definition: TowerDefinition; private sprite: PIXI.Sprite; - private antiLag = 0; - private debugGraphics: PIXI.Graphics = new PIXI.Graphics(); - private dbgtxt: any; - constructor(row, column, texture, definition) { + private graphics: PIXI.Graphics = new PIXI.Graphics(); + constructor(row, column, texture, definition, behaviour) { super(); this.row = row; this.column = column; + this.behaviour = behaviour; this.definition = definition; let parent: Cell = Globals.Grid.getCellByRowAndCol(row, column); this.sprite = new PIXI.Sprite({ @@ -47,25 +52,16 @@ export class Tower extends GameObject { width: 64, zIndex: 10, }); - this.dbgtxt = new PIXI.Text({ - text: 'instantiating', - x: 0, - y: -20, - style: { - fill: 0x0ff00f, - }, - }); this.container.addChild(this.sprite); - this.container.addChild(this.dbgtxt); parent.container.addChild(this.container); parent.clickDetector.onmouseenter = (e) => { - this.debugGraphics.circle(this.column * 64 + 32, this.row * 64 + 32, this.definition.stats.range * 64); - this.debugGraphics.fill({ color: 0xff0000, alpha: 0.5 }); + this.graphics.circle(this.column * 64 + 32, this.row * 64 + 32, this.definition.stats.range * 64); + this.graphics.fill({ color: 0xff0000, alpha: 0.5 }); }; parent.clickDetector.onmouseleave = (e) => { - this.debugGraphics.clear(); + this.graphics.clear(); }; - Globals.app.stage.addChild(this.debugGraphics); + Globals.app.stage.addChild(this.graphics); } public GetCreepsInRange() { let creeps = Globals.Grid.creeps; @@ -79,12 +75,22 @@ export class Tower extends GameObject { return d < radius; }); } + public Shoot(creep: Creep) { + let x = this.column * 64 + 32; + let y = this.row * 64 + 32; + let angle = calculateAngleToPoint(x, y, creep.x, creep.y); + this.projectiles.push(new Projectile(x, y, GameAssets.BasicProjectileTexture, angle)); + } public update(elapsedMS: any): void { - if (this.antiLag >= 10) { - this.antiLag = 0; - let inrange = this.GetCreepsInRange().length; - this.dbgtxt.text = inrange; + this.projectiles.forEach((proj) => { + proj.update(elapsedMS); + }); + if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) { + let creepsInRange = this.GetCreepsInRange(); + if (creepsInRange.length > 0) { + let focus = creepsInRange[0]; + this.Shoot(focus); + } } - this.antiLag++; } } diff --git a/src/classes/game/TowerManager.ts b/src/classes/game/TowerManager.ts index 0e39940..736e782 100644 --- a/src/classes/game/TowerManager.ts +++ b/src/classes/game/TowerManager.ts @@ -1,10 +1,14 @@ import * as PIXI from 'pixi.js'; import { Globals } from '../Bastion'; -import { TowerDefinition } from '../Definitions'; +import { TerrainType, TowerDefinition } from '../Definitions'; import GameAssets from '../Assets'; import GameObject from '../GameObject'; import { Tower, TowerEvents } from './Tower'; +export enum TowerBehaviours { + BasicTowerBehaviour = 'BasicTowerBehaviour', +} + export default class TowerManager { public isPlacingTower: boolean = false; public canPlaceTowers: boolean = true; @@ -32,7 +36,7 @@ export default class TowerManager { if (this.isPlacingTower) { if (!this.selectedTower) throw console.warn('TowerManager.selectedTower is null when trying to place tower.'); - this.PlaceTower(this.selectedTower, row, column); + this.PlaceTower(this.selectedTower, row, column, this.selectedTower.behaviour); } } public GetTowerByRowAndCol(row, col) { @@ -44,7 +48,7 @@ export default class TowerManager { }); return returnTower; } - public PlaceTower(definition: TowerDefinition, row, column, ignoreCost?) { + public PlaceTower(definition: TowerDefinition, row, column, behaviour: string, ignoreCost?) { let idx = 0; GameAssets.Towers.forEach((item, index) => { if (item.sprite == definition.sprite) idx = index; @@ -52,9 +56,13 @@ export default class TowerManager { const sprite = GameAssets.TowerSprites[idx]; if (!Globals.GameScene.MissionStats.hasEnoughGold(definition.stats.cost) && !ignoreCost) return console.warn('Does not have enough gold.'); - if (!this.GetTowerByRowAndCol(row, column) && !Globals.Grid.getCellByRowAndCol(row, column).isPath) { + if ( + !this.GetTowerByRowAndCol(row, column) && + Globals.Grid.getCellByRowAndCol(row, column).type != TerrainType.Path && + Globals.Grid.getCellByRowAndCol(row, column).type != TerrainType.Restricted + ) { Globals.GameScene.MissionStats.spendGold(definition.stats.cost); - let tower = new Tower(row, column, sprite, definition); + let tower = new Tower(row, column, sprite, definition, behaviour); this.towers.push(tower); this.ToggleChoosingTowerLocation('RESET'); console.log('SHOULDVE PLACED TOWER');