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