rename Layer → Controller; drop canvas2D-era interface hooks

The Layer interface dates to the canvas2D era when each entry drew to
the shared 2D context via renderLayer(ctx). With canvas2D gone, nothing
draws there and the renderLayer hook is dead. Rename the interface
("main-thread analog of the worker's Execution") and trim it:

  interface Controller {
    init?: () => void;
    tick?: () => void;
    getTickIntervalMs?: () => number;
  }

renderLayer / shouldTransform / redraw are gone.

Sweep across 28 files: from "./Layer" → "./Controller", implements
Layer → implements Controller, Layer[] / Map<Layer,…> →
Controller[] / Map<Controller,…>. Delete the no-op renderLayer +
shouldTransform method bodies that every layer had inherited.

GameRenderer drops the RedrawGraphicsEvent listener + redraw() fanout
(nothing implements redraw anymore) and the now-unused eventBus
constructor field.

One real case: AttackingTroopsOverlay.renderLayer wasn't a no-op — it
updates DOM label transforms each frame so labels track the WebGL
camera during pan/zoom. Rename to private updateLabelDOM() and start
a self-driven RAF in init() so the per-frame updates keep running.

Class names ending in "Layer" (UILayer, StructureIconsLayer, NameLayer,
etc.) intentionally left as-is — those are separate identifiers and
the class-rename / file-move is a follow-up.

407 tests pass.
This commit is contained in:
evanpelle
2026-05-16 22:35:14 -07:00
parent b2f84aad33
commit bac29448c2
30 changed files with 95 additions and 171 deletions
+4 -16
View File
@@ -2,7 +2,6 @@ import { EventBus } from "../../core/EventBus";
import { GameView } from "../../core/game/GameView";
import { UserSettings } from "../../core/game/UserSettings";
import { GameStartingModal } from "../GameStartingModal";
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
import { FrameProfiler } from "./FrameProfiler";
import { TransformHandler } from "./TransformHandler";
import { UIState } from "./UIState";
@@ -13,6 +12,7 @@ import { BuildMenu } from "./layers/BuildMenu";
import { ChatDisplay } from "./layers/ChatDisplay";
import { ChatModal } from "./layers/ChatModal";
import { ControlPanel } from "./layers/ControlPanel";
import { Controller } from "./layers/Controller";
import { EmojiTable } from "./layers/EmojiTable";
import { EventsDisplay } from "./layers/EventsDisplay";
import { GameLeftSidebar } from "./layers/GameLeftSidebar";
@@ -20,7 +20,6 @@ import { GameRightSidebar } from "./layers/GameRightSidebar";
import { HeadsUpMessage } from "./layers/HeadsUpMessage";
import { ImmunityTimer } from "./layers/ImmunityTimer";
import { InGamePromo } from "./layers/InGamePromo";
import { Layer } from "./layers/Layer";
import { Leaderboard } from "./layers/Leaderboard";
import { MainRadialMenu } from "./layers/MainRadialMenu";
import { MultiTabModal } from "./layers/MultiTabModal";
@@ -260,7 +259,7 @@ export function createRenderer(
// When updating these layers please be mindful of the order.
// Try to group layers by the return value of shouldTransform.
// Not grouping the layers may cause excessive calls to context.save() and context.restore().
const layers: Layer[] = [
const layers: Controller[] = [
new UILayer(game, eventBus, transformHandler),
new StructureIconsLayer(game, eventBus, uiState, transformHandler),
new AttackingTroopsOverlay(game, transformHandler, eventBus, userSettings),
@@ -298,7 +297,6 @@ export function createRenderer(
];
return new GameRenderer(
eventBus,
transformHandler,
uiState,
layers,
@@ -307,18 +305,16 @@ export function createRenderer(
}
export class GameRenderer {
private layerTickState = new Map<Layer, { lastTickAtMs: number }>();
private layerTickState = new Map<Controller, { lastTickAtMs: number }>();
constructor(
private eventBus: EventBus,
public transformHandler: TransformHandler,
public uiState: UIState,
private layers: Layer[],
private layers: Controller[],
private performanceOverlay: PerformanceOverlay,
) {}
initialize() {
this.eventBus.on(RedrawGraphicsEvent, () => this.redraw());
this.layers.forEach((l) => l.init?.());
window.addEventListener("resize", () =>
@@ -329,14 +325,6 @@ export class GameRenderer {
this.transformHandler.centerAll(0.9);
}
redraw() {
this.layers.forEach((l) => {
if (l.redraw) {
l.redraw();
}
});
}
tick() {
const nowMs = performance.now();
const shouldProfileTick = FrameProfiler.isEnabled();
+2 -5
View File
@@ -7,7 +7,7 @@ import {
} from "../../../core/game/GameUpdates";
import { GameView, PlayerView } from "../../../core/game/GameView";
import { UserSettings } from "../../../core/game/UserSettings";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
// Parameters for the alert animation
const ALERT_SPEED = 1.6;
@@ -16,7 +16,7 @@ const RETALIATION_WINDOW_TICKS = 15 * 10; // 15 seconds
const ALERT_COOLDOWN_TICKS = 15 * 10; // 15 seconds
@customElement("alert-frame")
export class AlertFrame extends LitElement implements Layer {
export class AlertFrame extends LitElement implements Controller {
public game: GameView;
private userSettings: UserSettings = new UserSettings();
@@ -118,9 +118,6 @@ export class AlertFrame extends LitElement implements Layer {
}
// The alert frame is not affected by the camera transform
shouldTransform(): boolean {
return false;
}
private onBrokeAllianceUpdate(update: BrokeAllianceUpdate) {
const myPlayer = this.game.myPlayer();
@@ -5,7 +5,7 @@ import { UserSettings } from "../../../core/game/UserSettings";
import { AlternateViewEvent } from "../../InputHandler";
import { renderTroops } from "../../Utils";
import { TransformHandler } from "../TransformHandler";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
// Match AttacksDisplay: aquarius for outgoing, red-400 for incoming.
const OUTGOING_COLOR = "var(--color-aquarius)";
@@ -51,7 +51,7 @@ interface AttackLabel {
attackerTroops: number;
}
export class AttackingTroopsOverlay implements Layer {
export class AttackingTroopsOverlay implements Controller {
private container: HTMLDivElement;
private labelTemplate: HTMLDivElement;
private labels = new Map<string, AttackLabel>();
@@ -70,10 +70,6 @@ export class AttackingTroopsOverlay implements Layer {
private readonly userSettings: UserSettings,
) {}
shouldTransform(): boolean {
return false;
}
init() {
this.container = document.createElement("div");
this.container.style.position = "fixed";
@@ -91,6 +87,15 @@ export class AttackingTroopsOverlay implements Layer {
this.container.style.display = this.isVisible ? "" : "none";
};
this.eventBus.on(AlternateViewEvent, this.onAlternateView);
// Self-driven RAF: DOM label positions must update every frame so the
// labels track the WebGL camera as the user pans/zooms. (Previously this
// ran via the now-deleted canvas2D RAF loop.)
const drive = () => {
this.updateLabelDOM();
requestAnimationFrame(drive);
};
requestAnimationFrame(drive);
}
destroy() {
@@ -200,7 +205,7 @@ export class AttackingTroopsOverlay implements Layer {
}
}
renderLayer(_context: CanvasRenderingContext2D) {
private updateLabelDOM() {
const screenPosOld = this.transformHandler.worldToScreenCoordinates(
new Cell(0, 0),
);
+2 -8
View File
@@ -22,12 +22,12 @@ import {
GoToUnitEvent,
} from "../TransformHandler";
import { UIState } from "../UIState";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const soldierIcon = assetUrl("images/SoldierIcon.svg");
const swordIcon = assetUrl("images/SwordIcon.svg");
@customElement("attacks-display")
export class AttacksDisplay extends LitElement implements Layer {
export class AttacksDisplay extends LitElement implements Controller {
public eventBus: EventBus;
public game: GameView;
public uiState: UIState;
@@ -110,12 +110,6 @@ export class AttacksDisplay extends LitElement implements Layer {
this.requestUpdate();
}
shouldTransform(): boolean {
return false;
}
renderLayer(): void {}
private renderButton(options: {
content: any;
onClick?: () => void;
+2 -2
View File
@@ -25,7 +25,7 @@ import {
import { renderNumber } from "../../Utils";
import { TransformHandler } from "../TransformHandler";
import { UIState } from "../UIState";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const warshipIcon = assetUrl("images/BattleshipIconWhite.svg");
const cityIcon = assetUrl("images/CityIconWhite.svg");
const factoryIcon = assetUrl("images/FactoryIconWhite.svg");
@@ -124,7 +124,7 @@ export const buildTable: BuildItemDisplay[][] = [
export const flattenedBuildTable = buildTable.flat();
@customElement("build-menu")
export class BuildMenu extends LitElement implements Layer {
export class BuildMenu extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
public uiState: UIState;
+2 -2
View File
@@ -10,7 +10,7 @@ import {
} from "../../../core/game/GameUpdates";
import { GameView } from "../../../core/game/GameView";
import { onlyImages } from "../../../core/Util";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
interface ChatEvent {
description: string;
@@ -20,7 +20,7 @@ interface ChatEvent {
}
@customElement("chat-display")
export class ChatDisplay extends LitElement implements Layer {
export class ChatDisplay extends LitElement implements Controller {
public eventBus: EventBus;
public game: GameView;
+2 -10
View File
@@ -9,13 +9,13 @@ import { ClientID } from "../../../core/Schemas";
import { AttackRatioEvent } from "../../InputHandler";
import { renderNumber, renderTroops } from "../../Utils";
import { UIState } from "../UIState";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const goldCoinIcon = assetUrl("images/GoldCoinIcon.svg");
const soldierIcon = assetUrl("images/SoldierIcon.svg");
const swordIcon = assetUrl("images/SwordIcon.svg");
@customElement("control-panel")
export class ControlPanel extends LitElement implements Layer {
export class ControlPanel extends LitElement implements Controller {
public game: GameView;
public clientID: ClientID;
public eventBus: EventBus;
@@ -111,14 +111,6 @@ export class ControlPanel extends LitElement implements Layer {
this.uiState.attackRatio = newRatio;
}
renderLayer(context: CanvasRenderingContext2D) {
// Render any necessary canvas elements
}
shouldTransform(): boolean {
return false;
}
setVisibile(visible: boolean) {
this._isVisible = visible;
this.requestUpdate();
+27
View File
@@ -0,0 +1,27 @@
/**
* Controller — the main-thread analog of the worker's Execution.
*
* A Controller subscribes to events / game state and drives some slice of
* the client side (input, UI state, view updates). The interface is just
* lifecycle hooks; all coordination happens via the EventBus and direct
* references the controller is given at construction time.
*
* Naming: previously "Layer" — the name was a leftover from the canvas2D
* era when each entry in the array drew to the same 2D context. Now nothing
* draws to a shared canvas, so they're plain controllers.
*/
export interface Controller {
/** Called once at game start. Subscribe to events / set up state here. */
init?: () => void;
/**
* Called per game tick (10Hz). Optional — pure event subscribers can omit.
*
* If `getTickIntervalMs()` returns > 0, the controller is throttled to that
* wall-clock interval instead of running every tick.
*/
tick?: () => void;
/** Optional throttle on tick frequency, in milliseconds. */
getTickIntervalMs?: () => number;
}
+2 -8
View File
@@ -29,7 +29,7 @@ import {
SendAllianceRejectIntentEvent,
SendAllianceRequestIntentEvent,
} from "../../Transport";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
import { GameView, PlayerView, UnitView } from "../../../core/game/GameView";
import { onlyImages } from "../../../core/Util";
@@ -68,7 +68,7 @@ interface GameEvent {
}
@customElement("events-display")
export class EventsDisplay extends LitElement implements Layer {
export class EventsDisplay extends LitElement implements Controller {
public eventBus: EventBus;
public game: GameView;
public uiState: UIState;
@@ -359,12 +359,6 @@ export class EventsDisplay extends LitElement implements Layer {
];
}
shouldTransform(): boolean {
return false;
}
renderLayer(): void {}
private removeAllianceRenewalEvents(allianceID: number) {
this.events = this.events.filter(
(event) =>
@@ -7,8 +7,8 @@ import { GameMode, Team } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { Platform } from "../../Platform";
import { getTranslatedPlayerTeamLabel, translateText } from "../../Utils";
import { Controller } from "./Controller";
import { ImmunityBarVisibleEvent } from "./ImmunityTimer";
import { Layer } from "./Layer";
import { SpawnBarVisibleEvent } from "./SpawnTimer";
const leaderboardRegularIcon = assetUrl(
"images/LeaderboardIconRegularWhite.svg",
@@ -18,7 +18,7 @@ const teamRegularIcon = assetUrl("images/TeamIconRegularWhite.svg");
const teamSolidIcon = assetUrl("images/TeamIconSolidWhite.svg");
@customElement("game-left-sidebar")
export class GameLeftSidebar extends LitElement implements Layer {
export class GameLeftSidebar extends LitElement implements Controller {
@state()
private isLeaderboardShow = false;
@state()
@@ -8,8 +8,8 @@ import { crazyGamesSDK } from "../../CrazyGamesSDK";
import { TogglePauseIntentEvent } from "../../InputHandler";
import { PauseGameIntentEvent, SendWinnerEvent } from "../../Transport";
import { translateText } from "../../Utils";
import { Controller } from "./Controller";
import { ImmunityBarVisibleEvent } from "./ImmunityTimer";
import { Layer } from "./Layer";
import { ShowReplayPanelEvent } from "./ReplayPanel";
import { ShowSettingsModalEvent } from "./SettingsModal";
import { SpawnBarVisibleEvent } from "./SpawnTimer";
@@ -22,7 +22,7 @@ const fullscreenIcon = assetUrl("images/FullscreenIconWhite.svg");
const exitFullscreenIcon = assetUrl("images/ExitFullscreenIconWhite.svg");
@customElement("game-right-sidebar")
export class GameRightSidebar extends LitElement implements Layer {
export class GameRightSidebar extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
+2 -2
View File
@@ -4,10 +4,10 @@ import { GameType } from "../../../core/game/Game";
import { GameUpdateType } from "../../../core/game/GameUpdates";
import { GameView } from "../../../core/game/GameView";
import { translateText } from "../../Utils";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
@customElement("heads-up-message")
export class HeadsUpMessage extends LitElement implements Layer {
export class HeadsUpMessage extends LitElement implements Controller {
public game: GameView;
@state()
+2 -6
View File
@@ -3,14 +3,14 @@ import { customElement } from "lit/decorators.js";
import { EventBus, GameEvent } from "../../../core/EventBus";
import { GameMode } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
export class ImmunityBarVisibleEvent implements GameEvent {
constructor(public readonly visible: boolean) {}
}
@customElement("immunity-timer")
export class ImmunityTimer extends LitElement implements Layer {
export class ImmunityTimer extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
@@ -88,10 +88,6 @@ export class ImmunityTimer extends LitElement implements Layer {
}
}
shouldTransform(): boolean {
return false;
}
render() {
if (!this.isVisible || !this.isActive) {
return html``;
+2 -6
View File
@@ -2,7 +2,7 @@ import { LitElement, html } from "lit";
import { customElement } from "lit/decorators.js";
import { GameView } from "../../../core/game/GameView";
import { crazyGamesSDK } from "../../CrazyGamesSDK";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const AD_TYPES = [
{ type: "standard_iab_left1", selectorId: "in-game-bottom-left-ad" },
@@ -11,7 +11,7 @@ const AD_TYPES = [
];
@customElement("in-game-promo")
export class InGamePromo extends LitElement implements Layer {
export class InGamePromo extends LitElement implements Controller {
public game: GameView;
private shouldShow: boolean = false;
@@ -169,10 +169,6 @@ export class InGamePromo extends LitElement implements Layer {
this.requestUpdate();
}
shouldTransform(): boolean {
return false;
}
render() {
if (!this.shouldShow) {
return html``;
-10
View File
@@ -1,10 +0,0 @@
export interface Layer {
init?: () => void;
tick?: () => void;
// Optional hint to throttle expensive ticks by wall-clock.
// If omitted or <= 0, the layer ticks whenever GameRenderer ticks.
getTickIntervalMs?: () => number;
renderLayer?: (context: CanvasRenderingContext2D) => void;
shouldTransform?: () => boolean;
redraw?: () => void;
}
+2 -8
View File
@@ -6,7 +6,7 @@ import { EventBus } from "../../../core/EventBus";
import { GameView, PlayerView } from "../../../core/game/GameView";
import { formatPercentage, renderNumber } from "../../Utils";
import { GoToPlayerEvent } from "../TransformHandler";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
interface Entry {
name: string;
@@ -20,7 +20,7 @@ interface Entry {
}
@customElement("leader-board")
export class Leaderboard extends LitElement implements Layer {
export class Leaderboard extends LitElement implements Controller {
public game: GameView | null = null;
public eventBus: EventBus | null = null;
@@ -157,12 +157,6 @@ export class Leaderboard extends LitElement implements Layer {
this.eventBus.emit(new GoToPlayerEvent(player));
}
renderLayer(context: CanvasRenderingContext2D) {}
shouldTransform(): boolean {
return false;
}
render() {
if (!this.visible) {
return html``;
+2 -10
View File
@@ -9,8 +9,8 @@ import { TransformHandler } from "../TransformHandler";
import { UIState } from "../UIState";
import { BuildMenu } from "./BuildMenu";
import { ChatIntegration } from "./ChatIntegration";
import { Controller } from "./Controller";
import { EmojiTable } from "./EmojiTable";
import { Layer } from "./Layer";
import { PlayerActionHandler } from "./PlayerActionHandler";
import { PlayerPanel } from "./PlayerPanel";
import { RadialMenu, RadialMenuConfig } from "./RadialMenu";
@@ -26,7 +26,7 @@ const swordIcon = assetUrl("images/SwordIconWhite.svg");
import { ContextMenuEvent } from "../../InputHandler";
@customElement("main-radial-menu")
export class MainRadialMenu extends LitElement implements Layer {
export class MainRadialMenu extends LitElement implements Controller {
private radialMenu: RadialMenu;
private playerActionHandler: PlayerActionHandler;
@@ -173,14 +173,6 @@ export class MainRadialMenu extends LitElement implements Layer {
});
}
renderLayer(context: CanvasRenderingContext2D) {
this.radialMenu.renderLayer(context);
}
shouldTransform(): boolean {
return this.radialMenu.shouldTransform();
}
closeMenu() {
if (this.radialMenu.isMenuVisible()) {
this.radialMenu.hideRadialMenu();
+2 -2
View File
@@ -6,10 +6,10 @@ import { GameType } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { MultiTabDetector } from "../../MultiTabDetector";
import { translateText } from "../../Utils";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
@customElement("multi-tab-modal")
export class MultiTabModal extends LitElement implements Layer {
export class MultiTabModal extends LitElement implements Controller {
public game: GameView;
private detector: MultiTabDetector;
@@ -13,10 +13,10 @@ import {
import type { LangSelector } from "../../LangSelector";
import { translateText } from "../../Utils";
import { FrameProfiler } from "../FrameProfiler";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
@customElement("performance-overlay")
export class PerformanceOverlay extends LitElement implements Layer {
export class PerformanceOverlay extends LitElement implements Controller {
@property({ type: Object })
public eventBus!: EventBus;
@@ -969,10 +969,6 @@ export class PerformanceOverlay extends LitElement implements Layer {
}
}
shouldTransform(): boolean {
return false;
}
private getPerformanceColor(fps: number): string {
if (fps >= 55) return "performance-good";
if (fps >= 30) return "performance-warning";
@@ -31,8 +31,8 @@ import {
IMAGE_ICON_KIND,
} from "../PlayerIcons";
import { TransformHandler } from "../TransformHandler";
import { Controller } from "./Controller";
import { ImmunityBarVisibleEvent } from "./ImmunityTimer";
import { Layer } from "./Layer";
import { CloseRadialMenuEvent } from "./RadialMenu";
import "./RelationSmiley";
import { SpawnBarVisibleEvent } from "./SpawnTimer";
@@ -68,7 +68,7 @@ function distSortUnitWorld(coord: { x: number; y: number }, game: GameView) {
}
@customElement("player-info-overlay")
export class PlayerInfoOverlay extends LitElement implements Layer {
export class PlayerInfoOverlay extends LitElement implements Controller {
@property({ type: Object })
public game!: GameView;
@@ -171,14 +171,6 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
this.requestUpdate();
}
renderLayer(context: CanvasRenderingContext2D) {
// Implementation for Layer interface
}
shouldTransform(): boolean {
return false;
}
setVisible(visible: boolean) {
this._isInfoVisible = visible;
this.requestUpdate();
+2 -2
View File
@@ -36,8 +36,8 @@ import {
} from "../../Utils";
import { UIState } from "../UIState";
import { ChatModal } from "./ChatModal";
import { Controller } from "./Controller";
import { EmojiTable } from "./EmojiTable";
import { Layer } from "./Layer";
import "./PlayerModerationModal";
import "./SendResourceModal";
const allianceIcon = assetUrl("images/AllianceIconWhite.svg");
@@ -53,7 +53,7 @@ const traitorIcon = assetUrl("images/TraitorIconLightRed.svg");
const breakAllianceIcon = assetUrl("images/TraitorIconWhite.svg");
@customElement("player-panel")
export class PlayerPanel extends LitElement implements Layer {
export class PlayerPanel extends LitElement implements Controller {
public g: GameView;
public eventBus: EventBus;
public emojiTable: EmojiTable;
+2 -10
View File
@@ -4,7 +4,7 @@ import { EventBus, GameEvent } from "../../../core/EventBus";
import { CloseViewEvent } from "../../InputHandler";
import { PlaySoundEffectEvent } from "../../sound/Sounds";
import { getSvgAspectRatio, translateText } from "../../Utils";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
import {
CenterButtonElement,
MenuElement,
@@ -51,7 +51,7 @@ type CenterButtonState = "default" | "back";
type RequiredRadialMenuConfig = Required<RadialMenuConfig>;
export class RadialMenu implements Layer {
export class RadialMenu implements Controller {
private menuElement: d3.Selection<HTMLDivElement, unknown, null, undefined>;
private tooltipElement: HTMLDivElement | null = null;
private isVisible: boolean = false;
@@ -1341,14 +1341,6 @@ export class RadialMenu implements Layer {
});
}
renderLayer(context: CanvasRenderingContext2D) {
// No need to render anything on the canvas
}
shouldTransform(): boolean {
return false;
}
private isReopeningAllowed(): boolean {
const now = Date.now();
const timeSinceHide = now - this.lastHideTime;
+2 -7
View File
@@ -8,7 +8,7 @@ import {
ReplaySpeedMultiplier,
} from "../../utilities/ReplaySpeedMultiplier";
import { translateText } from "../../Utils";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
export class ShowReplayPanelEvent {
constructor(
@@ -18,7 +18,7 @@ export class ShowReplayPanelEvent {
}
@customElement("replay-panel")
export class ReplayPanel extends LitElement implements Layer {
export class ReplayPanel extends LitElement implements Controller {
public game: GameView | undefined;
public eventBus: EventBus | undefined;
@@ -65,11 +65,6 @@ export class ReplayPanel extends LitElement implements Layer {
this.eventBus?.emit(new ReplaySpeedChangeEvent(value));
}
renderLayer(_ctx: CanvasRenderingContext2D) {}
shouldTransform() {
return false;
}
render() {
if (!this.visible) return html``;
+2 -2
View File
@@ -11,7 +11,7 @@ import {
SetBackgroundMusicVolumeEvent,
SetSoundEffectsVolumeEvent,
} from "../../sound/Sounds";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const structureIcon = assetUrl("images/CityIconWhite.svg");
const cursorPriceIcon = assetUrl("images/CursorPriceIconWhite.svg");
const darkModeIcon = assetUrl("images/DarkModeIconWhite.svg");
@@ -35,7 +35,7 @@ export class ShowSettingsModalEvent {
}
@customElement("settings-modal")
export class SettingsModal extends LitElement implements Layer {
export class SettingsModal extends LitElement implements Controller {
public eventBus: EventBus;
public userSettings: UserSettings;
+2 -6
View File
@@ -4,14 +4,14 @@ import { EventBus, GameEvent } from "../../../core/EventBus";
import { GameMode, GameType, Team } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { TransformHandler } from "../TransformHandler";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
export class SpawnBarVisibleEvent implements GameEvent {
constructor(public readonly visible: boolean) {}
}
@customElement("spawn-timer")
export class SpawnTimer extends LitElement implements Layer {
export class SpawnTimer extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
public transformHandler: TransformHandler;
@@ -95,10 +95,6 @@ export class SpawnTimer extends LitElement implements Layer {
}
}
shouldTransform(): boolean {
return false;
}
render() {
if (!this.isVisible) {
return html``;
@@ -30,14 +30,14 @@ import {
} from "../../Transport";
import { TransformHandler } from "../TransformHandler";
import { UIState } from "../UIState";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
/** True for nuke types (AtomBomb, HydrogenBomb): ghost is preserved after placement so user can place multiple or keep selection (Enter/key confirm). */
export function shouldPreserveGhostAfterBuild(unitType: UnitType): boolean {
return unitType === UnitType.AtomBomb || unitType === UnitType.HydrogenBomb;
}
export class StructureIconsLayer implements Layer {
export class StructureIconsLayer implements Controller {
/** Current ghost (null when no build type is active). */
private ghostUnit: { buildableUnit: BuildableUnit } | null = null;
private readonly connectedAllySmallIds: Set<number> = new Set();
+2 -8
View File
@@ -9,7 +9,7 @@ import {
renderTroops,
translateText,
} from "../../Utils";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
interface TeamEntry {
teamName: string;
@@ -26,7 +26,7 @@ interface TeamEntry {
}
@customElement("team-stats")
export class TeamStats extends LitElement implements Layer {
export class TeamStats extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
@@ -125,12 +125,6 @@ export class TeamStats extends LitElement implements Layer {
this.requestUpdate();
}
renderLayer(context: CanvasRenderingContext2D) {}
shouldTransform(): boolean {
return false;
}
render() {
if (!this.visible) return html``;
+2 -2
View File
@@ -16,7 +16,7 @@ import {
} from "../../InputHandler";
import { MoveWarshipIntentEvent } from "../../Transport";
import { TransformHandler } from "../TransformHandler";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const WARSHIP_SELECTION_RADIUS = 10;
@@ -29,7 +29,7 @@ const WARSHIP_SELECTION_RADIUS = 10;
* it stays in the Layer list for lifecycle hooks (init / tick / event
* subscriptions).
*/
export class UILayer implements Layer {
export class UILayer implements Controller {
// Currently selected single warship (game-logic readers use this; the
// visual is drawn by WebGL SelectionBoxPass).
private selectedUnit: UnitView | null = null;
+2 -2
View File
@@ -17,7 +17,7 @@ import {
} from "../../InputHandler";
import { renderNumber, translateText } from "../../Utils";
import { UIState } from "../UIState";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
const warshipIcon = assetUrl("images/BattleshipIconWhite.svg");
const cityIcon = assetUrl("images/CityIconWhite.svg");
const factoryIcon = assetUrl("images/FactoryIconWhite.svg");
@@ -31,7 +31,7 @@ const samLauncherIcon = assetUrl("images/SamLauncherIconWhite.svg");
const defensePostIcon = assetUrl("images/ShieldIconWhite.svg");
@customElement("unit-display")
export class UnitDisplay extends LitElement implements Layer {
export class UnitDisplay extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
public uiState: UIState;
+2 -8
View File
@@ -20,10 +20,10 @@ import {
import { crazyGamesSDK } from "../../CrazyGamesSDK";
import { Platform } from "../../Platform";
import { SendWinnerEvent } from "../../Transport";
import { Layer } from "./Layer";
import { Controller } from "./Controller";
@customElement("win-modal")
export class WinModal extends LitElement implements Layer {
export class WinModal extends LitElement implements Controller {
public game: GameView;
public eventBus: EventBus;
@@ -321,10 +321,4 @@ export class WinModal extends LitElement implements Layer {
}
});
}
renderLayer(/* context: CanvasRenderingContext2D */) {}
shouldTransform(): boolean {
return false;
}
}