diff --git a/common/utils.ts b/common/utils.ts index 52c7e04..71f6c4d 100644 --- a/common/utils.ts +++ b/common/utils.ts @@ -224,6 +224,14 @@ export class Vec2 { public clone() { return new Vec2(this.x(), this.y()); } + + public normalize() { + return new Vec2(clamp(this.x(), -1, 1), clamp(this.y(), -1, 1)); + } +} + +export function clamp(x: number, min: number, max: number) { + return Math.max(min, Math.min(x, max)); } export function v2(x: number, y: number) { diff --git a/server/entities/enemy.ts b/server/entities/enemy.ts index 134b76d..e6b7445 100644 --- a/server/entities/enemy.ts +++ b/server/entities/enemy.ts @@ -1,15 +1,37 @@ +import { assert } from "https://deno.land/std@0.221.0/assert/assert.ts"; +import { v2 } from "../../common/utils.ts"; import { Vec2 } from "../../common/utils.ts"; import { CompDisplay } from "../components/display.ts"; +import { query_in_rect } from "../components/world.ts"; import { CompPos } from "../components/world.ts"; +import { CompId, Query } from "../engine.ts"; import { Engine } from "../engine.ts"; +import { CompPlayer } from "./player.ts"; export class CompEnemy { target; life; + constructor() { this.target = null as number | null; this.life = 10; } + + get_target_pos(engine: Engine) { + if (this.target === null) return null; + const result = engine.one(Query.with(CompId).filter(([c]) => c.id === this.target).with(CompPos)); + if (result === null) return null; + const [_, pos] = result; + return pos.pos; + } + + find_target_from(engine: Engine, pos: Vec2) { + const RANGE = v2(2, 2); + const found = engine.one(Query.with(CompPlayer).with(CompId).and(query_in_rect(pos.sub(RANGE), pos.add(RANGE)))); + if (found === null) return this.target = null; + const [_, id, __] = found; + return this.target = id.id; + } } export function sys_spawn_enemy(pos: Vec2) { @@ -23,3 +45,20 @@ export function sys_spawn_enemy(pos: Vec2) { ); }; } + +export function sys_update_enemy() { + return (engine: Engine) => { + for (const [enemy, enemy_pos] of engine.all(Query.with(CompEnemy).with(CompPos))) { + if (enemy.target === null) enemy.find_target_from(engine, enemy_pos.pos); + if (enemy.target === null) continue; + const pos = enemy.get_target_pos(engine); + assert(pos !== null); + const direction = pos.sub(enemy_pos.pos); + enemy_pos.move_collide(engine, direction.normalize()); + } + }; +} + +export function enemy_plugin(engine: Engine) { + engine.global_system_loop(sys_update_enemy(), 500); +}