From bfb4979c6b132ac99015730e26e5f59a982b1a73 Mon Sep 17 00:00:00 2001 From: Pabloader Date: Sat, 9 May 2026 18:53:21 +0000 Subject: [PATCH] Fix bnario --- src/games/binario/game.ts | 9 +++--- src/games/binario/graphics.ts | 52 ++++++++++++++++++----------------- src/games/binario/renderer.ts | 2 +- src/games/binario/utils.ts | 50 +++++++++++++++++++++------------ src/games/binario/world.ts | 13 +++++---- 5 files changed, 73 insertions(+), 53 deletions(-) diff --git a/src/games/binario/game.ts b/src/games/binario/game.ts index 215a37f..274dc02 100644 --- a/src/games/binario/game.ts +++ b/src/games/binario/game.ts @@ -3,6 +3,7 @@ import UI from "./ui"; import World from "./world"; import { pointsEquals } from "./utils"; import { prevent } from "@common/utils"; +import { type Point } from "@common/geometry"; export default class Binario { private running = false; @@ -52,7 +53,7 @@ export default class Binario { scale = 1 / 1.1; } - this.graphics.applyScale(scale, [event.clientX, event.clientY]); + this.graphics.applyScale(scale, { x: event.clientX, y: event.clientY }); event.preventDefault(); } @@ -66,7 +67,7 @@ export default class Binario { this.canvas.style.cursor = 'default'; this.mouseDown = false; this.prevWorldPos = null; - const mousePos: Point = [event.clientX, event.clientY]; + const mousePos: Point = { x: event.clientX, y: event.clientY }; const worldPos = this.graphics.screenToWorld(mousePos); if (event.button === 0 && this.ui.selectedTool.tileType != null) { @@ -79,8 +80,8 @@ export default class Binario { } private onMouseMove = (event: MouseEvent) => { - const mousePos: Point = [event.clientX, event.clientY]; - const mouseDelta: Point = [event.movementX, event.movementY]; + const mousePos: Point = { x: event.clientX, y: event.clientY }; + const mouseDelta: Point = { x: event.movementX, y: event.movementY }; const worldPos = this.graphics.screenToWorld(mousePos); if (this.mouseDown === 1) { diff --git a/src/games/binario/graphics.ts b/src/games/binario/graphics.ts index d3f58c0..7873a64 100644 --- a/src/games/binario/graphics.ts +++ b/src/games/binario/graphics.ts @@ -2,14 +2,15 @@ import { defaultRenderer, renderPorts, renderResource, renderers, type NullRende import { ALL_DIRECTIONS, Direction, exp, trunc } from "./utils"; import type World from "./world"; import { type Tile } from "./world"; +import { type Point, type Rect } from "@common/geometry"; const initialTileSize = 32; export default class Graphics { private context: CanvasRenderingContext2D; private tileSize = initialTileSize; - private offset: Point = [0, 0]; - private highlighted: Point = [0, 0]; + private offset: Point = { x: 0, y: 0 }; + private highlighted: Point = { x: 0, y: 0 }; private tooltip: [Point, string] | null = null; constructor(private canvas: HTMLCanvasElement) { @@ -25,7 +26,7 @@ export default class Graphics { } get size(): Point { - return [this.canvas.width, this.canvas.height]; + return { x: this.canvas.width, y: this.canvas.height }; } applyScale(scale: number, point: Point) { @@ -93,16 +94,15 @@ export default class Graphics { } this.context.fillStyle = 'white'; - this.context.fillRect(...pos, maxWidth + 10, maxHeight + 3); + this.context.fillRect(pos.x, pos.y, maxWidth + 10, maxHeight + 3); this.context.strokeStyle = 'black'; - this.context.strokeRect(...pos, maxWidth + 10, maxHeight + 3); + this.context.strokeRect(pos.x, pos.y, maxWidth + 10, maxHeight + 3); this.context.font = '16px'; this.context.fillStyle = 'black'; - let y = pos[1] + 18; + let y = pos.y + 18; for (const line of lines) { - const measure = this.context.measureText(line); - this.context.fillText(line, pos[0] + 5, y); + this.context.fillText(line, pos.x + 5, y); y += 18; } this.context.restore(); @@ -112,15 +112,15 @@ export default class Graphics { drawGrid() { this.context.beginPath(); this.context.strokeStyle = 'gray'; - let [x0, y0, x1, y1] = this.visibleWorld; - [x0, y0] = this.worldToScreen([x0, y0]); - [x1, y1] = this.worldToScreen([x1, y1]); + const vw = this.visibleWorld; + const topLeft = this.worldToScreen({ x: vw.x, y: vw.y }); + const bottomRight = this.worldToScreen({ x: vw.x + vw.width, y: vw.y + vw.height }); - for (let x = x0; x < x1; x += this.tileSize) { + for (let x = topLeft.x; x < bottomRight.x; x += this.tileSize) { this.context.moveTo(x, 0); this.context.lineTo(x, this.height); } - for (let y = y0; y < y1; y += this.tileSize) { + for (let y = topLeft.y; y < bottomRight.y; y += this.tileSize) { this.context.moveTo(0, y); this.context.lineTo(this.width, y); } @@ -144,7 +144,7 @@ export default class Graphics { // TODO skip drawing if outside screen const screenPosition = this.worldToScreen(trunc(position)); - this.context.translate(screenPosition[0], screenPosition[1]); + this.context.translate(screenPosition.x, screenPosition.y); this.context.scale(this.tileSize, this.tileSize); if (tile) { @@ -160,11 +160,12 @@ export default class Graphics { } drawWorld(world: World) { - const [x0, y0, x1, y1] = this.visibleWorld; + const vw = this.visibleWorld; + const x0 = vw.x, y0 = vw.y, x1 = vw.x + vw.width, y1 = vw.y + vw.height; const resourceTiles: [Point, Tile][] = []; for (let y = y0; y <= y1; y++) { for (let x = x0; x <= x1; x++) { - const pos: Point = [x, y]; + const pos: Point = { x, y }; const tile = world.getTile(pos); if (tile) { let renderer = renderers[tile.type] as Renderer; @@ -186,20 +187,21 @@ export default class Graphics { } get visibleWorld(): Rect { - const [x0, y0] = this.screenToWorld([0, 0]); - const [x1, y1] = this.screenToWorld([this.width, this.height]); - - return [Math.floor(x0), Math.floor(y0), Math.ceil(x1), Math.ceil(y1)]; + const p0 = this.screenToWorld({ x: 0, y: 0 }); + const p1 = this.screenToWorld({ x: this.width, y: this.height }); + const x0 = Math.floor(p0.x), y0 = Math.floor(p0.y); + const x1 = Math.ceil(p1.x), y1 = Math.ceil(p1.y); + return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 }; } worldToScreen(point: Point): Point { - return [ - point[0] * this.tileSize + this.offset[0], - point[1] * this.tileSize + this.offset[1], - ]; + return { + x: point.x * this.tileSize + this.offset.x, + y: point.y * this.tileSize + this.offset.y, + }; } screenToWorld(point: Point): Point { return exp`(${point} - ${this.offset}) / ${this.tileSize}`; } -} \ No newline at end of file +} diff --git a/src/games/binario/renderer.ts b/src/games/binario/renderer.ts index 80d6a2b..eb4f4f2 100644 --- a/src/games/binario/renderer.ts +++ b/src/games/binario/renderer.ts @@ -47,7 +47,7 @@ export const renderResource = (ctx: CanvasRenderingContext2D, view: ViewConfig, const [timer, timerMax] = tile.inputAnimations?.get(direction) ?? [0, 1]; const amount = timer / timerMax; - const [x, y] = movePoint([0.5, 0.52], direction, amount); + const { x, y } = movePoint({ x: 0.5, y: 0.52 }, direction, amount); ctx.strokeStyle = 'white'; ctx.lineWidth = px * 2; diff --git a/src/games/binario/utils.ts b/src/games/binario/utils.ts index a1e1f24..702769c 100644 --- a/src/games/binario/utils.ts +++ b/src/games/binario/utils.ts @@ -1,3 +1,5 @@ +import { type Point } from "@common/geometry"; + export enum Direction { NONE, NORTH, @@ -13,13 +15,20 @@ export function isDirection(obj: any): obj is Direction { type Operand = Point | number; type Operation = (a: number, b: number) => number; + +function isPoint(v: Operand): v is Point { + return typeof v === 'object'; +} + function op(a: Operand, b: Operand, fn: Operation): Operand { - const aArray = Array.isArray(a); - const bArray = Array.isArray(b); - if (aArray) { - return (bArray ? a.map((x, i) => fn(x, b[i])) : a.map((x) => fn(x, b))) as Point; + if (isPoint(a)) { + return isPoint(b) + ? { x: fn(a.x, b.x), y: fn(a.y, b.y) } + : { x: fn(a.x, b as number), y: fn(a.y, b as number) }; } - return (bArray ? b.map((x) => fn(a, x)) : fn(a, b)) as Point; + return isPoint(b) + ? { x: fn(a as number, b.x), y: fn(a as number, b.y) } + : fn(a as number, b as number); } const operations: Record = { @@ -99,14 +108,16 @@ export function exp(strings: TemplateStringsArray, ...args: Operand[]): Operand return calcStack[0]; } + export function trunc(input: Point): Point { - return op(input, 0, (x) => Math.floor(x)) as Point; + return { x: Math.floor(input.x), y: Math.floor(input.y) }; } + const EPS = 0.001; -export const pointsEquals = (a: Point, b: Point) => Math.abs(a[0] - b[0]) < EPS && Math.abs(a[1] - b[1]) < EPS; +export const pointsEquals = (a: Point, b: Point) => Math.abs(a.x - b.x) < EPS && Math.abs(a.y - b.y) < EPS; export const getDirection = (point: Point): Direction => { - const [x, y] = point; + const { x, y } = point; const absX = Math.abs(x); const absY = Math.abs(y); if (absX === 0 && absY === 0) return Direction.NONE; @@ -114,6 +125,7 @@ export const getDirection = (point: Point): Direction => { else if (absY > absX) return y < 0 ? Direction.NORTH : Direction.SOUTH; else return Direction.NONE; } + export const getOppositeDirection = (dir: Direction): Direction => { switch (dir) { case Direction.NORTH: return Direction.SOUTH; @@ -123,13 +135,15 @@ export const getOppositeDirection = (dir: Direction): Direction => { default: return Direction.NONE; } } + export const DIRECTION_VECTORS: Record = { - [Direction.NONE]: [0, 0], - [Direction.NORTH]: [0, -1], - [Direction.SOUTH]: [0, 1], - [Direction.WEST]: [-1, 0], - [Direction.EAST]: [1, 0], + [Direction.NONE]: { x: 0, y: 0 }, + [Direction.NORTH]: { x: 0, y: -1 }, + [Direction.SOUTH]: { x: 0, y: 1 }, + [Direction.WEST]: { x: -1, y: 0 }, + [Direction.EAST]: { x: 1, y: 0 }, }; + export const NEXT_DIRECTION: Record = { [Direction.NONE]: Direction.NONE, [Direction.NORTH]: Direction.EAST, @@ -137,8 +151,10 @@ export const NEXT_DIRECTION: Record = { [Direction.WEST]: Direction.NORTH, [Direction.EAST]: Direction.SOUTH, }; + export const ALL_DIRECTIONS = [Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST]; -export const movePoint = (point: Point, direction: Direction, scale: number = 1): Point => [ - point[0] + DIRECTION_VECTORS[direction][0] * scale, - point[1] + DIRECTION_VECTORS[direction][1] * scale, -]; \ No newline at end of file + +export const movePoint = (point: Point, direction: Direction, scale: number = 1): Point => ({ + x: point.x + DIRECTION_VECTORS[direction].x * scale, + y: point.y + DIRECTION_VECTORS[direction].y * scale, +}); diff --git a/src/games/binario/world.ts b/src/games/binario/world.ts index ed2edc3..b63829c 100644 --- a/src/games/binario/world.ts +++ b/src/games/binario/world.ts @@ -1,4 +1,5 @@ import { intHash } from "@common/utils"; +import { type Point } from "@common/geometry"; import { ALL_DIRECTIONS, Direction, NEXT_DIRECTION, exp, getDirection, getOppositeDirection, isDirection, movePoint, pointsEquals, trunc } from "./utils"; export enum TileType { @@ -110,8 +111,8 @@ interface TileBinaryLogic extends BaseTile { export type Tile = TileDestination | TileSource | TileExtractor | TileConveyor | TileUnaryLogic | TileBinaryLogic; -const id = (point: Point) => ((Math.floor(point[0]) & 0xFFFF) << 16) | Math.floor(point[1]) & 0xFFFF; -const deid = (pid: number): Point => [(pid >> 16) & 0xFFFF, pid & 0xFFFF]; +const id = (point: Point) => ((Math.floor(point.x) & 0xFFFF) << 16) | Math.floor(point.y) & 0xFFFF; +const deid = (pid: number): Point => ({ x: (pid >> 16) & 0xFFFF, y: pid & 0xFFFF }); const rid = (resource: Resource): number => { const idPart = (resource.type & 0xFFFF) << 16; @@ -196,7 +197,7 @@ export default class World { if (x == 0) ports[Direction.WEST] = { direction: PortDirection.INPUT }; if (x == 4) ports[Direction.EAST] = { direction: PortDirection.INPUT }; - this.setTile([x - 2, y - 2], { + this.setTile({ x: x - 2, y: y - 2 }, { type: TileType.DESTINATION, ports, center: x == 2 && y == 2, @@ -331,7 +332,7 @@ export default class World { } getTile(position: Point): Tile | null { - const [x, y] = position; + const { x, y } = position; const pid = id(position); const tile = this.world.get(pid); if (tile) return tile; @@ -344,11 +345,11 @@ export default class World { } private genTile(position: Point): Tile | null { - const hash = intHash(this.seed, ...position); + const hash = intHash(this.seed, position.x, position.y); if ([42, 69, 0x42, 0x69].includes(hash & 0xFF)) { let mask = 1; - const dist = Math.log10(Math.hypot(...position)); + const dist = Math.log10(Math.hypot(position.x, position.y)); for (let i = 1; i < dist; i++) { mask = (mask << 1) | 1; }