enemies can be killed and they give money upon death. towers shoot properly

This commit is contained in:
koneko 2025-01-08 00:51:10 +01:00
parent 95332a6dcc
commit 8ebb75fd1a
8 changed files with 84 additions and 22 deletions

View File

@ -6,7 +6,7 @@
"description": "The building block of society, nothing more basic exists.",
"stats": {
"damage": 2,
"cooldown": 120,
"cooldown": 60,
"gemSlotsAmount": 2,
"cost": 100,
"range": 3

View File

@ -23,5 +23,13 @@ export default abstract class GameObject {
return this._events;
}
public copyContainerToBB() {
this.bb.x = this.container.x;
this.bb.y = this.container.y;
this.bb.width = this.container.width;
this.bb.height = this.container.height;
return this.bb;
}
public abstract update(elapsedMS): void;
}

View File

@ -13,6 +13,7 @@ export enum CreepEvents {
}
export default class Creep extends GameObject {
public id: number;
public creepType: CreepType;
private sprite: PIXI.Sprite;
private path: PathDefinition;
@ -25,14 +26,15 @@ export default class Creep extends GameObject {
public died: boolean = false;
public x: number;
public y: number;
constructor(creepType: CreepType, path: PathDefinition) {
public dead: boolean = false;
constructor(creepType: CreepType, path: PathDefinition, id) {
super();
this.creepType = creepType;
this.stats = structuredClone(Assets.CreepStats[this.creepType]);
this.sprite = new PIXI.Sprite({
texture: GameAssets.BasicCreepTexture,
});
this.container.label = 'creep-' + creepType.toString();
this.id = id;
// because wave manager spawns all instantly and i dont want
// it to look like a shit game (they all spawn in top left corner)
// i want to hide minion - mario
@ -46,10 +48,21 @@ export default class Creep extends GameObject {
this.path = path;
this.x = path[0][1] * 64 + 32; // centered
this.y = path[0][0] * 64 + 32;
Globals.GameScene.events.on(CreepEvents.TakenDamage, (creepID, damage) => {
if (creepID != this.id) return;
this.health -= damage;
});
Globals.Grid.container.addChild(this.container);
this.container.addChild(this.sprite);
}
public update(elapsedMS: number) {
if (this.dead) return;
if (this.health <= 0) {
Globals.GameScene.events.emit(CreepEvents.Died, this.maxHealth, this);
this.destroy();
this.dead = true;
return;
}
if (this.pathIndex + 1 == this.path.length) {
if (this.escaped) return;
this.events.emit(CreepEvents.Escaped, this);

View File

@ -141,7 +141,10 @@ export class Grid extends GameObject {
}
public update(elapsedMS) {
this.creeps.forEach((creep) => {
creep.update(elapsedMS);
if (creep.dead) {
this.creeps.splice(this.creeps.indexOf(creep), 1);
creep = null;
} else creep.update(elapsedMS);
});
}
public getCellByRowAndCol(row, column) {

View File

@ -1,6 +1,7 @@
import * as PIXI from 'pixi.js';
import GameObject from '../GameObject';
import { Globals } from '../Bastion';
import Creep, { CreepEvents } from './Creep';
export function calculateAngleToPoint(x, y, targetX, targetY) {
const dx = targetX - x;
@ -9,15 +10,20 @@ export function calculateAngleToPoint(x, y, targetX, targetY) {
}
export default class Projectile extends GameObject {
public deleteMe: boolean = false;
public sprite: PIXI.Sprite;
public x: number;
public y: number;
public angle: number;
public speed: number;
constructor(x, y, spriteTexture, angle) {
public damage: number;
public timeToLive: number = 1;
constructor(x, y, spriteTexture, angle, damage) {
super();
console.log('I SHOOTTED!');
this.x = x;
this.y = y;
this.damage = damage;
this.sprite = new PIXI.Sprite({ texture: spriteTexture, scale: 0.5, rotation: angle });
this.sprite.anchor.set(0.5);
@ -27,12 +33,24 @@ export default class Projectile extends GameObject {
Globals.app.stage.addChild(this.container);
this.angle = angle;
this.speed = 0.9;
}
public destroy(): void {
super.destroy();
this.deleteMe = true;
}
public update(elapsedMS) {
if (this.x > 2000 || this.x < 0 || this.y > 2000 || this.y < 0) return this.destroy();
if (this.deleteMe) return;
if (this.x > 2000 || this.x < 0 || this.y > 2000 || this.y < 0 || this.timeToLive <= 0) return this.destroy();
Globals.Grid.creeps.forEach((creep) => {
if (this.timeToLive <= 0) return;
if (creep.container && this.checkCollision(creep)) {
this.timeToLive--;
this.onCollide(creep);
return;
}
});
this.x += Math.cos(this.angle) * this.speed * elapsedMS;
this.y += Math.sin(this.angle) * this.speed * elapsedMS;
@ -40,18 +58,22 @@ export default class Projectile extends GameObject {
this.container.y = this.y;
}
public onCollide(otherSprite) {
console.log(`Collision detected with`, otherSprite);
public onCollide(creep) {
console.log('COLLIDED WITH' + creep);
Globals.GameScene.events.emit(CreepEvents.TakenDamage, creep.id, this.damage);
}
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
);
public checkCollision(creep: Creep) {
if (creep == null) return;
let mybb = this.copyContainerToBB();
let otherbb = creep.copyContainerToBB();
return mybb.getBounds().intersects(otherbb.getBounds());
// console.log(boundsA, boundsB);
// 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

@ -38,6 +38,7 @@ export class Tower extends GameObject {
private behaviour: string;
private definition: TowerDefinition;
private sprite: PIXI.Sprite;
private ticksUntilNextShot: number;
private graphics: PIXI.Graphics = new PIXI.Graphics();
constructor(row, column, texture, definition, behaviour) {
super();
@ -45,6 +46,7 @@ export class Tower extends GameObject {
this.column = column;
this.behaviour = behaviour;
this.definition = definition;
this.ticksUntilNextShot = 0;
let parent: Cell = Globals.Grid.getCellByRowAndCol(row, column);
this.sprite = new PIXI.Sprite({
texture: texture,
@ -79,18 +81,27 @@ export class Tower extends GameObject {
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));
this.projectiles.push(
new Projectile(x, y, GameAssets.BasicProjectileTexture, angle, this.definition.stats.damage)
);
}
public update(elapsedMS: any): void {
this.projectiles.forEach((proj) => {
proj.update(elapsedMS);
if (proj.deleteMe) {
this.projectiles.splice(this.projectiles.indexOf(proj), 1);
proj = null;
} else proj.update(elapsedMS);
});
if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) {
if (this.ticksUntilNextShot > 0) this.ticksUntilNextShot--;
let creepsInRange = this.GetCreepsInRange();
if (creepsInRange.length > 0) {
let focus = creepsInRange[0];
if (this.ticksUntilNextShot == 0) {
this.ticksUntilNextShot = this.definition.stats.cooldown;
this.Shoot(focus);
}
}
}
}
}

View File

@ -23,6 +23,7 @@ export default class WaveManager {
private started: boolean = false;
public finished: boolean = false;
public events = new PIXI.EventEmitter();
private internalCreepId: number = 0;
constructor(rounds: MissionRoundDefinition[], paths: PathDefinition[]) {
Globals.WaveManager = this;
this.rounds = rounds;
@ -37,7 +38,8 @@ export default class WaveManager {
this.rounds[roundIndex].waves.forEach((wave) => {
tickToSpawnAt += wave.firstCreepSpawnTick;
wave.creeps.forEach((creep) => {
const creepObj = new Creep(creep, this.paths[0]);
const creepObj = new Creep(creep, this.paths[0], this.internalCreepId);
this.internalCreepId++;
const creepInstance = {
creep: creepObj,
tickToSpawnAt,

View File

@ -58,6 +58,9 @@ export class GameScene extends Scene {
this.onCreepEscaped(creep);
});
});
this.events.on(CreepEvents.Died, (playerAward, creepThatDied) => {
this.MissionStats.earnGold(playerAward);
});
this.sidebar = new Sidebar(SidebarRect);
this.changeRoundButton = new Button(changeRoundButtonRect, 'Start', ButtonTexture.Button01, true);
this.changeRoundButton.container.removeFromParent();