import { assertEquals } from "https://deno.land/std@0.221.0/assert/mod.ts"; import { chunks, enumerate, log_from, spiral, Vec2 } from "../../common/utils.ts"; import { Engine, Entity, Query } from "../engine.ts"; import { CompDisplay } from "./display.ts"; const log = log_from(import.meta); export class CompPos { position; entity; constructor(entity: Entity, position: Vec2) { this.position = position; this.entity = entity; } move(displacement: Vec2) { this.position = this.position.add(displacement); } move_collide(engine: Engine, displacement: Vec2) { let result = false; for (const step of displacement_steps(this.position, displacement)) { const collider_exists = engine.query_one(query_at(step)) !== null; if (collider_exists) return result; this.position = step; result = true; } return result; } } function* displacement_steps(position: Vec2, displacement: Vec2) { let pos = position; let left = displacement; while (left.len() >= 1) { if (left.x() >= 1) { pos = pos.add(new Vec2(1, 0)); left = left.sub(new Vec2(1, 0)); } if (left.x() <= -1) { pos = pos.add(new Vec2(-1, 0)); left = left.sub(new Vec2(-1, 0)); } if (left.y() >= 1) { pos = pos.add(new Vec2(0, 1)); left = left.sub(new Vec2(0, 1)); } if (left.y() <= -1) { pos = pos.add(new Vec2(0, -1)); left = left.sub(new Vec2(0, -1)); } yield pos; } } Deno.test("test_displacement", () => { assertEquals( [...displacement_steps(new Vec2(1, 1), new Vec2(4, 6))], [new Vec2(2, 2), new Vec2(3, 3), new Vec2(4, 4), new Vec2(5, 5), new Vec2(5, 6), new Vec2(5, 7)], ); }); export function query_at(pos: Vec2) { return Query.with(CompPos).filter(([c]) => c.position.overlaps(pos)); } export function query_in_rect(min: Vec2, max: Vec2) { return Query.with(CompPos).filter(([c]) => c.position.inside(min, max)); } class CompStructure {} export function sys_spawn_obstacle(pos: Vec2, display: string) { return (engine: Engine) => engine.spawn((entity) => entity.insert( new CompStructure(), new CompDisplay(display), new CompPos(entity, pos), ) ); } export async function sys_spawn_structure(file_path: string, origin: Vec2) { const content = await Deno.readTextFile(file_path); return (engine: Engine) => { let count = 0; for (const [y, line] of enumerate(content.split("\n"))) { for (const [x, chars] of enumerate(chunks(line, 2))) { const display = chars[0] + chars[1]; if (display === " ") continue; engine.run(sys_spawn_obstacle(origin.add(new Vec2(x, y)), display)); count += 1; } } log("Spawned", count, "tiles from", file_path); }; } export function sys_find_free_pos(target: Vec2) { return (engine: Engine) => { for (const pos of spiral(target)) { const found = engine.query_one(query_at(pos)); if (found === null) return pos; } throw new Error("Unreachable."); }; }