import { load_texture } from "./assets"; import { btn, Button } from "./input"; import { Vec2, new_v2, vadd, vnorm, vmul } from "./vector"; import { spr, use_texture, Texture } from "./graphics"; interface ActorSnapshot { __type__: string; velocity: Vec2; friction: number; id: string; position: Vec2; bounds: Vec2; } export class Actor { velocity: Vec2 = new_v2(0); friction: number = 0.6; id: string; position: Vec2; bounds: Vec2; constructor(id: string, position: Vec2, bounds: Vec2) { this.id = id; this.position = position; this.bounds = bounds; } update() {} update_physics() { const velocity = vmul(this.velocity, this.friction); // Zero if we're smaller than some epsilon. if (Math.abs(velocity.x) < 0.01) { velocity.x = 0; } if (Math.abs(velocity.y) < 0.01) { velocity.y = 0; } const new_position = vadd(this.position, velocity); // TODO: Collision detection // const { w, h } = this.bounds; this.velocity = velocity; this.position = new_position; } draw(_clock: number) {} bonk(_other: Actor) {} snapshot(): ActorSnapshot { return { ...this, __type__: "??" }; } assign_snapshot(s: ActorSnapshot) { this.id = s.id; this.position = s.position; this.bounds = s.bounds; this.velocity = s.velocity; this.friction = s.friction; return this; } } const robo_info = { width: 32, height: 32, sprite: "./bot.png", animations: [ { start: 0, length: 1, speed: 20 }, { start: 1, length: 4, speed: 8 }, ], }; interface RoboSnapshot extends ActorSnapshot { __type__: "robo"; } export class Robo extends Actor { bot_sprite: Texture | undefined = undefined; constructor(pos: Vec2) { super("robo", pos, new_v2(robo_info.width, robo_info.height)); load_texture(robo_info.sprite).then((texture) => { this.bot_sprite = texture; }); } update() { // Acceleration from input let a = new_v2(0); if (btn(Button.Up)) { a.y -= 1; } if (btn(Button.Down)) { a.y += 1; } if (btn(Button.Left)) { a.x -= 1; } if (btn(Button.Right)) { a.x += 1; } vnorm(a); this.velocity = vadd(this.velocity, vmul(a, 1.5)); } draw(clock: number) { if (this.bot_sprite != undefined) { use_texture(this.bot_sprite); const vel = this.velocity; const moving = vel.x != 0 || vel.y != 0; const anim = robo_info.animations[moving ? 1 : 0]; const { x: w, y: h } = this.bounds; const { x, y } = this.position; const frame = (anim.start + ((clock / anim.speed) % anim.length)) >> 0; spr(x, y, w, h, frame * w, 0, 32, 32); } } snapshot(): RoboSnapshot { return { ...super.snapshot(), __type__: "robo" }; } assign_snapshot(s: RoboSnapshot) { super.assign_snapshot(s); return this; } } const SNAPSHOT_TABLE: { [key: string]: (s: any) => Actor } = { robo: (s: any) => new Robo(new_v2(0)).assign_snapshot(s), }; export function actor_from_snapshot(s: ActorSnapshot): Actor { const f = SNAPSHOT_TABLE[s.__type__]; if (f == undefined) { throw new Error("No handler for " + s.__type__); } return f(s); }