-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add debug renderer for boat areas as a setting (writing the same boil…
…erplate for the 7th time is enough) This also adds a new setting "type", which will be used more in the future
- Loading branch information
Showing
8 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import {areaCalculator} from "../../../map/area/AreaCalculator"; | ||
import {DebugRendererLayer} from "./DebugRendererRegistry"; | ||
import {mapNavigationHandler} from "../../../game/action/MapNavigationHandler"; | ||
|
||
export class BoatMeshDebugRenderer implements DebugRendererLayer { | ||
readonly useCache = false; | ||
|
||
render(context: CanvasRenderingContext2D): void { | ||
context.strokeStyle = "red"; | ||
context.fillStyle = "orange"; | ||
for (const nodes of areaCalculator.nodeIndex) { | ||
for (const node of nodes) { | ||
context.beginPath(); | ||
context.arc((node.x + 0.5) * mapNavigationHandler.zoom + mapNavigationHandler.x, (node.y + 0.5) * mapNavigationHandler.zoom + mapNavigationHandler.y, mapNavigationHandler.zoom / 2, 0, 2 * Math.PI); | ||
context.fill(); | ||
} | ||
} | ||
for (const nodes of areaCalculator.nodeIndex) { | ||
for (const node of nodes) { | ||
for (const neighbor of node.edges) { | ||
if (neighbor.node.x < node.x || (neighbor.node.x === node.x && neighbor.node.y < node.y)) continue; // Only draw each edge once | ||
context.beginPath(); | ||
context.moveTo((node.x + 0.5) * mapNavigationHandler.zoom + mapNavigationHandler.x, (node.y + 0.5) * mapNavigationHandler.zoom + mapNavigationHandler.y); | ||
context.lineTo((neighbor.node.x + 0.5) * mapNavigationHandler.zoom + mapNavigationHandler.x, (neighbor.node.y + 0.5) * mapNavigationHandler.zoom + mapNavigationHandler.y); | ||
context.stroke(); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import {CachedLayer} from "../CachedLayer"; | ||
import {mapTransformHandler} from "../../../event/MapTransformHandler"; | ||
import {gameMap} from "../../../game/GameData"; | ||
import {registerSettingListener} from "../../../util/UserSettingManager"; | ||
import {RendererLayer} from "../RendererLayer"; | ||
import {DebugRendererLayer} from "./DebugRendererRegistry"; | ||
import {gameStartRegistry} from "../../../game/Game"; | ||
|
||
/** | ||
* Debug renderer. | ||
* Renders debug information on the map if toggled. | ||
* @internal | ||
*/ | ||
class DebugRenderer extends CachedLayer { | ||
private readonly mapLayers: RendererLayer[] = []; | ||
private readonly liveLayers: RendererLayer[] = []; | ||
|
||
/** | ||
* Updates the layers to be rendered by the debug renderer. | ||
* @param layers layers to be rendered | ||
*/ | ||
updateLayers(layers: DebugRendererLayer[]): void { | ||
this.mapLayers.length = 0; | ||
this.liveLayers.length = 0; | ||
for (const layer of layers) { | ||
if (layer.useCache) { | ||
this.mapLayers.push(layer); | ||
} else { | ||
this.liveLayers.push(layer); | ||
} | ||
} | ||
} | ||
|
||
render(context: CanvasRenderingContext2D) { | ||
super.render(context); | ||
this.liveLayers.forEach(layer => layer.render(context)); | ||
} | ||
|
||
init(): void { | ||
this.resizeCanvas(gameMap.width, gameMap.height); | ||
this.mapLayers.forEach(layer => layer.render(this.context)); | ||
} | ||
|
||
onMapMove(this: void, x: number, y: number): void { | ||
debugRenderer.dx = x; | ||
debugRenderer.dy = y; | ||
} | ||
|
||
onMapScale(this: void, scale: number): void { | ||
debugRenderer.scale = scale; | ||
} | ||
} | ||
|
||
export const debugRenderer = new DebugRenderer(); | ||
|
||
mapTransformHandler.scale.register(debugRenderer.onMapScale); | ||
mapTransformHandler.move.register(debugRenderer.onMapMove); | ||
gameStartRegistry.register(debugRenderer.init.bind(debugRenderer)); | ||
|
||
registerSettingListener("debug-renderer", value => debugRenderer.updateLayers(value.getEnabledOptions()), true); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {MultiSelectSetting} from "../../../util/MultiSelectSetting"; | ||
import {BoatMeshDebugRenderer} from "./BoatMeshDebugRenderer"; | ||
import {RendererLayer} from "../RendererLayer"; | ||
|
||
export const debugRendererLayers = MultiSelectSetting.init() | ||
.option("boat-navigation-mesh", new BoatMeshDebugRenderer(), "Boat Navigation Mesh", false); | ||
|
||
export interface DebugRendererLayer extends Omit<RendererLayer, "invalidateCaches"> { | ||
useCache: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export interface ManagedSetting { | ||
/** | ||
* Returns a string representation of this settings value. | ||
*/ | ||
toString(): string; | ||
|
||
/** | ||
* Parses a string to set the value of this setting. | ||
*/ | ||
fromString(value: string): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import {InvalidArgumentException} from "./Exceptions"; | ||
import {ManagedSetting} from "./ManagedSetting"; | ||
|
||
export class MultiSelectSetting<T extends Record<string, Option<unknown>>> implements ManagedSetting { | ||
private options: T = {} as T; | ||
|
||
static init() { | ||
return new MultiSelectSetting<{}>(); | ||
} | ||
|
||
/** | ||
* Registers a new option with the given key and value. | ||
* @param key The key of the option. Must be unique, not contain ',' and shouldn't change in the future | ||
* @param value The value of the option | ||
* @param label The label of the option, displayed in the UI | ||
* @param defaultStatus The default status of the option | ||
* @throws InvalidArgumentException if the key contains ',' | ||
*/ | ||
option<K extends string, V>(key: K & Exclude<K, keyof T>, value: V, label: string, defaultStatus: boolean) { | ||
if (key.includes(",")) throw new InvalidArgumentException("Key cannot contain ','"); | ||
(this.options as unknown as Record<K, Option<V>>)[key] = {value, label, status: defaultStatus}; | ||
return this as unknown as MultiSelectSetting<T & Record<K, Option<V>>>; | ||
} | ||
|
||
/** | ||
* Checks if the option with the given key is selected. | ||
* @param key The key of the option | ||
* @returns true if the option is selected, false otherwise | ||
*/ | ||
isSelected(key: keyof T) { | ||
return this.options[key].status; | ||
} | ||
|
||
/** | ||
* Selects the option with the given key. | ||
* @param key The key of the option | ||
* @param status The status to set | ||
*/ | ||
select(key: keyof T, status: boolean) { | ||
this.options[key].status = status; | ||
} | ||
|
||
/** | ||
* Returns the enabled options. | ||
* @returns An array of the values of the enabled options | ||
*/ | ||
getEnabledOptions(): AnyValue<T>[] { | ||
return Object.keys(this.options).filter(key => this.options[key].status).map(key => this.options[key].value); | ||
} | ||
|
||
/** | ||
* Returns all options. | ||
* @returns An array of the values of all options | ||
*/ | ||
getAllOptions(): AnyValue<T>[] { | ||
return Object.keys(this.options).map(key => this.options[key].value); | ||
} | ||
|
||
toString() { | ||
return Object.keys(this.options).filter(key => this.options[key].status).join(","); | ||
} | ||
|
||
fromString(value: string) { | ||
const selected = value.split(","); | ||
for (const key in this.options) { | ||
this.options[key].status = selected.includes(key); | ||
} | ||
return this; | ||
} | ||
} | ||
|
||
type Option<T> = { | ||
value: T; | ||
label: string; | ||
status: boolean; | ||
} | ||
|
||
type AnyValue<T extends Record<string, Option<unknown>>> = { | ||
[K in keyof T]: T[K]["value"]; | ||
}[keyof T]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters