| import { SpatialGrid, randomRange } from "./utils.js"; | |
| import { ENTITY_TYPES, createGenome, reproduce } from "./genetics.js"; | |
| import { Entity } from "./entities.js"; | |
| export class EntityManager { | |
| constructor(worldWidth, worldHeight) { | |
| this.entities = []; | |
| this.spatialGrid = new SpatialGrid(worldWidth, worldHeight, 60); | |
| this.worldWidth = worldWidth; | |
| this.worldHeight = worldHeight; | |
| } | |
| add(entity) { | |
| this.entities.push(entity); | |
| } | |
| update(dt, world, particles, stats) { | |
| this.spatialGrid.clear(); | |
| for (const e of this.entities) { | |
| if (e.alive) this.spatialGrid.insert(e, e.x, e.y); | |
| } | |
| const newborns = []; | |
| for (const e of this.entities) { | |
| e.update(dt, world, this.entities, this.spatialGrid, particles); | |
| const child = e.tryReproduce(this.spatialGrid, particles); | |
| if (child) { | |
| newborns.push(child); | |
| stats.onBirth(); | |
| } | |
| } | |
| for (const child of newborns) { | |
| this.entities.push(child); | |
| } | |
| for (let i = this.entities.length - 1; i >= 0; i--) { | |
| if (!this.entities[i].alive) { | |
| stats.onDeath(); | |
| this.entities.splice(i, 1); | |
| } | |
| } | |
| } | |
| render(ctx) { | |
| this.entities.sort((a, b) => a.y - b.y); | |
| for (const e of this.entities) { | |
| e.render(ctx); | |
| } | |
| } | |
| getAlive() { | |
| return this.entities.filter((e) => e.alive); | |
| } | |
| spawnRandom(count, world) { | |
| const types = Object.keys(ENTITY_TYPES); | |
| for (let i = 0; i < count; i++) { | |
| const type = types[Math.floor(Math.random() * types.length)]; | |
| const genome = createGenome(type); | |
| const x = randomRange(20, world.width - 20); | |
| const y = randomRange(20, world.height - 20); | |
| this.entities.push(new Entity(x, y, genome, 0)); | |
| } | |
| } | |
| spawnFromPopulation(population, count, world) { | |
| if (population.length < 2) return; | |
| const candidates = population.map((e) => ({ | |
| genome: e.genome, | |
| fitness: e.fitness, | |
| })); | |
| for (let i = 0; i < count; i++) { | |
| const childGenome = reproduce(candidates); | |
| const x = randomRange(20, world.width - 20); | |
| const y = randomRange(20, world.height - 20); | |
| const gen = Math.max(...population.map((e) => e.generation)) + 1; | |
| this.entities.push(new Entity(x, y, childGenome, gen)); | |
| } | |
| } | |
| } | |