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",
"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

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',
});
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;

View File

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

View File

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

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 { 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++;
}
}

View File

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