towers can shoooot

This commit is contained in:
koneko 2025-01-05 00:07:21 +01:00
parent 6fd91b6e73
commit 87e5a7a71a
8 changed files with 108 additions and 29 deletions

View File

@ -1,11 +1,12 @@
[ [
{ {
"name": "Basic Tower", "name": "Basic Tower",
"behaviour": "BasicTowerBehaviour",
"sprite": "basic_tower", "sprite": "basic_tower",
"description": "The building block of society, nothing more basic exists.", "description": "The building block of society, nothing more basic exists.",
"stats": { "stats": {
"damage": 2, "damage": 2,
"cooldown": 2, "cooldown": 120,
"gemSlotsAmount": 2, "gemSlotsAmount": 2,
"cost": 100, "cost": 100,
"range": 3 "range": 3

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -58,6 +58,10 @@ export default class GameAssets {
src: '/assets/towers/basic_tower.png', src: '/assets/towers/basic_tower.png',
}); });
GameAssets.BasicProjectileTexture = await PIXI.Assets.load({
src: '/assets/projectiles/basic_tower.png',
});
await this.LoadMissions(); await this.LoadMissions();
await this.LoadTowers(); await this.LoadTowers();
await this.LoadCreepStats(); await this.LoadCreepStats();
@ -106,6 +110,8 @@ export default class GameAssets {
public static BasicTowerTexture: PIXI.Texture; public static BasicTowerTexture: PIXI.Texture;
public static BasicProjectileTexture: PIXI.Texture;
public static Frame01Texture: PIXI.Texture; public static Frame01Texture: PIXI.Texture;
public static Frame02Texture: PIXI.Texture; public static Frame02Texture: PIXI.Texture;
public static FrameBackground: PIXI.Texture; public static FrameBackground: PIXI.Texture;

View File

@ -45,6 +45,7 @@ export type CreepResistancesDefinition = {
export type TowerDefinition = { export type TowerDefinition = {
name: string; name: string;
behaviour: string;
sprite: string; sprite: string;
description: string; description: string;
stats: TowerStatsDefinition; stats: TowerStatsDefinition;

View File

@ -22,7 +22,7 @@ export default class Creep extends GameObject {
public maxHealth: number; public maxHealth: number;
public escaped: boolean = false; public escaped: boolean = false;
public died: 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; public y: number;
constructor(creepType: CreepType, path: PathDefinition) { constructor(creepType: CreepType, path: PathDefinition) {
super(); super();

View File

@ -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
);
}
}

View File

@ -3,6 +3,10 @@ import * as PIXI from 'pixi.js';
import GameObject from '../GameObject'; import GameObject from '../GameObject';
import { TowerDefinition } from '../Definitions'; import { TowerDefinition } from '../Definitions';
import { Cell } from './Grid'; 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) { function distance(x1, y1, x2, y2) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
@ -30,15 +34,16 @@ export enum TowerEvents {
export class Tower extends GameObject { export class Tower extends GameObject {
public row: number; public row: number;
public column: number; public column: number;
private projectiles: Projectile[] = [];
private behaviour: string;
private definition: TowerDefinition; private definition: TowerDefinition;
private sprite: PIXI.Sprite; private sprite: PIXI.Sprite;
private antiLag = 0; private graphics: PIXI.Graphics = new PIXI.Graphics();
private debugGraphics: PIXI.Graphics = new PIXI.Graphics(); constructor(row, column, texture, definition, behaviour) {
private dbgtxt: any;
constructor(row, column, texture, definition) {
super(); super();
this.row = row; this.row = row;
this.column = column; this.column = column;
this.behaviour = behaviour;
this.definition = definition; this.definition = definition;
let parent: Cell = Globals.Grid.getCellByRowAndCol(row, column); let parent: Cell = Globals.Grid.getCellByRowAndCol(row, column);
this.sprite = new PIXI.Sprite({ this.sprite = new PIXI.Sprite({
@ -47,25 +52,16 @@ export class Tower extends GameObject {
width: 64, width: 64,
zIndex: 10, 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.sprite);
this.container.addChild(this.dbgtxt);
parent.container.addChild(this.container); parent.container.addChild(this.container);
parent.clickDetector.onmouseenter = (e) => { parent.clickDetector.onmouseenter = (e) => {
this.debugGraphics.circle(this.column * 64 + 32, this.row * 64 + 32, this.definition.stats.range * 64); this.graphics.circle(this.column * 64 + 32, this.row * 64 + 32, this.definition.stats.range * 64);
this.debugGraphics.fill({ color: 0xff0000, alpha: 0.5 }); this.graphics.fill({ color: 0xff0000, alpha: 0.5 });
}; };
parent.clickDetector.onmouseleave = (e) => { parent.clickDetector.onmouseleave = (e) => {
this.debugGraphics.clear(); this.graphics.clear();
}; };
Globals.app.stage.addChild(this.debugGraphics); Globals.app.stage.addChild(this.graphics);
} }
public GetCreepsInRange() { public GetCreepsInRange() {
let creeps = Globals.Grid.creeps; let creeps = Globals.Grid.creeps;
@ -79,12 +75,22 @@ export class Tower extends GameObject {
return d < radius; 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 { public update(elapsedMS: any): void {
if (this.antiLag >= 10) { this.projectiles.forEach((proj) => {
this.antiLag = 0; proj.update(elapsedMS);
let inrange = this.GetCreepsInRange().length; });
this.dbgtxt.text = inrange; if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) {
let creepsInRange = this.GetCreepsInRange();
if (creepsInRange.length > 0) {
let focus = creepsInRange[0];
this.Shoot(focus);
}
} }
this.antiLag++;
} }
} }

View File

@ -1,10 +1,14 @@
import * as PIXI from 'pixi.js'; import * as PIXI from 'pixi.js';
import { Globals } from '../Bastion'; import { Globals } from '../Bastion';
import { TowerDefinition } from '../Definitions'; import { TerrainType, TowerDefinition } from '../Definitions';
import GameAssets from '../Assets'; import GameAssets from '../Assets';
import GameObject from '../GameObject'; import GameObject from '../GameObject';
import { Tower, TowerEvents } from './Tower'; import { Tower, TowerEvents } from './Tower';
export enum TowerBehaviours {
BasicTowerBehaviour = 'BasicTowerBehaviour',
}
export default class TowerManager { export default class TowerManager {
public isPlacingTower: boolean = false; public isPlacingTower: boolean = false;
public canPlaceTowers: boolean = true; public canPlaceTowers: boolean = true;
@ -32,7 +36,7 @@ export default class TowerManager {
if (this.isPlacingTower) { if (this.isPlacingTower) {
if (!this.selectedTower) if (!this.selectedTower)
throw console.warn('TowerManager.selectedTower is null when trying to place tower.'); 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) { public GetTowerByRowAndCol(row, col) {
@ -44,7 +48,7 @@ export default class TowerManager {
}); });
return returnTower; return returnTower;
} }
public PlaceTower(definition: TowerDefinition, row, column, ignoreCost?) { public PlaceTower(definition: TowerDefinition, row, column, behaviour: string, ignoreCost?) {
let idx = 0; let idx = 0;
GameAssets.Towers.forEach((item, index) => { GameAssets.Towers.forEach((item, index) => {
if (item.sprite == definition.sprite) idx = index; if (item.sprite == definition.sprite) idx = index;
@ -52,9 +56,13 @@ export default class TowerManager {
const sprite = GameAssets.TowerSprites[idx]; const sprite = GameAssets.TowerSprites[idx];
if (!Globals.GameScene.MissionStats.hasEnoughGold(definition.stats.cost) && !ignoreCost) if (!Globals.GameScene.MissionStats.hasEnoughGold(definition.stats.cost) && !ignoreCost)
return console.warn('Does not have enough gold.'); 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); 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.towers.push(tower);
this.ToggleChoosingTowerLocation('RESET'); this.ToggleChoosingTowerLocation('RESET');
console.log('SHOULDVE PLACED TOWER'); console.log('SHOULDVE PLACED TOWER');