1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
import { MapData } from '../model/data/map';
import { loadSimpleEntity } from '../view/entity';
import { DirectionHandler } from '../view/input/directionhandler';
import { loadMap } from '../view/map';
import { Renderer } from '../view/renderer/renderer';
import { SpriteView } from '../view/sprite';
import { getJSON } from '../util';
import { vec2 } from 'gl-matrix';
export class GameContext {
public static async load(renderer: Renderer): Promise<GameContext> {
const mapView = this.loadMap(renderer);
const entity = loadSimpleEntity(renderer, 'simple_square');
return new GameContext(
renderer,
await mapView,
await entity,
);
}
private static async loadMap(renderer: Renderer): Promise<SpriteView> {
const map = new MapData(await getJSON('resources/map/test.json'));
return loadMap(renderer, map);
}
private time: number|null = null;
private readonly tick = 10; // ms per tick
private readonly speed = 0.05; // movement per tick
private readonly maxSkip = 20; // maximum ticks to process in a single render step
private readonly input: DirectionHandler;
private readonly entityPos: vec2 = vec2.create();
private readonly entityMovement: vec2 = vec2.create();
private constructor(
private readonly renderer: Renderer,
private readonly mapView: SpriteView,
private readonly entity: SpriteView,
) {
this.input = new DirectionHandler();
this.input.addListener((v) => {
if (vec2.sqrLen(v) > 0)
vec2.normalize(this.entityMovement, v);
else
vec2.copy(this.entityMovement, [0, 0]);
});
window.requestAnimationFrame(this.render);
}
private updateTime(time: number): number {
const diff = this.time !== null ? time - this.time : 0;
this.time = time;
return diff;
}
private updateStep(): void {
vec2.scaleAndAdd(this.entityPos, this.entityPos, this.entityMovement, this.speed);
}
private update(time: number): void {
const diff = Math.min(this.maxSkip, this.updateTime(time));
if (vec2.sqrLen(this.entityMovement) === 0) {
this.renderer.snapToGrid(this.entityPos, this.entityPos);
return;
}
for (let i = 0; i < diff; i++)
this.updateStep();
}
private render = (time: number) => {
this.update(Math.round(time / this.tick));
this.renderer.setCenter(this.entityPos);
this.renderer.clear();
this.mapView.render();
this.renderer.setTranslation(this.entityPos);
this.entity.render();
window.requestAnimationFrame(this.render);
}
}
|