import { EntityData, EntityDataInput } from '../model/data/entity'; import { Renderer } from './renderer/renderer'; import { SpriteCoords, SpriteView, SpriteViewBuilder } from './sprite'; import { loadImage, mkTexture } from './util/image'; import { getJSON } from '../util'; import { vec2 } from 'gl-matrix'; export class EntityView { public static async load(r: Renderer, name: string): Promise { const data = new EntityData((await getJSON(`resources/entity/${name}.json`)) as EntityDataInput); const tile = await loadImage(`resources/sprite/entity/${data.sprite}.png`); const [texture, size] = mkTexture(r, tile); const frameSize: [number, number] = [size[0], size[1] / data.frames]; const offset = vec2.mul(vec2.create(), frameSize, data.anchor); r.snapToGrid(offset, offset); const coords: SpriteCoords = [ -offset[0], -offset[1], -offset[0] + frameSize[0], -offset[1] + frameSize[1], ]; const sprites: SpriteView[] = []; for (let frame = 0; frame < data.frames; frame++) { const builder = new SpriteViewBuilder(r, texture); builder.addSprite(coords, [0, frame / data.frames, 1, (frame + 1) / data.frames]); sprites.push(builder.build()); } return new EntityView(data, sprites); } private readonly totalTime: number; private constructor(public readonly data: EntityData, public readonly sprites: SpriteView[]) { if (data.animation) this.totalTime = data.animation.sequence.reduce((a, s) => a + s[0], 0); else this.totalTime = 0; } public getSpriteByTime(time: number): SpriteView { time %= this.totalTime; if (this.data.animation) { for (const [len, sprite] of this.data.animation.sequence) { time -= len; if (time < 0) return this.sprites[sprite]; } } return this.sprites[0]; } public renderByTime(time: number): void { this.getSpriteByTime(time).render(); } }