add runtime type-checking
This commit is contained in:
parent
d2a746cbe4
commit
43c8c0e535
279
src/gamelib.js
279
src/gamelib.js
@ -1,3 +1,5 @@
|
||||
import { GamelibAdapter } from "./gamelib_adapter.js";
|
||||
|
||||
export class Gamelib {
|
||||
constructor(console, assetProvider, canvasElement) {
|
||||
this.console = console;
|
||||
@ -274,280 +276,3 @@ export class Gamelib {
|
||||
return new GamelibAdapter(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that is called whenever the Key it is registered to is pressed or released.
|
||||
* @callback OnKeyEventHandler
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that is called whenever the MouseButton it is registered to is pressed or released.
|
||||
* @callback OnClickEventHandler
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that is called whenever the mouse is moved.
|
||||
* @callback OnMouseMoveEventHandler
|
||||
* @param {number} positionX The mouse x position
|
||||
* @param {number} positionY The mouse y position
|
||||
* @param {number} deltaX The difference in x position between this and the last onMouseMove event
|
||||
* @param {number} deltaY The difference in y position between this and the last onMouseMove event
|
||||
*/
|
||||
|
||||
/**
|
||||
* A loaded sprite
|
||||
* @typedef {object} Sprite
|
||||
*/
|
||||
|
||||
/**
|
||||
* A html color
|
||||
* @typedef {string} Color
|
||||
*/
|
||||
|
||||
/**
|
||||
* A component of `[x, y]` of a path.
|
||||
* @typedef {[number, number]} PathComponent
|
||||
*/
|
||||
|
||||
/**
|
||||
* Text style
|
||||
* @typedef TextStyle
|
||||
* @type {object}
|
||||
* @property {number} fontWeight Font weight
|
||||
* @property {number} fontStyle !!!!!!!!!!!!!!!!!!!!! no idea what this does, needs better docs
|
||||
* @property {number} fontSize Font size in pixels
|
||||
* @property {string} fontFamily Font family
|
||||
* @property {"left"|"center"|"right"} align Text alignment
|
||||
* @property {string} baseline !!!!!!!!!!!!!!!!!!!!! no idea what this does, needs better docs
|
||||
* @property {string} direction !!!!!!!!!!!!!!!!!!!!! no idea what this does, needs better docs
|
||||
* @property {Color} color
|
||||
*/
|
||||
|
||||
export class GamelibAdapter {
|
||||
/* Enum for MouseButton values
|
||||
* @enum {number}
|
||||
*/
|
||||
MouseButton = {
|
||||
Left: 0,
|
||||
Right: 1,
|
||||
Middle: 2,
|
||||
};
|
||||
|
||||
constructor(gamelib) {
|
||||
this.gamelib = gamelib;
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.gamelib.width;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.gamelib.height;
|
||||
}
|
||||
|
||||
get mouseX() {
|
||||
return this.gamelib.mouseX;
|
||||
}
|
||||
|
||||
get mouseY() {
|
||||
return this.gamelib.mouseY;
|
||||
}
|
||||
|
||||
println(msg) {
|
||||
this.gamelib.console.log(msg);
|
||||
}
|
||||
|
||||
startGameLoop(loopFunction) {
|
||||
this.gamelib.startGameLoop(loopFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not `key` is currently pressed.
|
||||
* `Key` can any one of [KeyBoardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)'s values
|
||||
* @param {Key} key
|
||||
* @return {boolean} Whether `key` is pressed.
|
||||
*/
|
||||
isPressed(key) {
|
||||
return this.gamelib.keysPressed.has(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `key` is pressed.
|
||||
* Key can be any of [KeyBoardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)'s values
|
||||
* @param {Key} key
|
||||
* @param {OnKeyEventHandler} handlerFunction
|
||||
* @return {void}
|
||||
*/
|
||||
onPress(key, handlerFunction) {
|
||||
this.gamelib.keyPressHandlers.set(key, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `key` is pressed.
|
||||
* Key can be any of [KeyBoardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)'s values
|
||||
* @param {Key} key
|
||||
* @param {OnKeyEventHandler} handlerFunction
|
||||
*/
|
||||
onRelease(key, handlerFunction) {
|
||||
this.gamelib.keyReleaseHandlers.set(key, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when mouse is moved.
|
||||
* @param {OnMouseMoveEventHandler} handlerFunction
|
||||
*/
|
||||
onMouseMove(handlerFunction) {
|
||||
this.gamelib.mouseMoveHandler = handlerFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not `button` is currently clicked.
|
||||
* MouseButton is accessed from `lib.MouseButton`
|
||||
* @param {GamelibAdapter.MouseButton} button defaults to {GamelibAdapter.MouseButton.Left}
|
||||
* @return {boolean} Whether `key` is pressed.
|
||||
*/
|
||||
isClicking(button = this.MouseButton.Left) {
|
||||
return this.gamelib.mouseButtonsPressed.has(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `button` is pressed.
|
||||
* MouseButton is accessed from `lib.MouseButton`
|
||||
* @param {OnClickEventHandler} handlerFunction
|
||||
* @param {GamelibAdapter.MouseButton} button defaults to {GamelibAdapter.MouseButton.Left}
|
||||
*/
|
||||
onClick(handlerFunction, button = this.MouseButton.Left) {
|
||||
this.gamelib.mouseDownHandlers.set(button, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `button` is released.
|
||||
* MouseButton is accessed from `lib.MouseButton`
|
||||
* @param {OnClickEventHandler} handlerFunction
|
||||
* @param {GamelibAdapter.MouseButton} button defaults to {GamelibAdapter.MouseButton.Left}
|
||||
*/
|
||||
onClickRelease(handlerFunction, button = this.MouseButton.Left) {
|
||||
this.gamelib.mouseUpHandlers.set(button, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a sprite with `name`, rendered with specified `width` and `height`
|
||||
*
|
||||
* @param {string} name The sprite name
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @return {Promise<Sprite>} The loaded sprite
|
||||
*/
|
||||
async loadSprite(name, width, height) {
|
||||
return await this.gamelib.loadSprite(name, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sprite loaded by {GamelibAdapter.loadSprite}
|
||||
*
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {Sprite} A loaded sprite
|
||||
*/
|
||||
drawSprite(x, y, sprite) {
|
||||
this.gamelib.drawSprite(x, y, sprite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a rotated sprite loaded by {GamelibAdapter.loadSprite}
|
||||
*
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {Sprite} sprite A loaded sprite
|
||||
* @param {number} angle An angle in radians
|
||||
*/
|
||||
drawSpriteRotated(x, y, sprite, angle) {
|
||||
this.gamelib.drawSpriteRotated(x, y, sprite, angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an rgb Color.
|
||||
*
|
||||
* @param {number} red
|
||||
* @param {number} green
|
||||
* @param {number} blue
|
||||
* @return {Color} Formatted {Color} string
|
||||
*/
|
||||
rgb(red, green, blue) {
|
||||
return `rgb(${red}, ${green}, ${blue})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the screen with `color`
|
||||
* @param {Color} color
|
||||
*/
|
||||
clear(color) {
|
||||
this.gamelib.clear(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a rect at `(x,y)` with a size of `(width,height)` in `color`
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawRect(x, y, width, height, color) {
|
||||
this.gamelib.drawRect(x, y, width, height, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a circle at `(x,y)` with a radius of `r` in `color`
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} r Radius of circle
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawCircle(x, y, r, color) {
|
||||
this.gamelib.drawCircle(x, y, r, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a line from `(x0,y0)` to `(x1,y1)` with a thickness of `thickness` in `color`
|
||||
* @param {number} x0
|
||||
* @param {number} y0
|
||||
* @param {number} x1
|
||||
* @param {number} y1
|
||||
* @param {number} thickness
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawLine(x0, y0, x1, y1, thickness, color) {
|
||||
this.gamelib.drawLine(x0, y0, x1, y1, thickness, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a polygon in `color` based off of `path` components
|
||||
* @param {PathComponent[]} path
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawPath(path, color) {
|
||||
this.gamelib.drawPath(path, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an outline in `color` based off of `path` components, with a thickness of `thickness`
|
||||
* @param {PathComponent[]} path
|
||||
* @param {number} thickness
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawPathLine(path, thickness, color) {
|
||||
this.gamelib.drawPathLine(path, thickness, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw text
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {string} text
|
||||
* @param {TextStyle} style
|
||||
*/
|
||||
drawText(x, y, text, style = {}) {
|
||||
this.gamelib.drawText(x, y, text, style);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,402 @@
|
||||
/**
|
||||
* A function that is called whenever the Key it is registered to is pressed or released.
|
||||
* @callback OnKeyEventHandler
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that is called whenever the MouseButton it is registered to is pressed or released.
|
||||
* @callback OnClickEventHandler
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that is called whenever the mouse is moved.
|
||||
* @callback OnMouseMoveEventHandler
|
||||
* @param {number} positionX The mouse x position
|
||||
* @param {number} positionY The mouse y position
|
||||
* @param {number} deltaX The difference in x position between this and the last onMouseMove event
|
||||
* @param {number} deltaY The difference in y position between this and the last onMouseMove event
|
||||
*/
|
||||
|
||||
/**
|
||||
* A loaded sprite
|
||||
* @typedef {object} Sprite
|
||||
*/
|
||||
|
||||
/**
|
||||
* A html color
|
||||
* @typedef {string} Color
|
||||
*/
|
||||
|
||||
/**
|
||||
* A component of `[x, y]` of a path.
|
||||
* @typedef {[number, number]} PathComponent
|
||||
*/
|
||||
|
||||
/**
|
||||
* A keyboard key
|
||||
* @typedef {string} Key
|
||||
*/
|
||||
|
||||
/**
|
||||
* Text style
|
||||
* @typedef TextStyle
|
||||
* @type {object}
|
||||
* @property {number|string} [fontWeight="normal"] Font weight as a number or a string, e.g. 400 or "bold"
|
||||
* @property {"normal"|"italic"} [fontStyle="normal"] Style to apply to the font, e.g. "italic"
|
||||
* @property {number} [fontSize=16] Font size in pixels
|
||||
* @property {string} [fontFamily="inherit"] Font family, e.g. "sans-serif" or "serif"
|
||||
* @property {"left"|"center"|"right"} [align="left"] Horizontal text alignment
|
||||
* @property {"top"|"hanging"|"middle"|"alphabetic"|"ideographic"|"bottom"} [baseline="alphabetic"] Vertical text alignment
|
||||
* @property {"ltr"|"rtl"} [direction="ltr"] Whether the text goes left-to-right or right-to-left
|
||||
* @property {Color} [color="white"] Text color
|
||||
*/
|
||||
|
||||
export class GamelibAdapter {
|
||||
/* Enum for MouseButton values
|
||||
* @enum {number}
|
||||
*/
|
||||
MouseButton = {
|
||||
Left: 0,
|
||||
Right: 1,
|
||||
Middle: 2,
|
||||
};
|
||||
|
||||
constructor(gamelib) {
|
||||
this.gamelib = gamelib;
|
||||
}
|
||||
|
||||
#error(message, func) {
|
||||
const error = new Error(`${func.name}: ${message}`);
|
||||
Error.captureStackTrace(error, func);
|
||||
|
||||
this.gamelib.console.error(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
#checkParams(func, args, expectedTypes) {
|
||||
console.log(func, args, expectedTypes);
|
||||
if (args.length > expectedTypes.length) {
|
||||
this.#error(
|
||||
`Too many arguments to function. Expected ${expectedTypes.length}, got ${args.length}`,
|
||||
func,
|
||||
);
|
||||
}
|
||||
|
||||
const typeAliases = {
|
||||
Sprite: OffscreenCanvas,
|
||||
MouseButton: "number",
|
||||
};
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const expectedType = typeAliases[expectedTypes[i]] ?? expectedTypes[i];
|
||||
|
||||
if (typeof expectedType === "string" && typeof args[i] !== expectedType) {
|
||||
this.#error(
|
||||
`Expected parameter #${
|
||||
i + 1
|
||||
} to be of type ${expectedType}, got ${typeof args[i]}`,
|
||||
func,
|
||||
);
|
||||
}
|
||||
|
||||
if (expectedType instanceof Object && !(args[i] instanceof expectedType)) {
|
||||
const expectedTypeName = expectedType.prototype.constructor.name;
|
||||
|
||||
this.#error(
|
||||
`Expected parameter #${
|
||||
i + 1
|
||||
} to be of type ${expectedTypeName}, got ${typeof args[i]}`,
|
||||
func,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.gamelib.width;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.gamelib.height;
|
||||
}
|
||||
|
||||
get mouseX() {
|
||||
return this.gamelib.mouseX;
|
||||
}
|
||||
|
||||
get mouseY() {
|
||||
return this.gamelib.mouseY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a line to the console
|
||||
* @param {any} msg The message or value to print
|
||||
* @return {void}
|
||||
*/
|
||||
println(msg) {
|
||||
this.gamelib.console.log(msg);
|
||||
}
|
||||
|
||||
startGameLoop(loopFunction) {
|
||||
this.#checkParams(this.startGameLoop, [loopFunction], [Function]);
|
||||
|
||||
this.gamelib.startGameLoop(loopFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not `key` is currently pressed.
|
||||
* `Key` can any one of [KeyBoardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)'s values
|
||||
* @param {Key} key
|
||||
* @return {boolean} Whether `key` is pressed.
|
||||
*/
|
||||
isPressed(key) {
|
||||
this.#checkParams(this.isPressed, [key], ["string"]);
|
||||
|
||||
return this.gamelib.keysPressed.has(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `key` is pressed.
|
||||
* Key can be any of [KeyBoardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)'s values
|
||||
* @param {Key} key
|
||||
* @param {OnKeyEventHandler} handlerFunction
|
||||
* @return {void}
|
||||
*/
|
||||
onPress(key, handlerFunction) {
|
||||
this.#checkParams(this.onPress, [key, handlerFunction], ["string", Function]);
|
||||
|
||||
this.gamelib.keyPressHandlers.set(key, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `key` is pressed.
|
||||
* Key can be any of [KeyBoardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)'s values
|
||||
* @param {Key} key
|
||||
* @param {OnKeyEventHandler} handlerFunction
|
||||
*/
|
||||
onRelease(key, handlerFunction) {
|
||||
this.#checkParams(this.onRelease, [key, handlerFunction], ["string", Function]);
|
||||
|
||||
this.gamelib.keyReleaseHandlers.set(key, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when mouse is moved.
|
||||
* @param {OnMouseMoveEventHandler} handlerFunction
|
||||
*/
|
||||
onMouseMove(handlerFunction) {
|
||||
this.#checkParams(this.onMouseMove, [handlerFunction], [Function]);
|
||||
|
||||
this.gamelib.mouseMoveHandler = handlerFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not `button` is currently clicked.
|
||||
* MouseButton is accessed from `lib.MouseButton`
|
||||
* @param {GamelibAdapter.MouseButton} button defaults to {GamelibAdapter.MouseButton.Left}
|
||||
* @return {boolean} Whether `key` is pressed.
|
||||
*/
|
||||
isClicking(button = this.MouseButton.Left) {
|
||||
this.#checkParams(this.isClicking, [button], ["MouseButton"]);
|
||||
|
||||
return this.gamelib.mouseButtonsPressed.has(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `button` is pressed.
|
||||
* MouseButton is accessed from `lib.MouseButton`
|
||||
* @param {OnClickEventHandler} handlerFunction
|
||||
* @param {GamelibAdapter.MouseButton} button defaults to {GamelibAdapter.MouseButton.Left}
|
||||
*/
|
||||
onClick(handlerFunction, button = this.MouseButton.Left) {
|
||||
this.#checkParams(this.onClick, [handlerFunction, button], [Function, "MouseButton"]);
|
||||
|
||||
this.gamelib.mouseDownHandlers.set(button, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a `handlerFunction` that is called when `button` is released.
|
||||
* MouseButton is accessed from `lib.MouseButton`
|
||||
* @param {OnClickEventHandler} handlerFunction
|
||||
* @param {GamelibAdapter.MouseButton} button defaults to {GamelibAdapter.MouseButton.Left}
|
||||
*/
|
||||
onClickRelease(handlerFunction, button = this.MouseButton.Left) {
|
||||
this.#checkParams(this.onClickRelease, [handlerFunction, button], [
|
||||
Function,
|
||||
"MouseButton",
|
||||
]);
|
||||
|
||||
this.gamelib.mouseUpHandlers.set(button, handlerFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a sprite with `name`, rendered with specified `width` and `height`
|
||||
*
|
||||
* @param {string} name The sprite name
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @return {Promise<Sprite>} The loaded sprite
|
||||
*/
|
||||
async loadSprite(name, width, height) {
|
||||
this.#checkParams(this.loadSprite, [name, width, height], ["string", "number", "number"]);
|
||||
|
||||
return await this.gamelib.loadSprite(name, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sprite loaded by {GamelibAdapter.loadSprite}
|
||||
*
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {Sprite} sprite A loaded sprite
|
||||
*/
|
||||
drawSprite(x, y, sprite) {
|
||||
this.#checkParams(this.drawSprite, [x, y, sprite], ["number", "number", "Sprite"]);
|
||||
|
||||
this.gamelib.drawSprite(x, y, sprite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a rotated sprite loaded by {GamelibAdapter.loadSprite}
|
||||
*
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {Sprite} sprite A loaded sprite
|
||||
* @param {number} angle An angle in radians
|
||||
*/
|
||||
drawSpriteRotated(x, y, sprite, angle) {
|
||||
this.#checkParams(this.drawSpriteRotated, [x, y, sprite, angle], [
|
||||
"number",
|
||||
"number",
|
||||
"Sprite",
|
||||
"number",
|
||||
]);
|
||||
|
||||
this.gamelib.drawSpriteRotated(x, y, sprite, angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an rgb Color.
|
||||
*
|
||||
* @param {number} red
|
||||
* @param {number} green
|
||||
* @param {number} blue
|
||||
* @return {Color} Formatted {Color} string
|
||||
*/
|
||||
rgb(red, green, blue) {
|
||||
this.#checkParams(this.rgb, [red, green, blue], ["number", "number", "number"]);
|
||||
|
||||
return `rgb(${red}, ${green}, ${blue})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the screen with `color`
|
||||
* @param {Color} color
|
||||
*/
|
||||
clear(color) {
|
||||
this.#checkParams(this.clear, [color], ["string"]);
|
||||
|
||||
this.gamelib.clear(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a rect at `(x,y)` with a size of `(width,height)` in `color`
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawRect(x, y, width, height, color) {
|
||||
this.#checkParams(this.drawRect, [x, y, width, height, color], [
|
||||
"number",
|
||||
"number",
|
||||
"number",
|
||||
"number",
|
||||
"string",
|
||||
]);
|
||||
|
||||
this.gamelib.drawRect(x, y, width, height, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a circle at `(x,y)` with a radius of `r` in `color`
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {number} r Radius of circle
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawCircle(x, y, r, color) {
|
||||
this.#checkParams(this.drawCircle, [x, y, r, color], [
|
||||
"number",
|
||||
"number",
|
||||
"number",
|
||||
"string",
|
||||
]);
|
||||
|
||||
this.gamelib.drawCircle(x, y, r, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a line from `(x0,y0)` to `(x1,y1)` with a thickness of `thickness` in `color`
|
||||
* @param {number} x0
|
||||
* @param {number} y0
|
||||
* @param {number} x1
|
||||
* @param {number} y1
|
||||
* @param {number} thickness
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawLine(x0, y0, x1, y1, thickness, color) {
|
||||
this.#checkParams(this.drawLine, [x0, y0, x1, y1, thickness, color], [
|
||||
"number",
|
||||
"number",
|
||||
"number",
|
||||
"number",
|
||||
"number",
|
||||
"string",
|
||||
]);
|
||||
|
||||
this.gamelib.drawLine(x0, y0, x1, y1, thickness, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a polygon in `color` based off of `path` components
|
||||
* @param {PathComponent[]} path
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawPath(path, color) {
|
||||
this.#checkParams(this.drawPath, [path, color], [Array, "string"]);
|
||||
|
||||
this.gamelib.drawPath(path, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an outline in `color` based off of `path` components, with a thickness of `thickness`
|
||||
* @param {PathComponent[]} path
|
||||
* @param {number} thickness
|
||||
* @param {Color} color
|
||||
*/
|
||||
drawPathLine(path, thickness, color) {
|
||||
this.#checkParams(this.drawPathLine, [path, thickness, color], [Array, "number", "string"]);
|
||||
|
||||
this.gamelib.drawPathLine(path, thickness, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw text
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {string} text
|
||||
* @param {TextStyle} style
|
||||
*/
|
||||
drawText(x, y, text, style = {}) {
|
||||
this.#checkParams(this.drawText, [x, y, text, style], [
|
||||
"number",
|
||||
"number",
|
||||
"string",
|
||||
Object,
|
||||
]);
|
||||
|
||||
this.gamelib.drawText(x, y, text, style);
|
||||
}
|
||||
}
|
@ -30,13 +30,13 @@ const languageProvider = LanguageProvider.fromCdn(
|
||||
languageProvider.registerEditor(editor);
|
||||
languageProvider.setGlobalOptions("typescript", {
|
||||
extraLibs: {
|
||||
"gamelib.js": {
|
||||
content: await (await fetch("/src/gamelib.js")).text(),
|
||||
"gamelib_adapter.js": {
|
||||
content: await (await fetch("/src/gamelib_adapter.js")).text(),
|
||||
version: 1,
|
||||
},
|
||||
"karlkoder.js": {
|
||||
content: `
|
||||
import { GamelibAdapter } from "./gamelib.js";
|
||||
import { GamelibAdapter } from "./gamelib_adapter.js";
|
||||
declare global {
|
||||
const karlkoder: { lib: () => GamelibAdapter }
|
||||
}
|
||||
|
@ -64,7 +64,13 @@ export class PlaygroundConsole {
|
||||
details.appendChild(summary);
|
||||
|
||||
if (arg instanceof Error) {
|
||||
// Add error stack trace
|
||||
// On Chrome, the first line of the stack trace is the error message repeated
|
||||
if (globalThis.chrome) {
|
||||
const trace = arg.stack.split("\n");
|
||||
trace.shift();
|
||||
arg.stack = trace.join("\n");
|
||||
}
|
||||
|
||||
const el = document.createElement("p");
|
||||
el.innerHTML = this.formatStacktrace(arg.stack);
|
||||
details.appendChild(el);
|
||||
@ -126,26 +132,32 @@ class PlaygroundConsoleAdapter {
|
||||
}
|
||||
|
||||
log() {
|
||||
console.log(...arguments);
|
||||
this.#console.addTopLevelEntry("log", ...arguments);
|
||||
}
|
||||
|
||||
dir() {
|
||||
console.dir(...arguments);
|
||||
this.#console.addTopLevelEntry("dir", ...arguments);
|
||||
}
|
||||
|
||||
debug() {
|
||||
console.debug(...arguments);
|
||||
this.#console.addTopLevelEntry("debug", ...arguments);
|
||||
}
|
||||
|
||||
info() {
|
||||
console.info(...arguments);
|
||||
this.#console.addTopLevelEntry("info", ...arguments);
|
||||
}
|
||||
|
||||
warn() {
|
||||
console.warn(...arguments);
|
||||
this.#console.addTopLevelEntry("warn", ...arguments);
|
||||
}
|
||||
|
||||
error() {
|
||||
console.error(...arguments);
|
||||
this.#console.addTopLevelEntry("error", ...arguments);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user