108 lines
2.8 KiB
TypeScript
108 lines
2.8 KiB
TypeScript
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.filter(CompPos, (c) => c.position.overlaps(pos));
|
|
}
|
|
|
|
export function query_in_rect(min: Vec2, max: Vec2) {
|
|
return Query.filter(CompPos, (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.");
|
|
};
|
|
}
|