From b591fc2dee222f78d9db0fed0eceac31b33a6dfa Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Sat, 30 Aug 2025 20:24:35 +0200 Subject: [PATCH] survivors: fixing drops being duplicated (sometimes) adding item container system to not edit the list while iterating over --- absurd-survivors/src/World.ts | 95 +++++++++++++++++++++++------------ absurd-survivors/src/drop.ts | 1 - absurd-survivors/src/main.ts | 2 +- 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/absurd-survivors/src/World.ts b/absurd-survivors/src/World.ts index a6cc0e8..7b03ac5 100644 --- a/absurd-survivors/src/World.ts +++ b/absurd-survivors/src/World.ts @@ -1,16 +1,16 @@ import {Enemy} from "./Enemies.ts"; import {Player} from "./Player.ts"; -import {Projectile, ProjectileStats} from "./projectile.ts"; +import {Projectile } from "./projectile.ts"; import {Vector} from "./base.ts"; import type {Drop, Placeable} from "./interfaces.ts"; export class World { - private _enemies: Enemy[] = []; - private _projectiles: Projectile[] = []; - private _drops: Drop[] = []; + private _enemies: ObjectContainer = new ObjectContainer() + private _projectiles: ObjectContainer = new ObjectContainer(); + private _drops: ObjectContainer = new ObjectContainer(); private _player: Player; - private _ctx: CanvasRenderingContext2D; - private _size: Vector + private readonly _ctx: CanvasRenderingContext2D; + private _size: Vector; constructor(player: Player, ctx: CanvasRenderingContext2D, size: Vector) { this._player = player; @@ -19,26 +19,42 @@ export class World { } enemiesAct() { - this._enemies.forEach(enemy => enemy.act()) - this._projectiles.forEach(projectile => projectile.act()) - this._drops.forEach(drop => drop.act()) + this._enemies.items.forEach(enemy => enemy.act()) + this._enemies.clean() + this._projectiles.items.forEach(projectile => projectile.act()) + this._projectiles.clean() + this._drops.items.forEach(drop => drop.act()) + this._drops.clean() } draw() { - this._enemies.forEach(enemy => enemy.draw(this._ctx)) - this._drops.forEach(drop => drop.draw(this._ctx)) - this._projectiles.forEach(projectile => projectile.draw(this._ctx)) + this._enemies.items.forEach(enemy => enemy.draw(this._ctx)) + this._drops.items.forEach(drop => drop.draw(this._ctx)) + this._projectiles.items.forEach(projectile => projectile.draw(this._ctx)) this._player.draw(this._ctx); } addProjectile(projectile: Projectile) { - this._projectiles.push(projectile) + this._projectiles.add(projectile) } addDrop(drop: Drop) { - this._drops.push(drop) + this._drops.add(drop) } + removeDrop(drop: Drop) { + this._drops.scheduleRemoval(drop) + } + + removeEnemy(enemy: Enemy) { + this._enemies.scheduleRemoval(enemy) + } + + removeProjectile(projectile: Projectile) { + this._projectiles.scheduleRemoval(projectile) + } + + movePlayer(vector: Vector) { this._player.position.x += vector.x; this._player.position.y += vector.y; @@ -48,26 +64,11 @@ export class World { this._player.position.y = Math.max(this._player.getSize(), this._player.position.y) } - removeDrop(drop: Drop) { - this._drops = this._drops.filter(item => item !== drop) - } - - removeProjectile(projectile: Projectile) { - this._projectiles = this._projectiles.filter(item => item !== projectile) - } - - removeEnemy(enemy: Enemy) { - this._enemies = this._enemies.filter(item => item !== enemy) - } maxValue() { return Math.max(this.size.x, this.size.y) } - get enemies(): [Enemy] { - return this._enemies; - } - get size(): Vector { return this._size; @@ -78,7 +79,7 @@ export class World { } addEnemy(enemy: Enemy) { - this._enemies.push(enemy) + this._enemies.add(enemy) } randomPlace(): Vector { @@ -96,7 +97,7 @@ export class World { getClosestTargetToButNotArray(point: Vector, placeAbles?: [Placeable | undefined], range?: number): [number, Placeable | undefined] | undefined { let currentTarget; let currentDistance = Number.MAX_SAFE_INTEGER; - this._enemies.forEach(enemy => { + this._enemies.items.forEach(enemy => { if(placeAbles && placeAbles.indexOf(enemy) !== -1) { return; } @@ -117,4 +118,36 @@ export class World { get player(): Player { return this._player; } +} + +class ObjectContainer { + private _items: T[] = []; + private _itemsToRemove: T[] = []; + + constructor() { + this._items = [] + this._itemsToRemove = [] + } + + scheduleRemoval(item: T) { + this._itemsToRemove.push(item) + } + + clean() { + this._itemsToRemove.forEach(value => this.remove(value)) + this._itemsToRemove = [] + } + + private remove(itemToRemove: T) { + this._items = this._items.filter(item => item !== itemToRemove) + } + + add(item: T) { + this._items.push(item) + } + + + get items(): T[] { + return this._items; + } } \ No newline at end of file diff --git a/absurd-survivors/src/drop.ts b/absurd-survivors/src/drop.ts index eb248b9..26d31c2 100644 --- a/absurd-survivors/src/drop.ts +++ b/absurd-survivors/src/drop.ts @@ -67,7 +67,6 @@ export class MoneyDrop extends BasicDrop { drop.worth = 1; drop.size = 1; drop._color = 'orange'; - world.addDrop(drop) return drop; } } diff --git a/absurd-survivors/src/main.ts b/absurd-survivors/src/main.ts index 10bebdf..4d7615c 100644 --- a/absurd-survivors/src/main.ts +++ b/absurd-survivors/src/main.ts @@ -7,6 +7,7 @@ import {Vector} from "./base.ts"; import {BasicEnemy, ContainerEnemy, Enemy, HealthEnemy, ShootingEnemy} from "./Enemies.ts"; import {HUD} from "./ui.ts"; import {HomingPistol, Pistol} from "./weapons.ts"; +import {MoneyDrop} from "./drop.ts"; let hud: HUD; @@ -107,7 +108,6 @@ docReady(function () { world = new World(player, ctx, new Vector(window.innerWidth, window.innerHeight)); state = new WorldState(); - ShootingEnemy.spawnShootingEnemy(world, new Vector(350, 350)) setInterval(() => { BasicEnemy.spawnBasicEnemy(world) ShootingEnemy.spawnShootingEnemy(world)