summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/controller/entitycontext.ts8
-rw-r--r--src/controller/gamecontext.ts54
-rw-r--r--src/view/input/directionhandler.ts37
-rw-r--r--src/view/input/gameinput.ts78
-rw-r--r--src/view/input/inputhandler.ts24
-rw-r--r--tslint.json1
6 files changed, 140 insertions, 62 deletions
diff --git a/src/controller/entitycontext.ts b/src/controller/entitycontext.ts
index c11c698..c1eb1fc 100644
--- a/src/controller/entitycontext.ts
+++ b/src/controller/entitycontext.ts
@@ -17,6 +17,7 @@ export class EntityContext implements CollidableGroup {
return new EntityContext(
renderer,
+ name,
await loadEntity(renderer, entity),
mkCollision(entity.collision),
);
@@ -26,8 +27,9 @@ export class EntityContext implements CollidableGroup {
private constructor(
private readonly renderer: Renderer,
+ private readonly name: string,
private readonly view: SpriteView,
- public readonly collision: Collidable[],
+ private readonly collision: Collidable[],
) {}
public render() {
@@ -42,4 +44,8 @@ export class EntityContext implements CollidableGroup {
public getCollidables(): Collidable[] {
return this.collision;
}
+
+ public interact() {
+ alert(`You've interacted with ${this.name}!`);
+ }
}
diff --git a/src/controller/gamecontext.ts b/src/controller/gamecontext.ts
index 8ec54b5..a12e3bc 100644
--- a/src/controller/gamecontext.ts
+++ b/src/controller/gamecontext.ts
@@ -3,7 +3,7 @@ import { EntityContext } from './entitycontext';
import { MapData } from '../model/data/map';
-import { DirectionHandler } from '../view/input/directionhandler';
+import { ButtonCode, GameInputHandler } from '../view/input/gameinput';
import { loadMap } from '../view/map';
import { Renderer } from '../view/renderer/renderer';
import { SpriteView } from '../view/sprite';
@@ -44,14 +44,16 @@ export class GameContext implements CollidableGroup {
private time: number|null = null;
private readonly tick = 10; // ms per tick
- private readonly speed = 0.04; // movement per tick
+ private readonly maxSpeed = 0.04; // movement per tick
private readonly maxSkip = 20; // maximum ticks to process in a single render step
- private readonly input: DirectionHandler;
+ private readonly input: GameInputHandler;
- private readonly playerMovement: vec2 = vec2.create();
+ private readonly playerDir: vec2 = vec2.fromValues(0, 1);
+ private speed: number = 0;
private readonly collisionRadius = 7 / 16;
+ private readonly interactLength = 1 / 32;
private constructor(
private readonly renderer: Renderer,
@@ -60,12 +62,23 @@ export class GameContext implements CollidableGroup {
private readonly entities: EntityContext[],
private readonly collision: Collidable[],
) {
- this.input = new DirectionHandler();
- this.input.addListener((v) => {
- if (vec2.sqrLen(v) > 0)
- vec2.normalize(this.playerMovement, v);
- else
- vec2.copy(this.playerMovement, [0, 0]);
+ this.input = new GameInputHandler();
+ this.input.addListener((input) => {
+ switch (input.type) {
+ case 'button':
+ if (input.button === ButtonCode.Action)
+ this.interact();
+ break;
+
+ case 'direction':
+ if (vec2.sqrLen(input.direction) > 0) {
+ vec2.copy(this.playerDir, input.direction);
+ this.speed = this.maxSpeed;
+ } else {
+ this.speed = 0;
+ }
+ break;
+ }
});
window.requestAnimationFrame(this.render);
@@ -86,6 +99,23 @@ export class GameContext implements CollidableGroup {
return diff;
}
+ private canInteract(c: CollidableGroup): boolean {
+ const dest = vec2.scaleAndAdd(vec2.create(), this.player.pos, this.playerDir, this.interactLength);
+ const move = new Movement(this.player.pos, dest);
+
+ return collide(c, vec2.create(), move, this.collisionRadius);
+ }
+
+ private interact(): void {
+ for (const e of this.entities) {
+ if (!this.canInteract(e))
+ continue;
+
+ e.interact();
+ break;
+ }
+ }
+
private updateStepCollide(out: vec2, dest: vec2): boolean {
const move = new Movement(this.player.pos, dest);
@@ -102,7 +132,7 @@ export class GameContext implements CollidableGroup {
}
private updateStep(): void {
- const dest = vec2.scaleAndAdd(vec2.create(), this.player.pos, this.playerMovement, this.speed);
+ const dest = vec2.scaleAndAdd(vec2.create(), this.player.pos, this.playerDir, this.speed);
const newDest = vec2.create();
while (this.updateStepCollide(newDest, dest)) {
@@ -118,7 +148,7 @@ export class GameContext implements CollidableGroup {
private update(time: number): void {
const diff = Math.min(this.maxSkip, this.updateTime(time));
- if (vec2.sqrLen(this.playerMovement) === 0) {
+ if (!this.speed) {
this.renderer.snapToGrid(this.player.pos, this.player.pos);
return;
}
diff --git a/src/view/input/directionhandler.ts b/src/view/input/directionhandler.ts
deleted file mode 100644
index 0a3687e..0000000
--- a/src/view/input/directionhandler.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { InputHandler } from './inputhandler';
-
-import { Listenable } from '../../util';
-
-import { vec2 } from 'gl-matrix';
-
-export const enum Keycode {
- Left = 37,
- Up = 38,
- Right = 39,
- Down = 40,
-}
-
-export class DirectionHandler extends Listenable<[vec2]> {
- private readonly input: InputHandler;
-
- constructor() {
- super();
-
- this.input = new InputHandler(new Set([Keycode.Left, Keycode.Up, Keycode.Right, Keycode.Down]));
-
- this.input.addListener(() => {
- const dir = vec2.create();
-
- if (this.input.has(Keycode.Left))
- vec2.add(dir, dir, [-1, 0]);
- if (this.input.has(Keycode.Up))
- vec2.add(dir, dir, [0, -1]);
- if (this.input.has(Keycode.Right))
- vec2.add(dir, dir, [1, 0]);
- if (this.input.has(Keycode.Down))
- vec2.add(dir, dir, [0, 1]);
-
- this.runListeners(dir);
- });
- }
-}
diff --git a/src/view/input/gameinput.ts b/src/view/input/gameinput.ts
new file mode 100644
index 0000000..f3066e3
--- /dev/null
+++ b/src/view/input/gameinput.ts
@@ -0,0 +1,78 @@
+import { InputHandler } from './inputhandler';
+
+import { Listenable } from '../../util';
+
+import { vec2 } from 'gl-matrix';
+
+export enum ButtonCode {
+ Action,
+ Back,
+ Menu,
+}
+
+const buttonMapping: {[key: string]: ButtonCode} = {
+ KeyZ: ButtonCode.Action,
+ KeyX: ButtonCode.Back,
+ KeyC: ButtonCode.Menu,
+};
+
+export interface DirectionInput {
+ type: 'direction';
+ direction: vec2;
+}
+
+export interface ButtonInput {
+ type: 'button';
+ button: ButtonCode;
+}
+
+export type GameInput = DirectionInput | ButtonInput;
+
+export class GameInputHandler extends Listenable<[GameInput]> {
+ private readonly input: InputHandler;
+
+ constructor() {
+ super();
+
+ this.input = new InputHandler(
+ new Set([
+ 'ArrowLeft',
+ 'ArrowUp',
+ 'ArrowRight',
+ 'ArrowDown',
+ ...Object.keys(buttonMapping),
+ ]));
+
+ this.input.addListener((key: string, pressed: boolean) => {
+ const button = buttonMapping[key];
+ if (button !== undefined) {
+ if (pressed)
+ this.runListeners({
+ type: 'button',
+ button,
+ });
+
+ return;
+ }
+
+ const dir = vec2.create();
+
+ if (this.input.has('ArrowLeft'))
+ vec2.add(dir, dir, [-1, 0]);
+ if (this.input.has('ArrowUp'))
+ vec2.add(dir, dir, [0, -1]);
+ if (this.input.has('ArrowRight'))
+ vec2.add(dir, dir, [1, 0]);
+ if (this.input.has('ArrowDown'))
+ vec2.add(dir, dir, [0, 1]);
+
+ if (vec2.sqrLen(dir) > 0)
+ vec2.normalize(dir, dir);
+
+ this.runListeners({
+ type: 'direction',
+ direction: dir,
+ });
+ });
+ }
+}
diff --git a/src/view/input/inputhandler.ts b/src/view/input/inputhandler.ts
index 96f15dd..22fdc28 100644
--- a/src/view/input/inputhandler.ts
+++ b/src/view/input/inputhandler.ts
@@ -1,39 +1,39 @@
import { Listenable } from '../../util';
-export class InputHandler extends Listenable<[]> {
- private readonly keys: Set<number> = new Set();
+export class InputHandler extends Listenable<[string, boolean]> {
+ private readonly keys: Set<string> = new Set();
- constructor(relevantKeys: Set<number>) {
+ constructor(relevantKeys: Set<string>) {
super();
window.addEventListener('keydown', (ev) => {
- if (!relevantKeys.has(ev.keyCode))
+ if (!relevantKeys.has(ev.code))
return;
ev.preventDefault();
- if (this.keys.has(ev.keyCode))
+ if (ev.repeat)
return;
- this.keys.add(ev.keyCode);
- this.runListeners();
+ this.keys.add(ev.code);
+ this.runListeners(ev.code, true);
});
window.addEventListener('keyup', (ev) => {
- if (!relevantKeys.has(ev.keyCode))
+ if (!relevantKeys.has(ev.code))
return;
ev.preventDefault();
- if (!this.keys.has(ev.keyCode))
+ if (!this.keys.has(ev.code))
return;
- this.keys.delete(ev.keyCode);
- this.runListeners();
+ this.keys.delete(ev.code);
+ this.runListeners(ev.code, false);
});
}
- public has(key: number): boolean {
+ public has(key: string): boolean {
return this.keys.has(key);
}
}
diff --git a/tslint.json b/tslint.json
index 3d735e4..e3b63f0 100644
--- a/tslint.json
+++ b/tslint.json
@@ -10,6 +10,7 @@
"interface-name": false,
"max-classes-per-file": false,
"no-bitwise": false,
+ "object-literal-sort-keys": false,
"one-variable-per-declaration": false,
"quotemark": [true, "single", "avoid-escape", "avoid-template"]
},