Back to Browser Side Quest
SOURCE / PINNED RELEASE

Made of little things.

Browser Side Quest

Release
b9d42f5768e4…
Author-recorded commit
c267690145fa…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.shakespeare.diy%2F/browser-side-quest

Archive hash verified: 6d4b90b8a5f328f7…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/client/camera.ts
// Port of BrowserQuest client/js/camera.js (MPL-2.0).
// gridW/gridH come from the renderer's frame fit instead of the fixed 15x7 / 30x14.
import type { Entity } from './entity.js';

export class Camera {
  x = 0;
  y = 0;
  gridX = 0;
  gridY = 0;

  constructor(
    public gridW: number,
    public gridH: number,
  ) {}

  setPosition(x: number, y: number): void {
    this.x = x;
    this.y = y;
    this.gridX = Math.floor(x / 16);
    this.gridY = Math.floor(y / 16);
  }

  setGridPosition(x: number, y: number): void {
    this.gridX = x;
    this.gridY = y;
    this.x = x * 16;
    this.y = y * 16;
  }

  lookAt(entity: Entity): void {
    const x = Math.round(entity.x - Math.floor(this.gridW / 2) * 16);
    const y = Math.round(entity.y - Math.floor(this.gridH / 2) * 16);
    this.setPosition(x, y);
  }

  forEachVisiblePosition(callback: (x: number, y: number) => void, extra = 0): void {
    const maxY = this.gridY + this.gridH + extra * 2;
    const maxX = this.gridX + this.gridW + extra * 2;
    for (let y = this.gridY - extra; y < maxY; y += 1) {
      for (let x = this.gridX - extra; x < maxX; x += 1) callback(x, y);
    }
  }

  isVisible(entity: Entity): boolean {
    return this.isVisiblePosition(entity.gridX, entity.gridY);
  }

  isVisiblePosition(x: number, y: number): boolean {
    return y >= this.gridY && y < this.gridY + this.gridH && x >= this.gridX && x < this.gridX + this.gridW;
  }

  /** Snap the view by whole screens, keeping a one-tile overlap on each edge. */
  focusEntity(entity: Entity): void {
    const w = this.gridW - 2;
    const h = this.gridH - 2;
    const x = Math.floor((entity.gridX - 1) / w) * w;
    const y = Math.floor((entity.gridY - 1) / h) * h;
    this.setGridPosition(x, y);
  }
}