fix: resolve parsing errors in FxLayer and RadialMenuElements

This commit is contained in:
Restart2008
2025-11-21 21:48:03 -08:00
parent 9ae7260a23
commit 6eb696d21d
8 changed files with 87 additions and 62 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 257 B

+17 -19
View File
@@ -1,10 +1,10 @@
import { EventBus, GameEvent } from "../core/EventBus";
import { UnitType } from "../core/game/Game";
import { UnitView } from "../core/game/GameView";
import { UserSettings } from "../core/game/UserSettings";
import { PingType } from "../core/game/Ping";
import { UIState } from "./graphics/UIState";
import { UserSettings } from "../core/game/UserSettings";
import { TransformHandler } from "./graphics/TransformHandler";
import { UIState } from "./graphics/UIState";
import { ReplaySpeedMultiplier } from "./utilities/ReplaySpeedMultiplier";
export class MouseUpEvent implements GameEvent {
@@ -501,26 +501,24 @@ export class InputHandler {
this.eventBus.emit(new PingSelectedEvent(null));
return;
}
{
const localX = event.clientX - rect.left;
const localY = event.clientY - rect.top;
const worldCoords = this.transformHandler.screenToWorldCoordinates(
localX,
localY,
);
this.eventBus.emit(
new PingPlacedEvent(
this.uiState.currentPingType,
worldCoords.x,
worldCoords.y,
),
);
}
const localX = event.clientX - rect.left;
const localY = event.clientY - rect.top;
const worldCoords = this.transformHandler.screenToWorldCoordinates(
localX,
localY,
);
this.eventBus.emit(
new PingPlacedEvent(
this.uiState.currentPingType,
worldCoords.x,
worldCoords.y,
),
);
this.uiState.currentPingType = null;
this.eventBus.emit(new PingSelectedEvent(null)); // Clear ping preview
this.eventBus.emit(new PingSelectedEvent(null));
return;
}
if (event.pointerType === "touch") {
this.eventBus.emit(new TouchEvent(event.x, event.y));
event.preventDefault();
+41 -11
View File
@@ -298,6 +298,10 @@ export function createRenderer(
export class GameRenderer {
private context: CanvasRenderingContext2D;
private rafId?: number;
private resizeListener?: () => void;
private contextLostListener?: () => void;
private contextRestoredListener?: () => void;
constructor(
private game: GameView,
@@ -316,33 +320,59 @@ export class GameRenderer {
private redrawEventCleanup?: () => void;
initialize() {
this.redrawEventCleanup = this.eventBus.on(RedrawGraphicsEvent, () =>
this.redrawEventCleanup = this.eventBus.on(RedrawGraphicsEvent, () =>
this.redraw(),
);
this.layers.forEach((l) => l.init?.());
document.body.appendChild(this.canvas);
window.addEventListener("resize", () => this.resizeCanvas());
this.resizeListener = () => this.resizeCanvas();
window.addEventListener("resize", this.resizeListener);
this.resizeCanvas();
//show whole map on startup
this.transformHandler.centerAll(0.9);
let rafId = requestAnimationFrame(() => this.renderGame());
this.canvas.addEventListener("contextlost", () => {
cancelAnimationFrame(rafId);
});
this.canvas.addEventListener("contextrestored", () => {
this.contextLostListener = () => {
if (this.rafId !== undefined) {
cancelAnimationFrame(this.rafId);
this.rafId = undefined;
}
};
this.canvas.addEventListener("contextlost", this.contextLostListener);
this.contextRestoredListener = () => {
this.redraw();
rafId = requestAnimationFrame(() => this.renderGame());
});
this.rafId = requestAnimationFrame(() => this.renderGame());
};
this.canvas.addEventListener(
"contextrestored",
this.contextRestoredListener,
);
this.rafId = requestAnimationFrame(() => this.renderGame());
}
destroy() {
this.redrawEventCleanup?.();
if (this.rafId !== undefined) {
cancelAnimationFrame(this.rafId);
}
if (this.resizeListener) {
window.removeEventListener("resize", this.resizeListener);
}
if (this.contextLostListener) {
this.canvas.removeEventListener("contextlost", this.contextLostListener);
}
if (this.contextRestoredListener) {
this.canvas.removeEventListener(
"contextrestored",
this.contextRestoredListener,
);
}
this.layers.forEach((l) => l.destroy?.());
}
resizeCanvas() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
+4 -6
View File
@@ -1,9 +1,8 @@
import { TileRef } from "../../../core/game/GameMap";
import { GameView } from "../../../core/game/GameView";
import { PingType } from "../../../core/game/Ping";
import { TileRef } from "../../../core/game/GameMap";
import { Fx } from "./Fx";
export class PingFx implements Fx {
private readonly durationMs: number = 3000; // Ping visible for 3 seconds
private startTime: number;
@@ -12,8 +11,6 @@ export class PingFx implements Fx {
return PingFx.iconCache.get(this.pingType) ?? null;
}
constructor(
private game: GameView,
private pingType: PingType,
@@ -57,9 +54,10 @@ export class PingFx implements Fx {
return null;
}
}
private static iconCache = new Map<PingType, HTMLImageElement | null>();
private static iconCache = new Map<PingType, HTMLImageElement | null>();
private static preloadIcon(pingType: PingType, iconPath: string): void {
if (!PingFx.iconCache.has(pingType)) {
PingFx.iconCache.set(pingType, null); // Reserve spot immediately
const img = new Image();
img.onload = () => {
PingFx.iconCache.set(pingType, img);
@@ -109,4 +107,4 @@ private static iconCache = new Map<PingType, HTMLImageElement | null>();
context.restore();
return true; // Fx is still active
}
}
}
+6
View File
@@ -353,6 +353,12 @@ export class FxLayer implements Layer {
}
private pingEventCleanup?: () => void;
dispose() {
if (this.pingEventCleanup) {
this.pingEventCleanup();
this.pingEventCleanup = undefined;
}
}
async init() {
this.redraw();
try {
+8 -11
View File
@@ -1,17 +1,13 @@
import {
MenuElement,
MenuElementParams,
COLORS,
} from "./RadialMenuElements";
import swordIcon from "../../../../resources/images/SwordIconWhite.svg";
import retreatIcon from "../../../../resources/images/BackIconWhite.svg";
import defendIcon from "../../../../resources/images/ShieldIconWhite.svg";
import pingIcon from "../../../../resources/images/PingIcon.svg";
import watchOutIcon from "../../../../resources/images/QuestionMarkIcon.svg";
import defendIcon from "../../../../resources/images/ShieldIconWhite.svg";
import { EventBus } from "../../../core/EventBus";
import { PingType } from "../../../core/game/Ping";
import { PingSelectedEvent } from "../../InputHandler";
import { COLORS, MenuElement, MenuElementParams } from "./RadialMenuElements";
export const PING_ICON = swordIcon;
export const PING_ICON = pingIcon;
export const PING_COLORS = {
[PingType.Attack]: "#ff0000",
@@ -34,9 +30,10 @@ function createPingElement(
color: PING_COLORS[pingType],
disabled: () => false,
action: (params?: MenuElementParams) => {
if (!params) return;
eventBus.emit(new PingSelectedEvent(pingType));
params.closeMenu();
if (params) {
params.closeMenu();
}
},
};
}
@@ -84,4 +81,4 @@ export function createPingMenu(eventBus: EventBus): MenuElement {
pingWatchOutElement,
],
};
}
}
@@ -572,6 +572,8 @@ export const rootMenuElement: MenuElement = {
icon: infoIcon,
color: COLORS.info,
subMenu: (params: MenuElementParams) => {
if (params === undefined) return [];
let ally = allyRequestElement;
if (params.selected?.isAlliedWith(params.myPlayer)) {
ally = allyBreakElement;
@@ -584,7 +586,7 @@ export const rootMenuElement: MenuElement = {
const menuItems: (MenuElement | null)[] = [
infoMenuElement,
createPingMenu(params.eventBus),
createPingMenu(params.eventBus),
...(isOwnTerritory
? [deleteUnitElement, ally, buildMenuElement]
: [boatMenuElement, ally, attackMenuElement]),
+5 -14
View File
@@ -1,17 +1,8 @@
import { TileRef } from "./GameMap";
export enum PingType {
Attack,
Retreat,
Defend,
WatchOut,
}
export type PingType = "attack" | "retreat" | "defend" | "watchOut";
export class Ping {
constructor(
public type: PingType,
public tile: TileRef,
) {}
}
export class PingPlacedEvent extends Ping {}
export type Ping = {
type: PingType;
tile: TileRef;
};