From 8aa3775bd81018e58ee73d9cb556a01f84cc02db Mon Sep 17 00:00:00 2001 From: evanpelle Date: Mon, 7 Jul 2025 15:20:44 -0700 Subject: [PATCH] move unit display to bottom of screen (#1365) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Using this design: https://cdn.discordapp.com/attachments/1391061082524881078/1391221235324551409/image.png?ex=686d157e&is=686bc3fe&hm=1027b79141dac471dcae4c002beb5f1425790bd282607efda5ff5bfb3e8fda83& Screenshot 2025-07-07 at 3 11 48 PM ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: evan --- src/client/graphics/GameRenderer.ts | 9 ++ src/client/graphics/layers/GameTopBar.ts | 158 +--------------------- src/client/graphics/layers/UnitDisplay.ts | 127 +++++++++++++++++ src/client/index.html | 1 + 4 files changed, 139 insertions(+), 156 deletions(-) create mode 100644 src/client/graphics/layers/UnitDisplay.ts diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 75a3e8e69..e75845173 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -35,6 +35,7 @@ import { TeamStats } from "./layers/TeamStats"; import { TerrainLayer } from "./layers/TerrainLayer"; import { TerritoryLayer } from "./layers/TerritoryLayer"; import { UILayer } from "./layers/UILayer"; +import { UnitDisplay } from "./layers/UnitDisplay"; import { UnitLayer } from "./layers/UnitLayer"; import { WinModal } from "./layers/WinModal"; @@ -158,6 +159,13 @@ export function createRenderer( gameTopBar.game = game; gameTopBar.eventBus = eventBus; + const unitDisplay = document.querySelector("unit-display") as UnitDisplay; + if (!(unitDisplay instanceof UnitDisplay)) { + console.error("unit display not found"); + } + unitDisplay.game = game; + unitDisplay.eventBus = eventBus; + const playerPanel = document.querySelector("player-panel") as PlayerPanel; if (!(playerPanel instanceof PlayerPanel)) { console.error("player panel not found"); @@ -238,6 +246,7 @@ export function createRenderer( leaderboard, gameLeftSidebar, gameTopBar, + unitDisplay, gameRightSidebar, controlPanel, playerInfo, diff --git a/src/client/graphics/layers/GameTopBar.ts b/src/client/graphics/layers/GameTopBar.ts index 0e98c31bc..377eed770 100644 --- a/src/client/graphics/layers/GameTopBar.ts +++ b/src/client/graphics/layers/GameTopBar.ts @@ -1,34 +1,23 @@ import { html, LitElement } from "lit"; import { customElement, query, state } from "lit/decorators.js"; -import cityIcon from "../../../../resources/images/CityIconWhite.svg"; import darkModeIcon from "../../../../resources/images/DarkModeIconWhite.svg"; import emojiIcon from "../../../../resources/images/EmojiIconWhite.svg"; import exitIcon from "../../../../resources/images/ExitIconWhite.svg"; import explosionIcon from "../../../../resources/images/ExplosionIconWhite.svg"; -import factoryIcon from "../../../../resources/images/FactoryIconWhite.svg"; import goldCoinIcon from "../../../../resources/images/GoldCoinIcon.svg"; -import missileSiloIcon from "../../../../resources/images/MissileSiloUnit.png"; import mouseIcon from "../../../../resources/images/MouseIconWhite.svg"; import ninjaIcon from "../../../../resources/images/NinjaIconWhite.svg"; import populationIcon from "../../../../resources/images/PopulationIconSolidWhite.svg"; -import portIcon from "../../../../resources/images/PortIcon.svg"; -import samLauncherIcon from "../../../../resources/images/SamLauncherUnitWhite.png"; import settingsIcon from "../../../../resources/images/SettingIconWhite.svg"; -import defensePostIcon from "../../../../resources/images/ShieldIconWhite.svg"; import treeIcon from "../../../../resources/images/TreeIconWhite.svg"; import troopIcon from "../../../../resources/images/TroopIconWhite.svg"; import workerIcon from "../../../../resources/images/WorkerIconWhite.svg"; import { translateText } from "../../../client/Utils"; import { EventBus } from "../../../core/EventBus"; -import { UnitType } from "../../../core/game/Game"; import { GameUpdateType } from "../../../core/game/GameUpdates"; import { GameView } from "../../../core/game/GameView"; import { UserSettings } from "../../../core/game/UserSettings"; -import { - AlternateViewEvent, - RefreshGraphicsEvent, - ToggleStructureEvent, -} from "../../InputHandler"; +import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler"; import { renderNumber, renderTroops } from "../../Utils"; import { Layer } from "./Layer"; @@ -37,16 +26,9 @@ export class GameTopBar extends LitElement implements Layer { public game: GameView; public eventBus: EventBus; private _userSettings: UserSettings = new UserSettings(); - private _selectedStructure: UnitType | null = null; private _population = 0; private _troops = 0; - private _cities = 0; - private _factories = 0; private _workers = 0; - private _missileSilo = 0; - private _port = 0; - private _defensePost = 0; - private _samLauncher = 0; private _lastPopulationIncreaseRate = 0; private _popRateIsIncreasing = false; private hasWinner = false; @@ -76,12 +58,6 @@ export class GameTopBar extends LitElement implements Layer { if (!player) return; this._troops = player.troops(); this._workers = player.workers(); - this._cities = player.totalUnitLevels(UnitType.City); - this._missileSilo = player.totalUnitLevels(UnitType.MissileSilo); - this._port = player.totalUnitLevels(UnitType.Port); - this._defensePost = player.totalUnitLevels(UnitType.DefensePost); - this._samLauncher = player.totalUnitLevels(UnitType.SAMLauncher); - this._factories = player.totalUnitLevels(UnitType.Factory); const updates = this.game.updatesSinceLastTick(); if (updates) { this.hasWinner = this.hasWinner || updates[GameUpdateType.Win].length > 0; @@ -145,12 +121,6 @@ export class GameTopBar extends LitElement implements Layer { this.eventBus.emit(new RefreshGraphicsEvent()); } - private onToggleStructureClick(structureType: UnitType) { - this._selectedStructure = - this._selectedStructure === structureType ? null : structureType; - this.eventBus.emit(new ToggleStructureEvent(this._selectedStructure)); - } - private onToggleRandomNameModeButtonClick() { this._userSettings.toggleRandomName(); } @@ -222,7 +192,7 @@ export class GameTopBar extends LitElement implements Layer { ? html`
-
-
- gold - ${renderNumber(this._cities)} -
-
- gold - ${renderNumber(this._factories)} -
-
- gold - ${renderNumber(this._port)} -
-
- gold - ${renderNumber(this._defensePost)} -
-
- gold - ${renderNumber(this._missileSilo)} -
-
- gold - ${renderNumber(this._samLauncher)} -
-
` diff --git a/src/client/graphics/layers/UnitDisplay.ts b/src/client/graphics/layers/UnitDisplay.ts new file mode 100644 index 000000000..e7c30bf51 --- /dev/null +++ b/src/client/graphics/layers/UnitDisplay.ts @@ -0,0 +1,127 @@ +import { html, LitElement } from "lit"; +import { customElement } from "lit/decorators.js"; +import cityIcon from "../../../../resources/images/CityIconWhite.svg"; +import factoryIcon from "../../../../resources/images/FactoryIconWhite.svg"; +import missileSiloIcon from "../../../../resources/images/MissileSiloUnit.png"; +import portIcon from "../../../../resources/images/PortIcon.svg"; +import samLauncherIcon from "../../../../resources/images/SamLauncherUnitWhite.png"; +import defensePostIcon from "../../../../resources/images/ShieldIconWhite.svg"; +import { EventBus } from "../../../core/EventBus"; +import { UnitType } from "../../../core/game/Game"; +import { GameView } from "../../../core/game/GameView"; +import { ToggleStructureEvent } from "../../InputHandler"; +import { renderNumber } from "../../Utils"; +import { Layer } from "./Layer"; + +@customElement("unit-display") +export class UnitDisplay extends LitElement implements Layer { + public game: GameView; + public eventBus: EventBus; + private _selectedStructure: UnitType | null = null; + private _cities = 0; + private _factories = 0; + private _missileSilo = 0; + private _port = 0; + private _defensePost = 0; + private _samLauncher = 0; + + createRenderRoot() { + return this; + } + + init() { + this.requestUpdate(); + } + + tick() { + const player = this.game?.myPlayer(); + if (!player) return; + this._cities = player.totalUnitLevels(UnitType.City); + this._missileSilo = player.totalUnitLevels(UnitType.MissileSilo); + this._port = player.totalUnitLevels(UnitType.Port); + this._defensePost = player.totalUnitLevels(UnitType.DefensePost); + this._samLauncher = player.totalUnitLevels(UnitType.SAMLauncher); + this._factories = player.totalUnitLevels(UnitType.Factory); + this.requestUpdate(); + } + + private renderUnitItem( + icon: string, + number: number, + unitType: UnitType, + altText: string, + ) { + if (this.game.config().isUnitDisabled(unitType)) { + return html``; + } + + return html` +
+ ${altText} + ${renderNumber(number)} +
+ `; + } + + render() { + const myPlayer = this.game?.myPlayer(); + if ( + !this.game || + !myPlayer || + this.game.inSpawnPhase() || + !myPlayer.isAlive() + ) { + return null; + } + + return html` + + `; + } +} diff --git a/src/client/index.html b/src/client/index.html index a7c7cd27d..d98fd4026 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -360,6 +360,7 @@ +