KHAKSWQANUZL7B3EYF6GWTDGSUR2WVZGU5BPPI6OKYIPCD3QMWAQC import { Entity } from "./entity";import { Debug } from "./debug";import { HashSet } from "./data_structures/hash";import { TypesafeLoader, AllResourcesType } from "./typesafe_loader";import { CreateGame as ReactMountGame } from "./react/react_root";import { Camera } from "./camera";import { DebugFlagsType } from "./react/debug_flag_buttons";import { CollisionHandler } from "./collision_handler";import { Rect } from "./geometry/rect";import { CoroutineManager } from "./coroutine_manager";import { IGameState } from 'Library';import { BaseGameState } from "./base_state";export let GameReference: BaseGame<any>;export type GameArgs = {scale: number;canvasWidth: number;canvasHeight: number;tileHeight: number;tileWidth: number;debugFlags: DebugFlagsType;state: Omit<IGameState, keyof BaseGameState>;assets: TypesafeLoader<any>;};export const StageName = "Stage";export const FixedStageName = "FixedStage";export const ParallaxStageName = "ParallaxStage";export class BaseGame<TResources extends AllResourcesType = {}> {app: PIXI.Application;state: IGameState;/*** The root of the display hierarchy for the game. Everything that exists in* the game that isn't fixed as the camera moves should be under this.*/stage: Entity;parallaxStage: Entity;/*** A stage for things in the game that don't move when the camera move and are* instead fixed to the screen. For example, the HUD.*/fixedCameraStage: Entity;private assets: TypesafeLoader<TResources>;renderer: Renderer;camera: Camera;collisionHandler: CollisionHandler;coroutineManager: CoroutineManager;constructor(props: GameArgs) {GameReference = this;this.coroutineManager = new CoroutineManager(this);this.state = {...(new BaseGameState()),...props.state,}const view = document.getElementById('canvas');if (!view) {throw new Error("I couldn't find an element named #canvas on initialization. Giving up!")}this.collisionHandler = new CollisionHandler({canvasWidth: props.canvasWidth / props.scale,canvasHeight: props.canvasHeight / props.scale,tileHeight: props.tileHeight,tileWidth: props.tileWidth,});this.app = new Application({width: props.canvasWidth,height: props.canvasHeight,powerPreference: "low-power",antialias: false,transparent: false,resolution: window.devicePixelRatio,autoDensity: true,backgroundColor: 0x4e5759,view: view as HTMLCanvasElement,});this.app.stage.scale = new Point(props.scale, props.scale);this.parallaxStage = new Entity({ name: ParallaxStageName });this.stage = new Entity({ name: StageName });this.fixedCameraStage = new Entity({ name: FixedStageName });this.state.stage = this.stage;this.app.stage.addChild(this.parallaxStage.sprite);this.app.stage.addChild(this.stage.sprite);this.app.stage.addChild(this.fixedCameraStage.sprite);this.state.renderer = this.app.renderer;this.state.stage = this.stage;this.assets = props.assets;this.assets.onLoadComplete(() => this.startGameLoop());this.assets.onLoadComplete(() => this.initialize());this.renderer = this.app.renderer;this.camera = new Camera({stage: this.stage,state: this.state,canvasWidth: props.canvasWidth,canvasHeight: props.canvasHeight,scale: props.scale,bounds: new Rect({ x: -5000, y: -5000, width: 10000, height: 10000 }),});this.state.camera = this.camera;ReactMountGame(this, props.debugFlags);this.stage.sprite.sortableChildren = true;this.fixedCameraStage.sprite.sortableChildren = true;}/*** Called after resources are finished loading.*/initialize() {}startGameLoop = () => {this.app.ticker.add(() => this.gameLoop());};gameLoop() {Debug.Clear();const { entities } = this.state;if (!this.state.lastCollisionGrid) {const grid = this.collisionHandler.buildCollisionGrid({bounds: new Rect({ x: 0, y: 0, width: 5000, height: 5000 }),entities: this.state.entities,});this.state.lastCollisionGrid = grid;}this.state.tick++;this.state.keys.update();for (const entity of entities.values()) {entity.baseUpdate(this.state);}this.state.entities = new HashSet(entities.values().filter(ent => !this.state.toBeDestroyed.includes(ent)));for (const entity of this.state.toBeDestroyed) {if (entity.sprite.parent) {entity.sprite.parent.removeChild(entity.sprite);}this.coroutineManager.stopCoroutinesOwnedBy(entity);}this.state.toBeDestroyed = [];const activeEntities = new HashSet(this.state.entities.values().filter(e => e.activeModes.includes(this.state.mode)));const grid = this.collisionHandler.buildCollisionGrid({bounds: this.camera.getBounds(),entities: activeEntities,});this.state.lastCollisionGrid = grid;this.collisionHandler.resolveCollisions({entities: activeEntities,grid: grid,});this.camera.update(this.state);this.coroutineManager.updateCoroutines(this.state);// let foo = Debug.GetDrawnObjects();// for (const f of Debug.GetDrawnObjects()) {// if (f instanceof AugmentedSprite) {// if (f.width > 1024) {// f.visible = false;// }// }// }// let foo = Debug.GetDrawn();Debug.ResetDrawCount();};}
// import { Entity } from "./entity";// import { Debug } from "./debug";// import { HashSet } from "./data_structures/hash";// import { TypesafeLoader, AllResourcesType } from "./typesafe_loader";// import { CreateGame as ReactMountGame } from "./react/react_root";// import { Camera } from "./camera";// import { DebugFlagsType } from "./react/debug_flag_buttons";// import { CollisionHandler } from "./collision_handler";// import { Rect } from "./geometry/rect";// import { CoroutineManager } from "./coroutine_manager";// import { IGameState } from 'Library';// import { BaseGameState } from "./base_state";//// export let GameReference: BaseGame<any>;//// export type GameArgs = {// scale: number;// canvasWidth: number;// canvasHeight: number;// tileHeight: number;// tileWidth: number;// debugFlags: DebugFlagsType;// state: Omit<IGameState, keyof BaseGameState>;// assets: TypesafeLoader<any>;// };//// export const StageName = "Stage";// export const FixedStageName = "FixedStage";// export const ParallaxStageName = "ParallaxStage";//// export class BaseGame<TResources extends AllResourcesType = {}> {// app: PIXI.Application;//// state: IGameState;//// /**// * The root of the display hierarchy for the game. Everything that exists in// * the game that isn't fixed as the camera moves should be under this.// */// stage: Entity;//// parallaxStage: Entity;//// /**// * A stage for things in the game that don't move when the camera move and are// * instead fixed to the screen. For example, the HUD.// */// fixedCameraStage: Entity;//// private assets: TypesafeLoader<TResources>;//// renderer: Renderer;//// camera: Camera;//// collisionHandler: CollisionHandler;//// coroutineManager: CoroutineManager;//// constructor(props: GameArgs) {// GameReference = this;//// this.coroutineManager = new CoroutineManager(this);// this.state = {// ...(new BaseGameState()),// ...props.state,// }//// const view = document.getElementById('canvas');//// if (!view) {// throw new Error("I couldn't find an element named #canvas on initialization. Giving up!")// }//// this.collisionHandler = new CollisionHandler({// canvasWidth: props.canvasWidth / props.scale,// canvasHeight: props.canvasHeight / props.scale,// tileHeight: props.tileHeight,// tileWidth: props.tileWidth,// });//// this.app = new Application({// width: props.canvasWidth,// height: props.canvasHeight,// powerPreference: "low-power",// antialias: false,// transparent: false,// resolution: window.devicePixelRatio,// autoDensity: true,// backgroundColor: 0x4e5759,// view: view as HTMLCanvasElement,// });//// this.app.stage.scale = new Point(props.scale, props.scale);//// this.parallaxStage = new Entity({ name: ParallaxStageName });// this.stage = new Entity({ name: StageName });// this.fixedCameraStage = new Entity({ name: FixedStageName });//// this.state.stage = this.stage;//// this.app.stage.addChild(this.parallaxStage.sprite);// this.app.stage.addChild(this.stage.sprite);// this.app.stage.addChild(this.fixedCameraStage.sprite);//// this.state.renderer = this.app.renderer;// this.state.stage = this.stage;//// this.assets = props.assets;// this.assets.onLoadComplete(() => this.startGameLoop());// this.assets.onLoadComplete(() => this.initialize());//// this.renderer = this.app.renderer;//// this.camera = new Camera({// stage: this.stage,// state: this.state,// canvasWidth: props.canvasWidth,// canvasHeight: props.canvasHeight,// scale: props.scale,// bounds: new Rect({ x: -5000, y: -5000, width: 10000, height: 10000 }),// });//// this.state.camera = this.camera;//// ReactMountGame(this, props.debugFlags);//// this.stage.sprite.sortableChildren = true;// this.fixedCameraStage.sprite.sortableChildren = true;// }//// /**// * Called after resources are finished loading.// */// initialize() {//// }//// startGameLoop = () => {// this.app.ticker.add(() => this.gameLoop());// };//// gameLoop() {// Debug.Clear();//// const { entities } = this.state;//// if (!this.state.lastCollisionGrid) {// const grid = this.collisionHandler.buildCollisionGrid({// bounds: new Rect({ x: 0, y: 0, width: 5000, height: 5000 }),// entities: this.state.entities,// });//// this.state.lastCollisionGrid = grid;// }//// this.state.tick++;//// this.state.keys.update();//// for (const entity of entities.values()) {// entity.baseUpdate(this.state);// }//// this.state.entities = new HashSet(entities.values().filter(ent => !this.state.toBeDestroyed.includes(ent)));//// for (const entity of this.state.toBeDestroyed) {// if (entity.sprite.parent) {// entity.sprite.parent.removeChild(entity.sprite);// }//// this.coroutineManager.stopCoroutinesOwnedBy(entity);// }//// this.state.toBeDestroyed = [];//// const activeEntities = new HashSet(this.state.entities.values().filter(e => e.activeModes.includes(this.state.mode)));//// const grid = this.collisionHandler.buildCollisionGrid({// bounds: this.camera.getBounds(),// entities: activeEntities,// });//// this.state.lastCollisionGrid = grid;//// this.collisionHandler.resolveCollisions({// entities: activeEntities,// grid: grid,// });//// this.camera.update(this.state);//// this.coroutineManager.updateCoroutines(this.state);//// // let foo = Debug.GetDrawnObjects();//// // for (const f of Debug.GetDrawnObjects()) {// // if (f instanceof AugmentedSprite) {// // if (f.width > 1024) {// // f.visible = false;// // }// // }// // }//// // let foo = Debug.GetDrawn();//// Debug.ResetDrawCount();// };// }
import { IGameState } from "Library";import { Entity } from "./entity";import { Game } from "../game/game";import { BaseGame } from "./base_game";import { IS_DEBUG } from "./environment";/*** const state: GameState = yield CoroutineResult;*/export type GameCoroutine = Generator<CoroutineResult, void, IGameState>export type CoroutineResult = "next" | { frames: number } | { untilKeyPress: keyof KeyInfoType };type ActiveCoroutine = {fn : GameCoroutine;status :| { waiting: false }| { waiting: true; type: "frames" ; frames: number }| { waiting: true; type: "untilKey"; untilKey: keyof KeyInfoType }name : string;owner : Entity | Game;};export type CoroutineId = number;export class CoroutineManager {private _lastCoroutineId: CoroutineId = -1;private _activeCoroutines: { [key: number]: ActiveCoroutine } = [];private _game: BaseGame<any>;constructor(game: BaseGame<any>) {this._game = game;}startCoroutine(name: string, co: GameCoroutine, owner: Entity | Game): CoroutineId {for (const activeCo of Object.values(this._activeCoroutines)) {if (activeCo.name === name) {if (IS_DEBUG) {throw new Error(`Two coroutines with the name ${ name }. Tell grant about this!!!`);} else {return 0;}}}this._activeCoroutines[++this._lastCoroutineId] = {fn : co,status : { waiting: false },name : name,owner : owner,};return this._lastCoroutineId;}public stopCoroutine(id: CoroutineId): void {delete this._activeCoroutines[id];}public updateCoroutines(state: IGameState): void {for (const key of Object.keys(this._activeCoroutines)) {const co = this._activeCoroutines[Number(key)];if (co.status.waiting) {if (co.status.type === "frames") {if (co.status.frames-- < 0) {co.status = { waiting: false };} else {continue;}} else if (co.status.type === "untilKey") {if (state.keys.justDown[co.status.untilKey]) {co.status = { waiting: false };} else {continue;}}}const { value, done } = co.fn.next(state);if (done) {this.stopCoroutine(Number(key));continue;}if (value === "next") {continue;}if (typeof value === "object") {if ("frames" in value) {co.status = { waiting: true, type: 'frames', frames: value.frames };continue;} else if ("untilKeyPress" in value) {co.status = { waiting: true, type: 'untilKey', untilKey: value.untilKeyPress };continue;}}}}stopCoroutinesOwnedBy(entity: Entity) {const ids = Object.keys(this._activeCoroutines).map(k => Number(k));for (const id of ids) {if (this._activeCoroutines[id].owner === entity) {this.stopCoroutine(id);}}}}
// import { IGameState } from "Library";// import { Entity } from "./entity";// import { Game } from "../game/game";// import { BaseGame } from "./base_game";// import { IS_DEBUG } from "./environment";//// /**// * const state: GameState = yield CoroutineResult;// */// export type GameCoroutine = Generator<CoroutineResult, void, IGameState>//// export type CoroutineResult = "next" | { frames: number } | { untilKeyPress: keyof KeyInfoType };//// type ActiveCoroutine = {// fn : GameCoroutine;// status :// | { waiting: false }// | { waiting: true; type: "frames" ; frames: number }// | { waiting: true; type: "untilKey"; untilKey: keyof KeyInfoType }// name : string;// owner : Entity | Game;// };//// export type CoroutineId = number;//// export class CoroutineManager {// private _lastCoroutineId: CoroutineId = -1;// private _activeCoroutines: { [key: number]: ActiveCoroutine } = [];// private _game: BaseGame<any>;//// constructor(game: BaseGame<any>) {// this._game = game;// }//// startCoroutine(name: string, co: GameCoroutine, owner: Entity | Game): CoroutineId {// for (const activeCo of Object.values(this._activeCoroutines)) {// if (activeCo.name === name) {// if (IS_DEBUG) {// throw new Error(`Two coroutines with the name ${ name }. Tell grant about this!!!`);// } else {// return 0;// }// }// }//// this._activeCoroutines[++this._lastCoroutineId] = {// fn : co,// status : { waiting: false },// name : name,// owner : owner,// };//// return this._lastCoroutineId;// }//// public stopCoroutine(id: CoroutineId): void {// delete this._activeCoroutines[id];// }//// public updateCoroutines(state: IGameState): void {// for (const key of Object.keys(this._activeCoroutines)) {// const co = this._activeCoroutines[Number(key)];//// if (co.status.waiting) {// if (co.status.type === "frames") {// if (co.status.frames-- < 0) {// co.status = { waiting: false };// } else {// continue;// }// } else if (co.status.type === "untilKey") {// if (state.keys.justDown[co.status.untilKey]) {// co.status = { waiting: false };// } else {// continue;// }// }// }//// const { value, done } = co.fn.next(state);//// if (done) {// this.stopCoroutine(Number(key));//// continue;// }//// if (value === "next") {// continue;// }//// if (typeof value === "object") {// if ("frames" in value) {// co.status = { waiting: true, type: 'frames', frames: value.frames };//// continue;// } else if ("untilKeyPress" in value) {// co.status = { waiting: true, type: 'untilKey', untilKey: value.untilKeyPress };//// continue;// }// }// }// }//// stopCoroutinesOwnedBy(entity: Entity) {// const ids = Object.keys(this._activeCoroutines).map(k => Number(k));//// for (const id of ids) {// if (this._activeCoroutines[id].owner === entity) {// this.stopCoroutine(id);// }// }// }// }
import { Graphics, Sprite, Container } from "pixi.js";import { Line } from "./geometry/line";import { Entity } from "./entity";import { Rect } from "./geometry/rect";import { RectGroup } from "./geometry/rect_group";import { GameReference } from "./base_game";import { BaseGameState } from "./base_state";import { IS_DEBUG, IS_PRODUCTION } from "./environment";const MAX_DEBUGGING_GRAPHICS_COUNT = 500;export class Debug {public static stageReference: Entity;public static DebugMode = false;public static DebugGraphicStack: Graphics[] = [];public static Clear(): void {for (const debug of Debug.DebugGraphicStack) {debug.parent.removeChild(debug);debug.destroy();}Debug.DebugGraphicStack = [];}/*** Draw a point on the canvas.** We expect this function to be called every tick in an update() function.* Debug graphics drawn in the previous tick are removed in the game loop.* If that's not what you want, pass persistent = true.*/public static DrawPoint(point: IVector2, color = 0xff0000, persistent = false): Graphics {if (IS_PRODUCTION) {console.error("SHOULD NOT HAPPEN")}const graphics = new Graphics();new Line({x1: point.x - 40,x2: point.x + 40,y1: point.y - 40,y2: point.y + 40,}).drawOnto(graphics, color);new Line({x1: point.x + 40,x2: point.x - 40,y1: point.y - 40,y2: point.y + 40,}).drawOnto(graphics, color);GameReference.stage.sprite.addChild(graphics);if (!persistent) {this.DebugGraphicStack.push(graphics);if (this.DebugGraphicStack.length > MAX_DEBUGGING_GRAPHICS_COUNT) {const toBeRemoved = this.DebugGraphicStack.shift()!;toBeRemoved.parent.removeChild(toBeRemoved);toBeRemoved.destroy();}}return graphics;}/*** Draw a line from start to end on the canvas, for debugging.** We expect this function to be called every tick in an update() function.* Debug graphics drawn in the previous tick are removed in the game loop.** If that's not what you want, pass persistent = true.*/public static DrawLineV2(start: Vector2, end: Vector2, color = 0xff0000, persistent = false): Graphics {if (IS_PRODUCTION) {console.error("SHOULD NOT HAPPEN")}return Debug.DrawLine(new Line({ start, end }), color, persistent);}/*** Draw a line on the canvas, for debugging.** We expect this function to be called every tick in an update() function.* Debug graphics drawn in the previous tick are removed in the game loop.** If that's not what you want, pass persistent = true.*/public static DrawLine(line: Line, color = 0xff0000, persistent = false, target: "stage" | "fixed" = "fixed"): Graphics {if (IS_PRODUCTION) {console.error("SHOULD NOT HAPPEN")}const graphics = new Graphics();line.drawOnto(graphics, color);if (target === "fixed") {GameReference.fixedCameraStage.sprite.addChild(graphics);} else {GameReference.stage.sprite.addChild(graphics);}if (!persistent) {this.DebugGraphicStack.push(graphics);if (this.DebugGraphicStack.length > MAX_DEBUGGING_GRAPHICS_COUNT) {const toBeRemoved = this.DebugGraphicStack.shift()!;toBeRemoved.parent.removeChild(toBeRemoved);toBeRemoved.destroy();}}return graphics;}/*** Draw a rectangle from start to end on the canvas, for debugging.** We expect this function to be called every tick in an update() function.* Debug graphics drawn in the previous tick are removed in the game loop.** If that's not what you want, pass persistent = true.*/public static DrawRect(rect: Rect, color = 0xff0000, persistent = false, target: "stage" | "fixed" = "fixed"): Graphics[] {if (IS_PRODUCTION) {console.error("SHOULD NOT HAPPEN")}const lines: Graphics[] = [];for (const line of rect.getLinesFromRect()) {lines.push(Debug.DrawLine(line, color, persistent, target));}return lines;}/*** Draw the bounds of a game object on the canvas, for debugging.** We expect this function to be called every tick in an update() function.* Debug graphics drawn in the previous tick are removed in the game loop.** If that's not what you want, pass persistent = true.*/public static DrawBounds(entity: Entity | Sprite | Graphics | RectGroup | Container | Rect,color = 0xff0000,persistent = false,target: "stage" | "fixed" = "stage"): Graphics[] {if (IS_PRODUCTION) {console.error("SHOULD NOT HAPPEN")}if (entity instanceof Entity) {entity = entity.collisionBounds().add(entity.positionAbsolute());}if (entity instanceof RectGroup) {const results: Graphics[] = [];for (const rect of entity.getRects()) {const lines = Debug.DrawRect(rect, color, persistent, target);for (const line of lines) {results.push(line);}}return results;} else {return Debug.DrawRect(new Rect({x : entity.x,y : entity.y,width : entity.width,height: entity.height,}), color, persistent, target);}}private static profiles: { [key: string]: number[] } = {};/*** Performance test a block of code.*/public static Profile(name: string, cb: () => void): void {Debug.profiles[name] = Debug.profiles[name] || [];const start = window.performance.now();cb();const end = window.performance.now();Debug.profiles[name].push(end - start);if (Debug.profiles[name].length === 60) {const average = Debug.profiles[name].reduce((a, b) => a + b) / 60;const rounded = Math.floor(average * 100) / 100;Debug.profiles[name] = [];console.log(`${ name }: ${ rounded }ms`);}}static ResetDrawCount() {(Sprite as any).drawCount = 0;(Container as any).drawCount = 0;drawn = [];}static GetDrawnObjects() {return drawn;}static GetDrawCount() {return ((Sprite as any).drawCount +(Container as any).drawCount);}public static DebugStuff(state: BaseGameState) {if (state.keys.justDown.Z) {Debug.DebugMode = true;state.stage.x = 0;state.stage.y = 0;if (state.stage.scale.x === 0.2) {state.stage.scale = new Vector2({ x: 1, y: 1 });} else {state.stage.scale = new Vector2({ x: 0.2, y: 0.2 });}}if (Debug.DebugMode) {if (state.keys.down.W) {state.stage.y += 20;}if (state.keys.down.S) {state.stage.y -= 20;}if (state.keys.down.D) {state.stage.x -= 20;}if (state.keys.down.A) {state.stage.x += 20;}}}public static DebugShowRect(state: BaseGameState, rect: Rect) {state.stage.scale = new Vector2({ x: 0.2, y: 0.2 });state.stage.x = -rect.x * 0.2;state.stage.y = -rect.y * 0.2;}}let drawn: any[] = [];if (IS_DEBUG) {(Sprite as any).drawCount = 0;(Sprite.prototype as any).__render = (Sprite.prototype as any)._render;(Sprite.prototype as any)._render = function (renderer: any) {(Sprite as any).drawCount++;this.__render(renderer);drawn.push(this);};(Sprite.prototype as any).__renderCanvas = (Sprite.prototype as any)._renderCanvas;(Sprite.prototype as any)._renderCanvas = function (renderer: any) {(Sprite as any).drawCount++;this.__renderCanvas(renderer);drawn.push(this);};// PIXI.Container(Container as any).drawCount = 0;(Container.prototype as any).__render = (Container.prototype as any)._render;(Container.prototype as any)._render = function (renderer: any) {(Container as any).drawCount++;this.__render(renderer);drawn.push(this);};(Container.prototype as any).__renderCanvas = (Container.prototype as any)._renderCanvas;(Container.prototype as any)._renderCanvas = function (renderer: any) {(Container as any).drawCount++;this.__renderCanvas(renderer);drawn.push(this);};}
// import { Graphics, Sprite, Container } from "pixi.js";// import { Line } from "./geometry/line";// import { Entity } from "./entity";// import { Rect } from "./geometry/rect";// import { RectGroup } from "./geometry/rect_group";// import { GameReference } from "./base_game";// import { BaseGameState } from "./base_state";// import { IS_DEBUG, IS_PRODUCTION } from "./environment";//// const MAX_DEBUGGING_GRAPHICS_COUNT = 500;//// export class Debug {// public static stageReference: Entity;//// public static DebugMode = false;//// public static DebugGraphicStack: Graphics[] = [];//// public static Clear(): void {// for (const debug of Debug.DebugGraphicStack) {// debug.parent.removeChild(debug);// debug.destroy();// }//// Debug.DebugGraphicStack = [];// }//// /**// * Draw a point on the canvas.// *// * We expect this function to be called every tick in an update() function.// * Debug graphics drawn in the previous tick are removed in the game loop.// * If that's not what you want, pass persistent = true.// */// public static DrawPoint(point: IVector2, color = 0xff0000, persistent = false): Graphics {// if (IS_PRODUCTION) {// console.error("SHOULD NOT HAPPEN")// }//// const graphics = new Graphics();//// new Line({// x1: point.x - 40,// x2: point.x + 40,//// y1: point.y - 40,// y2: point.y + 40,// }).drawOnto(graphics, color);//// new Line({// x1: point.x + 40,// x2: point.x - 40,//// y1: point.y - 40,// y2: point.y + 40,// }).drawOnto(graphics, color);//// GameReference.stage.sprite.addChild(graphics);//// if (!persistent) {// this.DebugGraphicStack.push(graphics);//// if (this.DebugGraphicStack.length > MAX_DEBUGGING_GRAPHICS_COUNT) {// const toBeRemoved = this.DebugGraphicStack.shift()!;//// toBeRemoved.parent.removeChild(toBeRemoved);// toBeRemoved.destroy();// }// }//// return graphics;// }//// /**// * Draw a line from start to end on the canvas, for debugging.// *// * We expect this function to be called every tick in an update() function.// * Debug graphics drawn in the previous tick are removed in the game loop.// *// * If that's not what you want, pass persistent = true.// */// public static DrawLineV2(start: Vector2, end: Vector2, color = 0xff0000, persistent = false): Graphics {// if (IS_PRODUCTION) {// console.error("SHOULD NOT HAPPEN")// }//// return Debug.DrawLine(new Line({ start, end }), color, persistent);// }//// /**// * Draw a line on the canvas, for debugging.// *// * We expect this function to be called every tick in an update() function.// * Debug graphics drawn in the previous tick are removed in the game loop.// *// * If that's not what you want, pass persistent = true.// */// public static DrawLine(line: Line, color = 0xff0000, persistent = false, target: "stage" | "fixed" = "fixed"): Graphics {// if (IS_PRODUCTION) {// console.error("SHOULD NOT HAPPEN")// }//// const graphics = new Graphics();//// line.drawOnto(graphics, color);//// if (target === "fixed") {// GameReference.fixedCameraStage.sprite.addChild(graphics);// } else {// GameReference.stage.sprite.addChild(graphics);// }//// if (!persistent) {// this.DebugGraphicStack.push(graphics);//// if (this.DebugGraphicStack.length > MAX_DEBUGGING_GRAPHICS_COUNT) {// const toBeRemoved = this.DebugGraphicStack.shift()!;//// toBeRemoved.parent.removeChild(toBeRemoved);// toBeRemoved.destroy();// }// }//// return graphics;// }//// /**// * Draw a rectangle from start to end on the canvas, for debugging.// *// * We expect this function to be called every tick in an update() function.// * Debug graphics drawn in the previous tick are removed in the game loop.// *// * If that's not what you want, pass persistent = true.// */// public static DrawRect(rect: Rect, color = 0xff0000, persistent = false, target: "stage" | "fixed" = "fixed"): Graphics[] {// if (IS_PRODUCTION) {// console.error("SHOULD NOT HAPPEN")// }//// const lines: Graphics[] = [];//// for (const line of rect.getLinesFromRect()) {// lines.push(Debug.DrawLine(line, color, persistent, target));// }//// return lines;// }//// /**// * Draw the bounds of a game object on the canvas, for debugging.// *// * We expect this function to be called every tick in an update() function.// * Debug graphics drawn in the previous tick are removed in the game loop.// *// * If that's not what you want, pass persistent = true.// */// public static DrawBounds(// entity: Entity | Sprite | Graphics | RectGroup | Container | Rect,// color = 0xff0000,// persistent = false,// target: "stage" | "fixed" = "stage"// ): Graphics[] {// if (IS_PRODUCTION) {// console.error("SHOULD NOT HAPPEN")// }//// if (entity instanceof Entity) {// entity = entity.collisionBounds()// .add(entity.positionAbsolute())// ;// }//// if (entity instanceof RectGroup) {// const results: Graphics[] = [];//// for (const rect of entity.getRects()) {// const lines = Debug.DrawRect(rect, color, persistent, target);//// for (const line of lines) {// results.push(line);// }// }//// return results;// } else {// return Debug.DrawRect(new Rect({// x : entity.x,// y : entity.y,// width : entity.width,// height: entity.height,// }), color, persistent, target);// }// }//// private static profiles: { [key: string]: number[] } = {};//// /**// * Performance test a block of code.// */// public static Profile(name: string, cb: () => void): void {// Debug.profiles[name] = Debug.profiles[name] || [];//// const start = window.performance.now();//// cb();//// const end = window.performance.now();//// Debug.profiles[name].push(end - start);//// if (Debug.profiles[name].length === 60) {// const average = Debug.profiles[name].reduce((a, b) => a + b) / 60;// const rounded = Math.floor(average * 100) / 100;//// Debug.profiles[name] = [];//// console.log(`${ name }: ${ rounded }ms`);// }// }//// static ResetDrawCount() {// (Sprite as any).drawCount = 0;// (Container as any).drawCount = 0;// drawn = [];// }//// static GetDrawnObjects() {// return drawn;// }//// static GetDrawCount() {// return (// (Sprite as any).drawCount +// (Container as any).drawCount// );// }//// public static DebugStuff(state: BaseGameState) {// if (state.keys.justDown.Z) {// Debug.DebugMode = true;//// state.stage.x = 0;// state.stage.y = 0;//// if (state.stage.scale.x === 0.2) {// state.stage.scale = new Vector2({ x: 1, y: 1 });// } else {// state.stage.scale = new Vector2({ x: 0.2, y: 0.2 });// }// }//// if (Debug.DebugMode) {// if (state.keys.down.W) {// state.stage.y += 20;// }//// if (state.keys.down.S) {// state.stage.y -= 20;// }//// if (state.keys.down.D) {// state.stage.x -= 20;// }//// if (state.keys.down.A) {// state.stage.x += 20;// }// }// }//// public static DebugShowRect(state: BaseGameState, rect: Rect) {// state.stage.scale = new Vector2({ x: 0.2, y: 0.2 });// state.stage.x = -rect.x * 0.2;// state.stage.y = -rect.y * 0.2;// }// }//// let drawn: any[] = [];//// if (IS_DEBUG) {// (Sprite as any).drawCount = 0;//// (Sprite.prototype as any).__render = (Sprite.prototype as any)._render;// (Sprite.prototype as any)._render = function (renderer: any) {// (Sprite as any).drawCount++;// this.__render(renderer);// drawn.push(this);// };////// (Sprite.prototype as any).__renderCanvas = (Sprite.prototype as any)._renderCanvas;// (Sprite.prototype as any)._renderCanvas = function (renderer: any) {// (Sprite as any).drawCount++;// this.__renderCanvas(renderer);// drawn.push(this);// };////// // PIXI.Container//// (Container as any).drawCount = 0;//// (Container.prototype as any).__render = (Container.prototype as any)._render;// (Container.prototype as any)._render = function (renderer: any) {// (Container as any).drawCount++;// this.__render(renderer);// drawn.push(this);// };////// (Container.prototype as any).__renderCanvas = (Container.prototype as any)._renderCanvas;// (Container.prototype as any)._renderCanvas = function (renderer: any) {// (Container as any).drawCount++;// this.__renderCanvas(renderer);// drawn.push(this);// };// }
import crypto from "crypto";/*** Md5 is 16 bytes, or max int of 256 ** 16 = 2 ** 128*/export class HashState {private seed!: Buffer;/*** HashState().step("foo") is equivalent to HashState("foo")*/constructor(seed?: string) {const buffer = crypto.createHash("md5").update((seed || "").toString()).digest();this.seed = buffer;}public peekRandom(): number {const buffer = crypto.createHash("md5").update(this.seed).digest();return Number(this.bufferToBigInt(buffer) % BigInt(2 ** 32)) % 2 ** 32;}// increment the seed linearly by 1public step(numSteps: number = 1) {this.seed = this.bigIntToBuffer(this.bufferToBigInt(this.seed) + BigInt(1));}public stepSeed(seed: string) {const buffer = crypto.createHash("md5").update(seed.toString()).digest();this.seed = this.bigIntToBuffer(this.bufferToBigInt(this.seed) + this.bufferToBigInt(buffer));}private bigIntToBuffer(b: bigint): Buffer {let buf = Buffer.alloc(16);let val = b;for (let i = 0; i < 16; i++) {buf[i] = Number(val % BigInt(256));val = val / BigInt(256);}return buf;}private bufferToBigInt(b: Buffer): bigint {let val = BigInt(0);for (let i = 0; i < 16; i++) {val = val * BigInt(256) + BigInt(b[i]);}return val;}public random(): number {this.step();return this.peekRandom();}}
public drawAll() {}
public drawAll() {// get the first 3 layers' configurations// render the top layer points// renderLayerPoints(layer[0], { rect: null })// render the next layer// render the intermediate connections// render the final layer// render the intermediate connections}
import { connect } from "http2";import { HashState } from "../library/random";export type Topo3Frames = {out: TopoFrame;in0: TopoFrame;in1: TopoFrame;};export class TopoTemplate {public id!: string;public orientation!: FrameOrientation;public frames!: Topo3Frames;public nodes: TopoNode[] = [];constructor(id: string, frames: Topo3Frames, random: HashState) {this.id = id;this.frames = frames;this.orientation = frames.out.orientation;// start constructing the guyconnectCorner(this.frames.out.corners["00"], this.frames.in0.corners["00"]);connectCorner(this.frames.out.corners["11"], this.frames.in1.corners["00"]);if (this.orientation == "=") {connectCorner(this.frames.out.corners["01"],this.frames.in0.corners["01"]);connectCorner(this.frames.out.corners["10"],this.frames.in1.corners["10"]);connectMiddleCorner(this.frames.in0.corners["10"],this.frames.in1.corners["00"]);connectMiddleCorner(this.frames.in0.corners["11"],this.frames.in1.corners["01"]);} else if (this.orientation == "0") {connectCorner(this.frames.out.corners["01"],this.frames.in1.corners["01"]);connectCorner(this.frames.out.corners["10"],this.frames.in0.corners["10"]);connectMiddleCorner(this.frames.in0.corners["01"],this.frames.in1.corners["00"]);connectMiddleCorner(this.frames.in0.corners["11"],this.frames.in1.corners["10"]);}}}export type FrameOrientation = "=" | "0";export class TopoFrame {public id!: string;public orientation!: FrameOrientation;public corners!: {"00": TopoNode;"01": TopoNode;"10": TopoNode;"11": TopoNode;};/*** 00 ----- 10* | |* 01 ----- 11*/constructor(id: string, orientation: FrameOrientation) {this.id = id;this.corners = {"00": new TopoNode(id + "-N00"),"01": new TopoNode(id + "-N01"),"10": new TopoNode(id + "-N10"),"11": new TopoNode(id + "-N11"),};this.orientation = orientation;}}export class TopoNode {public id!: string;constructor(id: string) {this.id = id;}}