Run prettier over everything
This commit is contained in:
@ -17,11 +17,13 @@ export class Color {
|
||||
}
|
||||
|
||||
static parseHexCode(hexCode: string) {
|
||||
const regex1 = /#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})?/;
|
||||
const regex2 = /#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})?/;
|
||||
const regex1 =
|
||||
/#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})?/;
|
||||
const regex2 =
|
||||
/#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})?/;
|
||||
let result = regex1.exec(hexCode) ?? regex2.exec(hexCode);
|
||||
if (result == null) {
|
||||
throw `could not parse color: ${hexCode}`
|
||||
throw `could not parse color: ${hexCode}`;
|
||||
}
|
||||
|
||||
let parseGroup = (s: string | undefined): number => {
|
||||
@ -32,7 +34,7 @@ export class Color {
|
||||
return 17 * parseInt(s, 16);
|
||||
}
|
||||
return parseInt(s, 16);
|
||||
}
|
||||
};
|
||||
return new Color(
|
||||
parseGroup(result[1]),
|
||||
parseGroup(result[2]),
|
||||
@ -42,7 +44,7 @@ export class Color {
|
||||
}
|
||||
|
||||
toStyle(): string {
|
||||
return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a / 255.0})`
|
||||
return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a / 255.0})`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +58,7 @@ export class Point {
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.x},${this.y}`
|
||||
return `${this.x},${this.y}`;
|
||||
}
|
||||
|
||||
offset(other: Point | Size): Point {
|
||||
@ -109,7 +111,7 @@ export class Size {
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.w}x${this.h}`
|
||||
return `${this.w}x${this.h}`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +129,12 @@ export class Rect {
|
||||
}
|
||||
|
||||
contains(other: Point) {
|
||||
return (other.x >= this.top.x && other.y >= this.top.y && other.x < this.top.x + this.size.w && other.y < this.top.y + this.size.h);
|
||||
return (
|
||||
other.x >= this.top.x &&
|
||||
other.y >= this.top.y &&
|
||||
other.x < this.top.x + this.size.w &&
|
||||
other.y < this.top.y + this.size.h
|
||||
);
|
||||
}
|
||||
|
||||
overlaps(other: Rect) {
|
||||
@ -156,20 +163,20 @@ export class Grid<T> {
|
||||
for (let y = 0; y < size.h; y++) {
|
||||
let row = [];
|
||||
for (let x = 0; x < size.w; x++) {
|
||||
row.push(cbDefault(new Point(x, y)))
|
||||
row.push(cbDefault(new Point(x, y)));
|
||||
}
|
||||
this.#data.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
static createGridFromMultilineString(multiline: string): Grid<string> {
|
||||
let lines = []
|
||||
let lines = [];
|
||||
for (let line of multiline.split("\n")) {
|
||||
let trimmedLine = line.trim();
|
||||
if (trimmedLine == "") {
|
||||
continue;
|
||||
}
|
||||
lines.push(trimmedLine)
|
||||
lines.push(trimmedLine);
|
||||
}
|
||||
return this.createGridFromStringArray(lines);
|
||||
}
|
||||
@ -181,17 +188,14 @@ export class Grid<T> {
|
||||
let w1 = ary[i].length;
|
||||
let w2 = ary[i + 1].length;
|
||||
if (w1 != w2) {
|
||||
throw `createGridFromStringArray: must be grid-shaped, got ${ary}`
|
||||
throw `createGridFromStringArray: must be grid-shaped, got ${ary}`;
|
||||
}
|
||||
w = w1;
|
||||
}
|
||||
|
||||
return new Grid(
|
||||
new Size(w, h),
|
||||
(xy) => {
|
||||
return ary[xy.y].charAt(xy.x);
|
||||
}
|
||||
)
|
||||
return new Grid(new Size(w, h), (xy) => {
|
||||
return ary[xy.y].charAt(xy.x);
|
||||
});
|
||||
}
|
||||
|
||||
static createGridFromJaggedArray<T>(ary: Array<Array<T>>): Grid<T> {
|
||||
@ -201,17 +205,14 @@ export class Grid<T> {
|
||||
let w1 = ary[i].length;
|
||||
let w2 = ary[i + 1].length;
|
||||
if (w1 != w2) {
|
||||
throw `createGridFromJaggedArray: must be grid-shaped, got ${ary}`
|
||||
throw `createGridFromJaggedArray: must be grid-shaped, got ${ary}`;
|
||||
}
|
||||
w = w1;
|
||||
}
|
||||
|
||||
return new Grid(
|
||||
new Size(w, h),
|
||||
(xy) => {
|
||||
return ary[xy.y][xy.x];
|
||||
}
|
||||
)
|
||||
return new Grid(new Size(w, h), (xy) => {
|
||||
return ary[xy.y][xy.x];
|
||||
});
|
||||
}
|
||||
|
||||
map<T2>(cbCell: (content: T, position: Point) => T2) {
|
||||
@ -220,10 +221,14 @@ export class Grid<T> {
|
||||
|
||||
#checkPosition(position: Point) {
|
||||
if (
|
||||
(position.x < 0 || position.x >= this.size.w || Math.floor(position.x) != position.x) ||
|
||||
(position.y < 0 || position.y >= this.size.h || Math.floor(position.y) != position.y)
|
||||
position.x < 0 ||
|
||||
position.x >= this.size.w ||
|
||||
Math.floor(position.x) != position.x ||
|
||||
position.y < 0 ||
|
||||
position.y >= this.size.h ||
|
||||
Math.floor(position.y) != position.y
|
||||
) {
|
||||
throw new Error(`invalid position for ${this.size}: ${position}`)
|
||||
throw new Error(`invalid position for ${this.size}: ${position}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +246,7 @@ export class Grid<T> {
|
||||
export enum AlignX {
|
||||
Left = 0,
|
||||
Center = 1,
|
||||
Right = 2
|
||||
Right = 2,
|
||||
}
|
||||
|
||||
export enum AlignY {
|
||||
|
@ -13,7 +13,7 @@ class Assets {
|
||||
// and then wait for isLoaded to return true)
|
||||
for (let filename in this.#images) {
|
||||
if (!this.#images[filename].complete) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ class Assets {
|
||||
element.src = filename;
|
||||
this.#images[filename] = element;
|
||||
}
|
||||
return element
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,4 +38,3 @@ let active: Assets = new Assets();
|
||||
export function getAssets(): Assets {
|
||||
return active;
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,17 @@
|
||||
const MAX_UPDATES_BANKED: number = 20.0;
|
||||
|
||||
// always run physics at 240 hz
|
||||
const UPDATES_PER_MS: number = 1/(1000.0/240.0);
|
||||
const UPDATES_PER_MS: number = 1 / (1000.0 / 240.0);
|
||||
|
||||
class Clock {
|
||||
#lastTimestamp: number | undefined;
|
||||
#updatesBanked: number
|
||||
#updatesBanked: number;
|
||||
|
||||
constructor() {
|
||||
this.#lastTimestamp = undefined;
|
||||
this.#updatesBanked = 0.0
|
||||
this.#updatesBanked = 0.0;
|
||||
}
|
||||
|
||||
|
||||
recordTimestamp(timestamp: number) {
|
||||
if (this.#lastTimestamp) {
|
||||
let delta = timestamp - this.#lastTimestamp;
|
||||
@ -26,7 +25,7 @@ class Clock {
|
||||
// and remove one draw from the bank
|
||||
if (this.#updatesBanked > 1) {
|
||||
this.#updatesBanked -= 1;
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -40,5 +39,3 @@ let active: Clock = new Clock();
|
||||
export function getClock(): Clock {
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {getScreen} from "./screen.ts";
|
||||
import {AlignX, AlignY, Color, Point, Size} from "../datatypes.ts";
|
||||
import {mainFont} from "./font.ts";
|
||||
import {Sprite} from "./sprite.ts";
|
||||
import { getScreen } from "./screen.ts";
|
||||
import { AlignX, AlignY, Color, Point, Size } from "../datatypes.ts";
|
||||
import { mainFont } from "./font.ts";
|
||||
import { Sprite } from "./sprite.ts";
|
||||
|
||||
class Drawing {
|
||||
camera: Point;
|
||||
@ -19,7 +19,9 @@ class Drawing {
|
||||
this.camera = oldCamera;
|
||||
}
|
||||
|
||||
get size() { return getScreen().size; }
|
||||
get size() {
|
||||
return getScreen().size;
|
||||
}
|
||||
|
||||
invertRect(position: Point, size: Size) {
|
||||
position = this.camera.negate().offset(position);
|
||||
@ -31,8 +33,8 @@ class Drawing {
|
||||
Math.floor(position.x),
|
||||
Math.floor(position.y),
|
||||
Math.floor(size.w),
|
||||
Math.floor(size.h)
|
||||
)
|
||||
Math.floor(size.h),
|
||||
);
|
||||
}
|
||||
|
||||
fillRect(position: Point, size: Size, color: Color) {
|
||||
@ -44,7 +46,7 @@ class Drawing {
|
||||
Math.floor(position.x),
|
||||
Math.floor(position.y),
|
||||
Math.floor(size.w),
|
||||
Math.floor(size.h)
|
||||
Math.floor(size.h),
|
||||
);
|
||||
}
|
||||
|
||||
@ -57,11 +59,16 @@ class Drawing {
|
||||
Math.floor(position.x) + 0.5,
|
||||
Math.floor(position.y) + 0.5,
|
||||
Math.floor(size.w) - 1,
|
||||
Math.floor(size.h) - 1
|
||||
)
|
||||
Math.floor(size.h) - 1,
|
||||
);
|
||||
}
|
||||
|
||||
drawText(text: string, position: Point, color: Color, options?: {alignX?: AlignX, alignY?: AlignY, forceWidth?: number}) {
|
||||
drawText(
|
||||
text: string,
|
||||
position: Point,
|
||||
color: Color,
|
||||
options?: { alignX?: AlignX; alignY?: AlignY; forceWidth?: number },
|
||||
) {
|
||||
position = this.camera.negate().offset(position);
|
||||
|
||||
let ctx = getScreen().unsafeMakeContext();
|
||||
@ -72,19 +79,30 @@ class Drawing {
|
||||
alignX: options?.alignX,
|
||||
alignY: options?.alignY,
|
||||
forceWidth: options?.forceWidth,
|
||||
color
|
||||
})
|
||||
color,
|
||||
});
|
||||
}
|
||||
|
||||
measureText(text: string, forceWidth?: number): Size {
|
||||
return mainFont.measureText({text, forceWidth})
|
||||
return mainFont.measureText({ text, forceWidth });
|
||||
}
|
||||
|
||||
drawSprite(sprite: Sprite, position: Point, ix?: number, options?: {xScale?: number, yScale: number, angle?: number}) {
|
||||
drawSprite(
|
||||
sprite: Sprite,
|
||||
position: Point,
|
||||
ix?: number,
|
||||
options?: { xScale?: number; yScale: number; angle?: number },
|
||||
) {
|
||||
position = this.camera.negate().offset(position);
|
||||
|
||||
let ctx = getScreen().unsafeMakeContext();
|
||||
sprite.internalDraw(ctx, {position, ix, xScale: options?.xScale, yScale: options?.yScale, angle: options?.angle})
|
||||
sprite.internalDraw(ctx, {
|
||||
position,
|
||||
ix,
|
||||
xScale: options?.xScale,
|
||||
yScale: options?.yScale,
|
||||
angle: options?.angle,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,5 +111,3 @@ let active: Drawing = new Drawing();
|
||||
export function getDrawing(): Drawing {
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {getAssets} from "./assets.ts";
|
||||
import fontSheet from '../../art/fonts/vga_8x16.png';
|
||||
import {AlignX, AlignY, Color, Point, Size} from "../datatypes.ts";
|
||||
import { getAssets } from "./assets.ts";
|
||||
import fontSheet from "../../art/fonts/vga_8x16.png";
|
||||
import { AlignX, AlignY, Color, Point, Size } from "../datatypes.ts";
|
||||
|
||||
class Font {
|
||||
#filename: string;
|
||||
@ -14,18 +14,28 @@ class Font {
|
||||
this.#cellsPerSheet = cellsPerSheet;
|
||||
this.#pixelsPerCell = pixelsPerCell;
|
||||
this.#tintingCanvas = document.createElement("canvas");
|
||||
this.#tintedVersions = {}
|
||||
this.#tintedVersions = {};
|
||||
}
|
||||
|
||||
get #cx(): number { return this.#cellsPerSheet.w }
|
||||
get #cy(): number { return this.#cellsPerSheet.h }
|
||||
get #px(): number { return this.#pixelsPerCell.w }
|
||||
get #py(): number { return this.#pixelsPerCell.h }
|
||||
get #cx(): number {
|
||||
return this.#cellsPerSheet.w;
|
||||
}
|
||||
get #cy(): number {
|
||||
return this.#cellsPerSheet.h;
|
||||
}
|
||||
get #px(): number {
|
||||
return this.#pixelsPerCell.w;
|
||||
}
|
||||
get #py(): number {
|
||||
return this.#pixelsPerCell.h;
|
||||
}
|
||||
|
||||
#getTintedImage(color: string): HTMLImageElement | null {
|
||||
let image = getAssets().getImage(this.#filename);
|
||||
|
||||
if (!image.complete) { return null; }
|
||||
if (!image.complete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let tintedVersion = this.#tintedVersions[color];
|
||||
if (tintedVersion != undefined) {
|
||||
@ -36,7 +46,7 @@ class Font {
|
||||
let h = image.height;
|
||||
|
||||
if (!(w == this.#cx * this.#px && h == this.#cy * this.#py)) {
|
||||
throw `unexpected image dimensions for font ${this.#filename}: ${w} x ${h}`
|
||||
throw `unexpected image dimensions for font ${this.#filename}: ${w} x ${h}`;
|
||||
}
|
||||
|
||||
this.#tintingCanvas.width = w;
|
||||
@ -55,17 +65,28 @@ class Font {
|
||||
return result;
|
||||
}
|
||||
|
||||
internalDrawText({ctx, text, position, alignX, alignY, forceWidth, color}: {
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
position: Point, alignX?: AlignX, alignY?: AlignY,
|
||||
forceWidth?: number, color: Color
|
||||
internalDrawText({
|
||||
ctx,
|
||||
text,
|
||||
position,
|
||||
alignX,
|
||||
alignY,
|
||||
forceWidth,
|
||||
color,
|
||||
}: {
|
||||
ctx: CanvasRenderingContext2D;
|
||||
text: string;
|
||||
position: Point;
|
||||
alignX?: AlignX;
|
||||
alignY?: AlignY;
|
||||
forceWidth?: number;
|
||||
color: Color;
|
||||
}) {
|
||||
alignX = alignX == undefined ? AlignX.Left : alignX;
|
||||
alignY = alignY == undefined ? AlignY.Top : alignY;
|
||||
forceWidth = forceWidth == undefined ? 65535 : forceWidth;
|
||||
|
||||
let image = this.#getTintedImage(color.toStyle())
|
||||
let image = this.#getTintedImage(color.toStyle());
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
@ -73,43 +94,80 @@ class Font {
|
||||
let sz = this.#glyphwise(text, forceWidth, () => {});
|
||||
let offsetX = position.x;
|
||||
let offsetY = position.y;
|
||||
offsetX += (alignX == AlignX.Left ? 0 : alignX == AlignX.Center ? -sz.w / 2 : - sz.w)
|
||||
offsetY += (alignY == AlignY.Top ? 0 : alignY == AlignY.Middle ? -sz.h / 2 : - sz.h)
|
||||
offsetX +=
|
||||
alignX == AlignX.Left ? 0 : alignX == AlignX.Center ? -sz.w / 2 : -sz.w;
|
||||
offsetY +=
|
||||
alignY == AlignY.Top ? 0 : alignY == AlignY.Middle ? -sz.h / 2 : -sz.h;
|
||||
|
||||
this.#glyphwise(text, forceWidth, (cx, cy, char) => {
|
||||
let srcIx = char.charCodeAt(0);
|
||||
this.#drawGlyph({ctx: ctx, image: image, ix: srcIx, x: offsetX + cx * this.#px, y: offsetY + cy * this.#py});
|
||||
})
|
||||
this.#drawGlyph({
|
||||
ctx: ctx,
|
||||
image: image,
|
||||
ix: srcIx,
|
||||
x: offsetX + cx * this.#px,
|
||||
y: offsetY + cy * this.#py,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#drawGlyph({ctx, image, ix, x, y}: {ctx: CanvasRenderingContext2D, image: HTMLImageElement, ix: number, x: number, y: number}) {
|
||||
#drawGlyph({
|
||||
ctx,
|
||||
image,
|
||||
ix,
|
||||
x,
|
||||
y,
|
||||
}: {
|
||||
ctx: CanvasRenderingContext2D;
|
||||
image: HTMLImageElement;
|
||||
ix: number;
|
||||
x: number;
|
||||
y: number;
|
||||
}) {
|
||||
let srcCx = ix % this.#cx;
|
||||
let srcCy = Math.floor(ix / this.#cx);
|
||||
let srcPx = srcCx * this.#px;
|
||||
let srcPy = srcCy * this.#py;
|
||||
ctx.drawImage(
|
||||
image,
|
||||
srcPx, srcPy, this.#px, this.#py,
|
||||
Math.floor(x), Math.floor(y), this.#px, this.#py
|
||||
srcPx,
|
||||
srcPy,
|
||||
this.#px,
|
||||
this.#py,
|
||||
Math.floor(x),
|
||||
Math.floor(y),
|
||||
this.#px,
|
||||
this.#py,
|
||||
);
|
||||
}
|
||||
|
||||
measureText({text, forceWidth}: {text: string, forceWidth?: number}): Size {
|
||||
measureText({
|
||||
text,
|
||||
forceWidth,
|
||||
}: {
|
||||
text: string;
|
||||
forceWidth?: number;
|
||||
}): Size {
|
||||
return this.#glyphwise(text, forceWidth, () => {});
|
||||
}
|
||||
|
||||
#glyphwise(text: string, forceWidth: number | undefined, callback: (x: number, y: number, char: string) => void): Size {
|
||||
#glyphwise(
|
||||
text: string,
|
||||
forceWidth: number | undefined,
|
||||
callback: (x: number, y: number, char: string) => void,
|
||||
): Size {
|
||||
let cx = 0;
|
||||
let cy = 0;
|
||||
let cw = 0;
|
||||
let ch = 0;
|
||||
let wcx = forceWidth == undefined ? undefined : Math.floor(forceWidth / this.#px);
|
||||
let wcx =
|
||||
forceWidth == undefined ? undefined : Math.floor(forceWidth / this.#px);
|
||||
|
||||
text = betterWordWrap(text, wcx);
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
let char = text[i]
|
||||
if (char == '\n') {
|
||||
let char = text[i];
|
||||
if (char == "\n") {
|
||||
cx = 0;
|
||||
cy += 1;
|
||||
ch = cy + 1;
|
||||
@ -121,7 +179,7 @@ class Font {
|
||||
ch = cy + 1;
|
||||
}
|
||||
|
||||
callback(cx, cy, char)
|
||||
callback(cx, cy, char);
|
||||
cx += 1;
|
||||
cw = Math.max(cw, cx);
|
||||
ch = cy + 1;
|
||||
@ -132,15 +190,15 @@ class Font {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// https://stackoverflow.com/users/1993501/edi9999
|
||||
function betterWordWrap(s: string, wcx?: number) {
|
||||
if (wcx === undefined) {
|
||||
return s;
|
||||
}
|
||||
return s.replace(
|
||||
new RegExp(`(?![^\\n]{1,${wcx}}$)([^\\n]{1,${wcx}})\\s`, 'g'), '$1\n'
|
||||
new RegExp(`(?![^\\n]{1,${wcx}}$)([^\\n]{1,${wcx}})\\s`, "g"),
|
||||
"$1\n",
|
||||
);
|
||||
}
|
||||
|
||||
export let mainFont = new Font(fontSheet, new Size(32, 8), new Size(8, 16));
|
||||
export let mainFont = new Font(fontSheet, new Size(32, 8), new Size(8, 16));
|
||||
|
@ -1,14 +1,14 @@
|
||||
import './style.css'
|
||||
import "./style.css";
|
||||
|
||||
import {pollAndTouch} from "./screen.ts";
|
||||
import {getClock} from "./clock.ts";
|
||||
import {getInput, setupInput} from "./input.ts";
|
||||
import {IGame} from "../datatypes.ts";
|
||||
import { pollAndTouch } from "./screen.ts";
|
||||
import { getClock } from "./clock.ts";
|
||||
import { getInput, setupInput } from "./input.ts";
|
||||
import { IGame } from "../datatypes.ts";
|
||||
|
||||
export function hostGame(game: IGame) {
|
||||
let gameCanvas = document.getElementById("game") as HTMLCanvasElement;
|
||||
setupInput(gameCanvas);
|
||||
onFrame(game, undefined); // start on-frame draw loop, set up screen
|
||||
onFrame(game, undefined); // start on-frame draw loop, set up screen
|
||||
}
|
||||
|
||||
function onFrame(game: IGame, timestamp: number | undefined) {
|
||||
@ -31,4 +31,3 @@ function onFrame(game: IGame, timestamp: number | undefined) {
|
||||
function onFrameFixScreen(canvas: HTMLCanvasElement) {
|
||||
pollAndTouch(canvas);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {getScreen} from "./screen.ts";
|
||||
import {Point} from "../datatypes.ts";
|
||||
import { getScreen } from "./screen.ts";
|
||||
import { Point } from "../datatypes.ts";
|
||||
|
||||
function handleKey(e: KeyboardEvent, down: boolean) {
|
||||
active.handleKeyDown(e.key, down);
|
||||
@ -12,25 +12,31 @@ function handleMouseMove(canvas: HTMLCanvasElement, m: MouseEvent) {
|
||||
if (canvas.offsetWidth == 0 || canvas.offsetHeight == 0) {
|
||||
return;
|
||||
}
|
||||
active.handleMouseMove(m.offsetX / canvas.offsetWidth, m.offsetY / canvas.offsetHeight);
|
||||
active.handleMouseMove(
|
||||
m.offsetX / canvas.offsetWidth,
|
||||
m.offsetY / canvas.offsetHeight,
|
||||
);
|
||||
}
|
||||
|
||||
function handleMouseButton(canvas: HTMLCanvasElement, m: MouseEvent, down: boolean) {
|
||||
function handleMouseButton(
|
||||
canvas: HTMLCanvasElement,
|
||||
m: MouseEvent,
|
||||
down: boolean,
|
||||
) {
|
||||
if (canvas.offsetWidth == 0 || canvas.offsetHeight == 0) {
|
||||
return;
|
||||
}
|
||||
active.handleMouseMove(m.offsetX / canvas.offsetWidth, m.offsetY / canvas.offsetHeight);
|
||||
let button: MouseButton | null = (
|
||||
m.button == 0 ? "leftMouse" :
|
||||
m.button == 1 ? "rightMouse" :
|
||||
null
|
||||
)
|
||||
active.handleMouseMove(
|
||||
m.offsetX / canvas.offsetWidth,
|
||||
m.offsetY / canvas.offsetHeight,
|
||||
);
|
||||
let button: MouseButton | null =
|
||||
m.button == 0 ? "leftMouse" : m.button == 1 ? "rightMouse" : null;
|
||||
if (button != null) {
|
||||
active.handleMouseDown(button, down);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function setupInput(canvas: HTMLCanvasElement) {
|
||||
canvas.addEventListener("keyup", (k) => handleKey(k, false));
|
||||
document.addEventListener("keyup", (k) => handleKey(k, false));
|
||||
@ -38,8 +44,12 @@ export function setupInput(canvas: HTMLCanvasElement) {
|
||||
document.addEventListener("keydown", (k) => handleKey(k, true));
|
||||
canvas.addEventListener("mouseout", (_) => handleMouseOut());
|
||||
canvas.addEventListener("mousemove", (m) => handleMouseMove(canvas, m));
|
||||
canvas.addEventListener("mousedown", (m) => handleMouseButton(canvas, m, true));
|
||||
canvas.addEventListener("mouseup", (m) => handleMouseButton(canvas, m, false));
|
||||
canvas.addEventListener("mousedown", (m) =>
|
||||
handleMouseButton(canvas, m, true),
|
||||
);
|
||||
canvas.addEventListener("mouseup", (m) =>
|
||||
handleMouseButton(canvas, m, false),
|
||||
);
|
||||
}
|
||||
|
||||
export type MouseButton = "leftMouse" | "rightMouse";
|
||||
@ -60,8 +70,8 @@ class Input {
|
||||
}
|
||||
|
||||
update() {
|
||||
this.#previousKeyDown = {...this.#keyDown};
|
||||
this.#previousMouseDown = {...this.#mouseDown};
|
||||
this.#previousKeyDown = { ...this.#keyDown };
|
||||
this.#previousMouseDown = { ...this.#mouseDown };
|
||||
}
|
||||
|
||||
handleMouseDown(name: string, down: boolean) {
|
||||
@ -73,51 +83,56 @@ class Input {
|
||||
|
||||
handleMouseMove(x: number, y: number) {
|
||||
let screen = getScreen();
|
||||
if (x < 0.0 || x >= 1.0) { this.#mousePosition = null; }
|
||||
if (y < 0.0 || y >= 1.0) { this.#mousePosition = null; }
|
||||
if (x < 0.0 || x >= 1.0) {
|
||||
this.#mousePosition = null;
|
||||
}
|
||||
if (y < 0.0 || y >= 1.0) {
|
||||
this.#mousePosition = null;
|
||||
}
|
||||
|
||||
let w = screen.size.w;
|
||||
let h = screen.size.h;
|
||||
this.#mousePosition = new Point(
|
||||
Math.floor(x * w),
|
||||
Math.floor(y * h),
|
||||
)
|
||||
this.#mousePosition = new Point(Math.floor(x * w), Math.floor(y * h));
|
||||
}
|
||||
|
||||
isMouseDown(btn: MouseButton) : boolean {
|
||||
isMouseDown(btn: MouseButton): boolean {
|
||||
return this.#mouseDown[btn];
|
||||
}
|
||||
|
||||
isMouseClicked(btn: MouseButton) : boolean {
|
||||
isMouseClicked(btn: MouseButton): boolean {
|
||||
return this.#mouseDown[btn] && !this.#previousMouseDown[btn];
|
||||
}
|
||||
|
||||
isMouseReleased(btn: MouseButton) : boolean {
|
||||
isMouseReleased(btn: MouseButton): boolean {
|
||||
return !this.#mouseDown[btn] && this.#previousMouseDown[btn];
|
||||
}
|
||||
|
||||
get mousePosition(): Point | null {
|
||||
return this.#mousePosition
|
||||
return this.#mousePosition;
|
||||
}
|
||||
|
||||
isKeyDown(key: string) : boolean {
|
||||
isKeyDown(key: string): boolean {
|
||||
return this.#keyDown[key];
|
||||
}
|
||||
|
||||
isKeyPressed(key: string) : boolean {
|
||||
isKeyPressed(key: string): boolean {
|
||||
return this.#keyDown[key] && !this.#previousKeyDown[key];
|
||||
}
|
||||
|
||||
isKeyReleased(key: string) : boolean {
|
||||
isKeyReleased(key: string): boolean {
|
||||
return !this.#keyDown[key] && this.#previousKeyDown[key];
|
||||
}
|
||||
|
||||
isAnythingPressed(): boolean {
|
||||
for (let k of Object.keys(this.#keyDown)) {
|
||||
if (this.#keyDown[k] && !this.#previousKeyDown[k]) { return true }
|
||||
if (this.#keyDown[k] && !this.#previousKeyDown[k]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (let k of Object.keys(this.#mouseDown)) {
|
||||
if (this.#mouseDown[k] && !this.#previousMouseDown[k]) { return true }
|
||||
if (this.#mouseDown[k] && !this.#previousMouseDown[k]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -127,4 +142,4 @@ let active = new Input();
|
||||
|
||||
export function getInput(): Input {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {Size} from "../datatypes.ts";
|
||||
import { Size } from "../datatypes.ts";
|
||||
|
||||
// TODO: Just switch to the same pattern as everywhere else
|
||||
// (without repeatedly reassigning the variable)
|
||||
class Screen {
|
||||
#canvas: HTMLCanvasElement
|
||||
size: Size
|
||||
#canvas: HTMLCanvasElement;
|
||||
size: Size;
|
||||
|
||||
constructor(canvas: HTMLCanvasElement, size: Size) {
|
||||
this.#canvas = canvas;
|
||||
this.size = size
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
unsafeMakeContext(): CanvasRenderingContext2D {
|
||||
@ -26,8 +26,7 @@ class Screen {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let active: Screen | undefined = undefined
|
||||
let active: Screen | undefined = undefined;
|
||||
|
||||
// TODO: Move these to Game?
|
||||
export let desiredWidth = 400;
|
||||
@ -45,9 +44,9 @@ export function pollAndTouch(canvas: HTMLCanvasElement) {
|
||||
|
||||
let div = 0;
|
||||
while (
|
||||
(div < divisors.length - 1) &&
|
||||
(realWidth / divisors[div + 1] >= desiredWidth) &&
|
||||
(realHeight / divisors[div + 1] >= desiredHeight)
|
||||
div < divisors.length - 1 &&
|
||||
realWidth / divisors[div + 1] >= desiredWidth &&
|
||||
realHeight / divisors[div + 1] >= desiredHeight
|
||||
) {
|
||||
div += 1;
|
||||
}
|
||||
@ -60,9 +59,7 @@ export function pollAndTouch(canvas: HTMLCanvasElement) {
|
||||
|
||||
export function getScreen(): Screen {
|
||||
if (active === undefined) {
|
||||
throw `screen should have been defined: ${active}`
|
||||
throw `screen should have been defined: ${active}`;
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {getAssets} from "./assets.ts";
|
||||
import {Point, Size} from "../datatypes.ts";
|
||||
|
||||
import { getAssets } from "./assets.ts";
|
||||
import { Point, Size } from "../datatypes.ts";
|
||||
|
||||
export class Sprite {
|
||||
readonly imageSet: string;
|
||||
@ -11,7 +10,13 @@ export class Sprite {
|
||||
// number of frames
|
||||
readonly nFrames: number;
|
||||
|
||||
constructor(imageSet: string, pixelsPerSubimage: Size, origin: Point, cellsPerSheet: Size, nFrames: number) {
|
||||
constructor(
|
||||
imageSet: string,
|
||||
pixelsPerSubimage: Size,
|
||||
origin: Point,
|
||||
cellsPerSheet: Size,
|
||||
nFrames: number,
|
||||
) {
|
||||
this.imageSet = imageSet;
|
||||
this.pixelsPerSubimage = pixelsPerSubimage;
|
||||
this.origin = origin;
|
||||
@ -24,7 +29,22 @@ export class Sprite {
|
||||
}
|
||||
}
|
||||
|
||||
internalDraw(ctx: CanvasRenderingContext2D, {position, ix, xScale, yScale, angle}: {position: Point, ix?: number, xScale?: number, yScale?: number, angle?: number}) {
|
||||
internalDraw(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
{
|
||||
position,
|
||||
ix,
|
||||
xScale,
|
||||
yScale,
|
||||
angle,
|
||||
}: {
|
||||
position: Point;
|
||||
ix?: number;
|
||||
xScale?: number;
|
||||
yScale?: number;
|
||||
angle?: number;
|
||||
},
|
||||
) {
|
||||
ix = ix == undefined ? 0 : ix;
|
||||
xScale = xScale == undefined ? 1.0 : xScale;
|
||||
yScale = yScale == undefined ? 1.0 : yScale;
|
||||
@ -32,7 +52,7 @@ export class Sprite {
|
||||
|
||||
// ctx.translate(Math.floor(x), Math.floor(y));
|
||||
ctx.translate(Math.floor(position.x), Math.floor(position.y));
|
||||
ctx.rotate(angle * Math.PI / 180);
|
||||
ctx.rotate((angle * Math.PI) / 180);
|
||||
ctx.scale(xScale, yScale);
|
||||
ctx.translate(-this.origin.x, -this.origin.y);
|
||||
|
||||
@ -41,6 +61,16 @@ export class Sprite {
|
||||
let srcCy = Math.floor(ix / this.cellsPerSheet.w);
|
||||
let srcPx = srcCx * this.pixelsPerSubimage.w;
|
||||
let srcPy = srcCy * this.pixelsPerSubimage.h;
|
||||
ctx.drawImage(me, srcPx, srcPy, this.pixelsPerSubimage.w, this.pixelsPerSubimage.h, 0, 0, this.pixelsPerSubimage.w, this.pixelsPerSubimage.h);
|
||||
ctx.drawImage(
|
||||
me,
|
||||
srcPx,
|
||||
srcPy,
|
||||
this.pixelsPerSubimage.w,
|
||||
this.pixelsPerSubimage.h,
|
||||
0,
|
||||
0,
|
||||
this.pixelsPerSubimage.w,
|
||||
this.pixelsPerSubimage.h,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
@ -9,4 +10,4 @@ html, body {
|
||||
image-rendering: pixelated;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {getInput} from "./internal/input.ts";
|
||||
import {getDrawing} from "./internal/drawing.ts";
|
||||
import { getInput } from "./internal/input.ts";
|
||||
import { getDrawing } from "./internal/drawing.ts";
|
||||
|
||||
// input reexports
|
||||
export let I = getInput();
|
||||
|
Reference in New Issue
Block a user