import { load_texture } from "./assets"; import { btn, Button } from "./input"; import { Vec2, new_v2, vadd, vsub, vnorm, vmul } from "./vector"; import { spr, use_texture, Texture } from "./graphics"; export interface ActorProps { position: Vec2; velocity: Vec2; friction: number; id: string; } export function new_actor_props(id: string, position: Vec2): ActorProps { return { velocity: new_v2(0), friction: 0.6, id, position, }; } export class Actor { type: ActorType; props: ActorProps; constructor(type: ActorType, props: ActorProps) { this.type = type; this.props = props; } update() {} update_physics() { const velocity = vmul(this.props.velocity, this.props.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.props.position, velocity); // TODO: Collision detection // const { w, h } = this.bounds; this.props.velocity = velocity; this.props.position = new_position; } draw(_clock: number) {} bonk(_other: Actor) {} } const robo_info = { anchor: new_v2(16, 24), // Distance from upper-left of sprite. bounds: new_v2(32), // Width/height of sprite. sprite: "./bot.png", animations: [ { start: 0, length: 1, speed: 20 }, { start: 1, length: 4, speed: 8 }, ], }; export class Robo extends Actor { bot_sprite: Texture | undefined = undefined; constructor(props: ActorProps) { super("robo", props); 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.props.velocity = vadd(this.props.velocity, vmul(a, 1.5)); } draw(clock: number) { if (this.bot_sprite != undefined) { use_texture(this.bot_sprite); const vel = this.props.velocity; const moving = vel.x != 0 || vel.y != 0; const anim = robo_info.animations[moving ? 1 : 0]; const { x: w, y: h } = robo_info.bounds; const { x, y } = vsub(this.props.position, robo_info.anchor); const frame = (anim.start + ((clock / anim.speed) % anim.length)) >> 0; spr(x, y, w, h, frame * w, 0, 32, 32); } } } const ACTOR_TABLE = { robo: (s: ActorProps) => new Robo(s), }; export type ActorType = keyof typeof ACTOR_TABLE; export function is_actor_type(type: string): type is ActorType { return ACTOR_TABLE.hasOwnProperty(type); } export function spawn_actor(type: ActorType, props: ActorProps): Actor { return ACTOR_TABLE[type](props); }