2018-11-01 00:59:13 +01:00
|
|
|
import { MapData } from '../model/data/map';
|
2018-10-31 23:02:41 +01:00
|
|
|
|
|
|
|
import { loadSimpleEntity } from '../view/entity';
|
2018-11-01 00:59:13 +01:00
|
|
|
import { DirectionHandler } from '../view/input/directionhandler';
|
2018-10-31 23:02:41 +01:00
|
|
|
import { loadMap } from '../view/map';
|
2018-11-01 00:59:13 +01:00
|
|
|
import { Renderer } from '../view/renderer/renderer';
|
2018-10-31 23:02:41 +01:00
|
|
|
import { SpriteView } from '../view/sprite';
|
|
|
|
|
2018-11-04 20:22:47 +01:00
|
|
|
import { LineSegment } from '../math/line';
|
2018-10-31 23:02:41 +01:00
|
|
|
import { getJSON } from '../util';
|
|
|
|
|
|
|
|
import { vec2 } from 'gl-matrix';
|
|
|
|
|
|
|
|
export class GameContext {
|
|
|
|
public static async load(renderer: Renderer): Promise<GameContext> {
|
2018-11-01 00:44:49 +01:00
|
|
|
const mapView = this.loadMap(renderer);
|
|
|
|
const entity = loadSimpleEntity(renderer, 'simple_square');
|
2018-10-31 23:02:41 +01:00
|
|
|
|
|
|
|
return new GameContext(
|
|
|
|
renderer,
|
2018-11-01 00:44:49 +01:00
|
|
|
await mapView,
|
|
|
|
await entity,
|
2018-10-31 23:02:41 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-11-01 00:44:49 +01:00
|
|
|
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
|
2018-10-31 23:02:41 +01:00
|
|
|
|
|
|
|
private readonly input: DirectionHandler;
|
|
|
|
|
2018-11-04 20:22:47 +01:00
|
|
|
private readonly entityPos: vec2 = vec2.clone([6, 6]);
|
2018-10-31 23:02:41 +01:00
|
|
|
private readonly entityMovement: vec2 = vec2.create();
|
|
|
|
|
2018-11-04 20:22:47 +01:00
|
|
|
private readonly walls: LineSegment[] = [
|
|
|
|
new LineSegment(vec2.fromValues(1, 1), vec2.fromValues(1, 0), 10),
|
|
|
|
new LineSegment(vec2.fromValues(11, 1), vec2.fromValues(0, 1), 10),
|
|
|
|
new LineSegment(vec2.fromValues(11, 11), vec2.fromValues(-1, 0), 10),
|
|
|
|
new LineSegment(vec2.fromValues(1, 11), vec2.fromValues(0, -1), 10),
|
|
|
|
];
|
|
|
|
|
2018-10-31 23:02:41 +01:00
|
|
|
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 {
|
2018-10-31 23:13:52 +01:00
|
|
|
const diff = this.time !== null ? time - this.time : 0;
|
2018-10-31 23:02:41 +01:00
|
|
|
this.time = time;
|
|
|
|
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
2018-11-01 00:44:49 +01:00
|
|
|
private updateStep(): void {
|
2018-11-04 20:22:47 +01:00
|
|
|
let move = new LineSegment(this.entityPos, this.entityMovement, this.speed);
|
|
|
|
const p = vec2.create();
|
|
|
|
|
|
|
|
let rescan = true;
|
|
|
|
|
|
|
|
while (rescan) {
|
|
|
|
rescan = false;
|
|
|
|
|
|
|
|
for (const w of this.walls) {
|
|
|
|
if (!w.collidesMove(move))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
move.getP2(p);
|
|
|
|
w.projectPoint(p, p);
|
|
|
|
|
|
|
|
const move2 = LineSegment.fromPoints(this.entityPos, p);
|
|
|
|
if (move2.l === 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!move.equals(move2)) {
|
|
|
|
move = move2;
|
|
|
|
rescan = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
move.getP2(this.entityPos);
|
2018-11-01 00:44:49 +01:00
|
|
|
}
|
|
|
|
|
2018-10-31 23:02:41 +01:00
|
|
|
private update(time: number): void {
|
2018-11-01 00:44:49 +01:00
|
|
|
const diff = Math.min(this.maxSkip, this.updateTime(time));
|
2018-10-31 23:02:41 +01:00
|
|
|
|
2018-11-01 00:44:49 +01:00
|
|
|
if (vec2.sqrLen(this.entityMovement) === 0) {
|
2018-10-31 23:13:52 +01:00
|
|
|
this.renderer.snapToGrid(this.entityPos, this.entityPos);
|
2018-11-01 00:44:49 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < diff; i++)
|
|
|
|
this.updateStep();
|
2018-10-31 23:02:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private render = (time: number) => {
|
2018-11-01 00:44:49 +01:00
|
|
|
this.update(Math.round(time / this.tick));
|
2018-10-31 23:02:41 +01:00
|
|
|
|
|
|
|
this.renderer.setCenter(this.entityPos);
|
|
|
|
this.renderer.clear();
|
|
|
|
|
|
|
|
this.mapView.render();
|
|
|
|
|
|
|
|
this.renderer.setTranslation(this.entityPos);
|
|
|
|
this.entity.render();
|
|
|
|
|
|
|
|
window.requestAnimationFrame(this.render);
|
|
|
|
}
|
|
|
|
}
|