151 lines
4.6 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|
|
|