Add basic controls

This commit is contained in:
kolaflash
2026-01-23 14:21:21 +01:00
parent 589af23e8c
commit f9a2409dad
19 changed files with 225 additions and 47 deletions
+2 -3
View File
@@ -21,14 +21,13 @@ export const entityMap = new Map<string, Entity<unknown>>();
export const entityAnimateMap = new Map<string, Animate<Indirect>>();
export const entityProcessMap = new Map<string, Process<Indirect>>();
export function useEntity<T extends { animation: Animation }>(
meta: { url: string },
export function defineEntity<T extends { animation: Animation }>(
name: string,
state: T,
): {
animate: (fn: Animate<T>) => void;
process: (fn: Process<T>) => void;
} {
const name = meta.url.match(/entities\/(.+)\/entity\.ts$/)![1];
entityMap.set(name, {
name,
position: createVector(),
+73
View File
@@ -0,0 +1,73 @@
export type KeyboardInput = {
arrowUp: boolean;
arrowDown: boolean;
arrowLeft: boolean;
arrowRight: boolean;
enter: boolean;
escape: boolean;
};
export const keyboardInput: KeyboardInput = {
arrowUp: false,
arrowDown: false,
arrowLeft: false,
arrowRight: false,
enter: false,
escape: false,
};
function onKeyDown(event: KeyboardEvent) {
switch (event.key) {
case "ArrowUp":
keyboardInput.arrowUp = true;
break;
case "ArrowDown":
keyboardInput.arrowDown = true;
break;
case "ArrowLeft":
keyboardInput.arrowLeft = true;
break;
case "ArrowRight":
keyboardInput.arrowRight = true;
break;
case "Enter":
keyboardInput.enter = true;
break;
case "Escape":
keyboardInput.escape = true;
break;
}
}
function onKeyUp(event: KeyboardEvent) {
switch (event.key) {
case "ArrowUp":
keyboardInput.arrowUp = false;
break;
case "ArrowDown":
keyboardInput.arrowDown = false;
break;
case "ArrowLeft":
keyboardInput.arrowLeft = false;
break;
case "ArrowRight":
keyboardInput.arrowRight = false;
break;
case "Enter":
keyboardInput.enter = false;
break;
case "Escape":
keyboardInput.escape = false;
break;
}
}
export function listenKeyboard(): () => void {
document.addEventListener("keydown", onKeyDown);
document.addEventListener("keyup", onKeyUp);
return () => {
document.removeEventListener("keydown", onKeyDown);
document.removeEventListener("keyup", onKeyUp);
};
}
+84
View File
@@ -0,0 +1,84 @@
import type { Vector } from "#/lib/Vector.ts";
import { viewport } from "./Viewport.ts";
export type Pointer = {
isDown: boolean;
position: Vector;
};
export const pointer: Pointer = {
isDown: false,
position: { x: 0, y: 0 },
};
function onMouseDown(event: MouseEvent): void {
adjustPointerPosition(pointer, event.clientX, event.clientY);
pointer.isDown = event.button === 0 ? true : pointer.isDown;
}
function onTouchStart(event: TouchEvent): void {
adjustPointerPosition(
pointer,
event.touches[0].clientX,
event.touches[0].clientY,
);
pointer.isDown = true;
}
function onMouseMove(event: MouseEvent): void {
adjustPointerPosition(pointer, event.clientX, event.clientY);
}
function onTouchMove(event: TouchEvent): void {
adjustPointerPosition(
pointer,
event.touches[0].clientX,
event.touches[0].clientY,
);
}
function onMouseUp(event: MouseEvent): void {
pointer.isDown = event.button === 0 ? false : pointer.isDown;
}
function onTouchEnd(event: TouchEvent): void {
pointer.isDown = event.touches.length === 0 ? false : pointer.isDown;
}
function onContextMenu(event: MouseEvent): void {
event.preventDefault();
}
function adjustPointerPosition(
pointer: Pointer,
clientX: number,
clientY: number,
): void {
const { ctx, translation: position, initialScale } = viewport;
const clientRect = ctx.canvas.getBoundingClientRect();
pointer.position.x = (clientX - clientRect.x + position.x) / initialScale;
pointer.position.y = (clientY - clientRect.y + position.y) / initialScale;
}
export function listenPointer(): () => void {
const canvas = viewport.ctx.canvas;
canvas.addEventListener("mousedown", onMouseDown);
canvas.addEventListener("touchstart", onTouchStart);
canvas.addEventListener("mousemove", onMouseMove);
canvas.addEventListener("touchmove", onTouchMove);
canvas.addEventListener("mouseup", onMouseUp);
canvas.addEventListener("touchend", onTouchEnd);
canvas.addEventListener("contextmenu", onContextMenu);
return () => {
canvas.removeEventListener("mousedown", onMouseDown);
canvas.removeEventListener("touchstart", onTouchStart);
canvas.removeEventListener("mousemove", onMouseMove);
canvas.removeEventListener("touchmove", onTouchMove);
canvas.removeEventListener("mouseup", onMouseUp);
canvas.removeEventListener("touchend", onTouchEnd);
canvas.removeEventListener("contextmenu", onContextMenu);
};
}
+4 -4
View File
@@ -1,5 +1,3 @@
import { useWithAsyncCache } from "#/lib/cache.ts";
import { type Graph, getNeighbours } from "#/lib/Graph.ts";
import {
type Animate as AnimateEntity,
type Entity,
@@ -8,7 +6,9 @@ import {
entityProcessMap,
type Indirect,
type Process as ProcessEntity,
} from "./Entity.ts";
} from "#/engine/Entity.ts";
import { useWithAsyncCache } from "#/lib/cache.ts";
import { type Graph, getNeighbours } from "#/lib/Graph.ts";
export type SceneData = {
name: string;
@@ -121,7 +121,7 @@ function linkScenes(a: string, b: string): void {
}
}
export function useScene(data: SceneData): {
export function defineScene(data: SceneData): {
linkScenes: <T extends readonly string[]>(
names: T,
) => (name: T[number]) => Promise<void>;