strong and debuff tower basic implementation

This commit is contained in:
koneko 2025-02-18 23:59:19 +01:00
parent 1c3c9b287f
commit a632da412c
6 changed files with 97 additions and 23 deletions

View File

@ -91,7 +91,7 @@
"cost": 125,
"range": 2.5,
"timeToLive": 12,
"pierce": 30
"pierce": 1
}
},
{

View File

@ -7,6 +7,7 @@ export enum WaveManagerEvents {
export enum CreepEvents {
Died = 'died',
TakenDamage = 'takenDamage',
GiveEffect = 'giveEffect',
Escaped = 'escaped',
Moved = 'moved',
}

View File

@ -1,4 +1,3 @@
import GameAssets from '../Assets';
import Assets from '../Assets';
import { Engine } from '../Bastion';
import { CreepResistancesDefinition, CreepStatsDefinition, CreepType, PathDefinition } from '../Definitions';
@ -6,6 +5,21 @@ import GameObject from '../GameObject';
import * as PIXI from 'pixi.js';
import { CreepEvents } from '../Events';
export enum CreepEffects {
MovingBackwards = 'MovingBackwards',
DebuffTowerDebuff = 'DebuffTowerDebuff',
}
class Effect {
public effectEnum: CreepEffects;
public durationInMS: number;
public ticks: number = 0;
constructor(effectEnum: CreepEffects, durationInMS: number) {
this.effectEnum = effectEnum;
this.durationInMS = durationInMS;
}
}
export default class Creep extends GameObject {
public id: number;
public creepType: CreepType;
@ -17,6 +31,7 @@ export default class Creep extends GameObject {
private direction: number = 1;
private healthBarGraphics: PIXI.Graphics = new PIXI.Graphics();
private healthBarWidth = 50;
private effects: Effect[] = [];
public health: number;
public maxHealth: number;
public escaped: boolean = false;
@ -56,7 +71,10 @@ export default class Creep extends GameObject {
CreepEvents.TakenDamage,
(creepID, damage, gemResistanceModifications: CreepResistancesDefinition) => {
if (creepID != this.id) return;
if (this.effects.find((e) => e.effectEnum == CreepEffects.DebuffTowerDebuff)) {
damage = damage * 1.5;
console.log('multiplying damage, ' + damage);
}
// Apply resistances.
this.health -= damage + damage * (gemResistanceModifications.physical - this.stats.resistance.physical);
if (gemResistanceModifications.fire != 0)
@ -76,23 +94,49 @@ export default class Creep extends GameObject {
this.UpdateHealthbar();
}
);
Engine.GameScene.events.on(
CreepEvents.GiveEffect,
(creepID: number, effect: CreepEffects, durationInMS: number) => {
if (creepID != this.id) return;
console.log(' I CAUGHT THE EVENT!');
if (this.effects.find((e) => e.effectEnum == effect) == undefined)
this.effects.push(new Effect(effect, durationInMS));
}
);
Engine.Grid.container.addChild(this.container);
this.container.addChild(this.healthBarGraphics);
this.container.addChild(this.sprite);
this.UpdateHealthbar();
}
// Used ChatGPT to make this easier to understand.
private UpdateHealthbar() {
this.healthBarGraphics.clear();
const hp = this.health;
const maxHp = this.maxHealth;
const percent = hp / maxHp;
const width = this.healthBarWidth * percent;
// ! TODO: MAKE THIS BETTER! It works like this now, but I don't like how its implemented.
this.healthBarGraphics.rect(-this.healthBarWidth / 2 + 3, -32, this.healthBarWidth + 4, 14);
const percent = Math.max(0, hp / maxHp);
const barWidth = this.healthBarWidth;
const barHeight = 10; // Height of the health bar
const borderPadding = 2; // Border thickness around the health bar
const offsetX = -barWidth / 2; // Centering the bar
const offsetY = -32; // Position above the entity
// Border
this.healthBarGraphics.rect(
offsetX - borderPadding,
offsetY - borderPadding,
barWidth + borderPadding * 2,
barHeight + borderPadding * 2
);
this.healthBarGraphics.fill({ color: 0x000000 });
this.healthBarGraphics.rect(-this.healthBarWidth / 2 + 5, -30, width, 10);
// Health
const healthWidth = barWidth * percent;
this.healthBarGraphics.rect(offsetX, offsetY, healthWidth, barHeight);
this.healthBarGraphics.fill({ color: 0xff0000 });
}
public update(elapsedMS: number) {
if (this.dead) return;
if (this.health <= 0) {
@ -110,14 +154,30 @@ export default class Creep extends GameObject {
this.escaped = true;
return;
}
const currentCell = this.path[this.pathIndex];
const targetCell = this.path[this.pathIndex + 1];
const previousCell = this.pathIndex - 1 != 0 ? this.path[this.pathIndex - 1] : this.path[0];
let isMovingBackwards = false;
for (let i = this.effects.length - 1; i >= 0; i--) {
let effect = this.effects[i];
effect.ticks += elapsedMS * Engine.GameScene.gameSpeedMultiplier;
if (effect.ticks >= effect.durationInMS) this.effects.splice(i, 1);
else if (effect.effectEnum == CreepEffects.MovingBackwards) return (isMovingBackwards = true);
}
// Added + 32 for centering.
const targetX = targetCell[0] * Engine.GridCellSize + Engine.GridCellSize / 2;
const targetY = targetCell[1] * Engine.GridCellSize + Engine.GridCellSize / 2;
const directionX = targetCell[0] - currentCell[0];
const directionY = targetCell[1] - currentCell[1];
let targetX, targetY, directionX, directionY;
if (!isMovingBackwards) {
targetX = targetCell[0] * Engine.GridCellSize + Engine.GridCellSize / 2;
targetY = targetCell[1] * Engine.GridCellSize + Engine.GridCellSize / 2;
directionX = targetCell[0] - currentCell[0];
directionY = targetCell[1] - currentCell[1];
} else {
targetX = previousCell[0] * Engine.GridCellSize + Engine.GridCellSize / 2;
targetY = previousCell[1] * Engine.GridCellSize + Engine.GridCellSize / 2;
directionX = currentCell[0] - previousCell[0];
directionY = previousCell[1] - currentCell[1];
}
if (directionX > 0) {
// Going right
if (this.direction != 1) {
@ -157,7 +217,9 @@ export default class Creep extends GameObject {
}
this.x += deltaX;
this.y += deltaY;
if (increaseIndex) this.pathIndex++;
if (increaseIndex) {
if (!isMovingBackwards) this.pathIndex++;
}
this.container.x = this.x;
this.container.y = this.y;
}

View File

@ -143,6 +143,7 @@ export class RailProjectile extends Projectile {
newVisual.anchor.set(0.5, 0.5);
this.visuals.push(newVisual);
this.visuals.forEach((visual) => {
if (visual.scale == null) return visual.destroy();
if (visual.width && visual.height && visual.alpha) {
visual.width -= 4;
visual.height -= 4;

View File

@ -2,7 +2,7 @@ import GameAssets from '../Assets';
import { Engine } from '../Bastion';
import { TowerType } from '../Definitions';
import { CreepEvents } from '../Events';
import Creep from './Creep';
import Creep, { CreepEffects } from './Creep';
import Projectile, { calculateAngleToPoint, VisualLightning } from './Projectile';
import { distance, Tower } from './Tower';
import * as PIXI from 'pixi.js';
@ -16,17 +16,21 @@ import * as PIXI from 'pixi.js';
* @param elapsedMS - The elapsed time in milliseconds since the last update.
*/
function projectileCheck(tower: Tower, elapsedMS: number) {
tower.projectiles.forEach((proj) => {
for (let i = tower.projectiles.length - 1; i >= 0; i--) {
let proj = tower.projectiles[i];
if (proj.deleteMe || tower.sold) {
proj.collidedCreepIDs.forEach(() => {
tower.damageDealt += tower.computedDamageToDeal;
});
proj.collidedCreepIDs = [];
tower.projectiles.splice(tower.projectiles.indexOf(proj), 1);
proj.destroy();
proj = null;
} else proj.update(elapsedMS);
});
tower.projectiles.splice(i, 1);
} else {
proj.update(elapsedMS);
}
}
}
/**
@ -215,7 +219,10 @@ export function StrongTowerBehaviour(tower: Tower, elapsedMS: number) {
let x = tower.column * Engine.GridCellSize + Engine.GridCellSize / 2;
let y = tower.row * Engine.GridCellSize + Engine.GridCellSize / 2;
tower.millisecondsUntilNextShot = tower.computedCooldown;
tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
let proj = tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
proj.onCollide = (creep: Creep, proj: Projectile) => {
Engine.GameScene.events.emit(CreepEvents.GiveEffect, creep.id, CreepEffects.MovingBackwards, 500);
};
}
}
}
@ -233,6 +240,7 @@ export function RailTowerBehaviour(tower: Tower, elapsedMS: number) {
let x = tower.column * Engine.GridCellSize + Engine.GridCellSize / 2;
let y = tower.row * Engine.GridCellSize + Engine.GridCellSize / 2;
tower.millisecondsUntilNextShot = tower.computedCooldown;
// Custom logic handled via tower.Shoot
tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
}
}
@ -259,7 +267,10 @@ export function DebuffTowerBehaviour(tower: Tower, elapsedMS: number) {
let x = tower.column * Engine.GridCellSize + Engine.GridCellSize / 2;
let y = tower.row * Engine.GridCellSize + Engine.GridCellSize / 2;
tower.millisecondsUntilNextShot = tower.computedCooldown;
tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
let proj = tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
proj.onCollide = (creep: Creep, proj: Projectile) => {
Engine.GameScene.events.emit(CreepEvents.GiveEffect, creep.id, CreepEffects.DebuffTowerDebuff, 5000);
};
}
}
}

View File

@ -167,7 +167,6 @@ export class GameScene extends Scene {
this.ticker.add(() => {
if (this.update) this.update(this.ticker.elapsedMS);
// if (this.isFastForwarded) this.update(this.ticker.elapsedMS);
});
this.ticker.start();
}