1
0
Fork 0
tsgames/src/games/binario/game.ts

151 lines
4.6 KiB
TypeScript

import Graphics from "./graphics";
import UI from "./ui";
import World from "./world";
import { pointsEquals, prevent } from "./utils";
export default class Binario implements IGame {
private running = false;
private mouseDown: false | number = false;
private graphics;
private world;
private ui;
private prevWorldPos: Point | null = null;
private prevFrame: number = performance.now();
private paused = false;
constructor(private canvas: HTMLCanvasElement) {
canvas.focus();
canvas.addEventListener('wheel', this.onScroll);
canvas.addEventListener('mousedown', this.onMouseDown);
canvas.addEventListener('mousemove', this.onMouseMove);
canvas.addEventListener('mouseup', this.onMouseUp);
document.addEventListener('keypress', this.onKeyPress);
document.addEventListener('contextmenu', prevent);
document.addEventListener('select', prevent);
document.addEventListener('selectstart', prevent);
this.graphics = new Graphics(canvas);
this.world = new World();
this.ui = new UI();
window.addEventListener('resize', this.onResize);
this.onResize();
this.graphics.resetView();
}
private onResize = () => {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.graphics.resetStyle();
}
private onScroll = (event: WheelEvent) => {
const direction = event.deltaY / Math.abs(event.deltaY);
let scale = 1;
if (direction < 0) {
scale = 1.1;
} else if (direction > 0) {
scale = 1 / 1.1;
}
this.graphics.applyScale(scale, [event.clientX, event.clientY]);
event.preventDefault();
}
private onMouseDown = (event: MouseEvent) => {
this.mouseDown = event.button;
event.preventDefault();
}
private onMouseUp = (event: MouseEvent) => {
this.canvas.style.cursor = 'default';
this.mouseDown = false;
this.prevWorldPos = null;
const mousePos: Point = [event.clientX, event.clientY];
const worldPos = this.graphics.screenToWorld(mousePos);
if (event.button === 0 && this.ui.selectedTool.tileType != null) {
const tileType = this.ui.selectedTool.tileType;
this.world.placeTile(worldPos, tileType);
} else if (event.button === 2) {
this.world.removeTile(worldPos);
}
event.preventDefault();
}
private onMouseMove = (event: MouseEvent) => {
const mousePos: Point = [event.clientX, event.clientY];
const mouseDelta: Point = [event.movementX, event.movementY];
const worldPos = this.graphics.screenToWorld(mousePos);
if (this.mouseDown === 1) {
this.canvas.style.cursor = 'grabbing';
this.graphics.pan(mouseDelta);
} else if (this.mouseDown === 0 && this.ui.selectedTool.tileType != null) {
const tileType = this.ui.selectedTool.tileType;
this.world.placeTile(worldPos, tileType, this.prevWorldPos);
} else if (this.mouseDown === 2) {
this.world.removeTile(worldPos);
}
if (!this.prevWorldPos || !pointsEquals(this.prevWorldPos, worldPos)) {
this.prevWorldPos = worldPos;
}
this.graphics.highlight(mousePos);
const tile = this.world.getTile(worldPos);
if (tile) {
this.graphics.showTooltip(mousePos, JSON.stringify(tile, null, 2));
} else {
this.graphics.showTooltip(mousePos, '');
}
event.preventDefault();
}
private onKeyPress = (event: KeyboardEvent) => {
const key = event.key.toLowerCase();
if (key === 'h') {
this.graphics.resetView();
} else if (key === ' ') {
this.paused = !this.paused;
} else if (key.length === 1 && key >= '1' && key <= '9') {
const slot = parseInt(key);
this.ui.useSlot(slot);
} else {
console.log(`Pressed: ${key}`);
}
}
run() {
this.running = true;
this.loop();
}
private loop = () => {
const now = performance.now();
const dt = now - this.prevFrame;
this.prevFrame = now;
if (!this.paused) {
this.world.update(dt);
}
this.graphics.clear();
this.graphics.drawGrid();
this.graphics.drawWorld(this.world);
this.graphics.drawHighlight();
this.graphics.drawTooltip();
this.graphics.debug();
if (this.running) {
requestAnimationFrame(this.loop);
}
}
}