From 5a1295a0dad4e91f9744e117b6313af2eea3ec2f Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 30 Jan 2025 09:45:24 -0800 Subject: [PATCH] create topbar for mobile --- src/client/graphics/GameRenderer.ts | 312 ++++++++++++--------- src/client/graphics/layers/ControlPanel.ts | 2 +- src/client/graphics/layers/TopBar.ts | 66 +++++ src/client/index.html | 3 +- 4 files changed, 246 insertions(+), 137 deletions(-) create mode 100644 src/client/graphics/layers/TopBar.ts diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 2e5c23267..55b0f5a84 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -22,170 +22,212 @@ import { GameView } from "../../core/game/GameView"; import { WinModal } from "./layers/WinModal"; import { SpawnTimer } from "./layers/SpawnTimer"; import { OptionsMenu } from "./layers/OptionsMenu"; +import { TopBar } from "./layers/TopBar"; +export function createRenderer( + canvas: HTMLCanvasElement, + game: GameView, + eventBus: EventBus, + clientID: ClientID +): GameRenderer { + const transformHandler = new TransformHandler(game, eventBus, canvas); -export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventBus: EventBus, clientID: ClientID): GameRenderer { - const transformHandler = new TransformHandler(game, eventBus, canvas) + const uiState = { attackRatio: 20 }; - const uiState = { attackRatio: 20 } + // TODO maybe append this to dcoument instead of querying for them? + const emojiTable = document.querySelector("emoji-table") as EmojiTable; + if (!emojiTable || !(emojiTable instanceof EmojiTable)) { + consolex.error("EmojiTable element not found in the DOM"); + } + const buildMenu = document.querySelector("build-menu") as BuildMenu; + if (!buildMenu || !(buildMenu instanceof BuildMenu)) { + consolex.error("BuildMenu element not found in the DOM"); + } + buildMenu.game = game; + buildMenu.eventBus = eventBus; - // TODO maybe append this to dcoument instead of querying for them? - const emojiTable = document.querySelector('emoji-table') as EmojiTable; - if (!emojiTable || !(emojiTable instanceof EmojiTable)) { - consolex.error('EmojiTable element not found in the DOM'); - } - const buildMenu = document.querySelector('build-menu') as BuildMenu; - if (!buildMenu || !(buildMenu instanceof BuildMenu)) { - consolex.error('BuildMenu element not found in the DOM') - } - buildMenu.game = game - buildMenu.eventBus = eventBus + const leaderboard = document.querySelector("leader-board") as Leaderboard; + if (!emojiTable || !(leaderboard instanceof Leaderboard)) { + consolex.error("EmojiTable element not found in the DOM"); + } + leaderboard.clientID = clientID; + leaderboard.eventBus = eventBus; + leaderboard.game = game; - const leaderboard = document.querySelector('leader-board') as Leaderboard; - if (!emojiTable || !(leaderboard instanceof Leaderboard)) { - consolex.error('EmojiTable element not found in the DOM'); - } - leaderboard.clientID = clientID - leaderboard.eventBus = eventBus - leaderboard.game = game + const controlPanel = document.querySelector("control-panel") as ControlPanel; + if (!(controlPanel instanceof ControlPanel)) { + consolex.error("ControlPanel element not found in the DOM"); + } + controlPanel.clientID = clientID; + controlPanel.eventBus = eventBus; + controlPanel.uiState = uiState; + controlPanel.game = game; + const eventsDisplay = document.querySelector( + "events-display" + ) as EventsDisplay; + if (!(eventsDisplay instanceof EventsDisplay)) { + consolex.error("events display not found"); + } + eventsDisplay.eventBus = eventBus; + eventsDisplay.game = game; + eventsDisplay.clientID = clientID; - const controlPanel = document.querySelector('control-panel') as ControlPanel; - if (!(controlPanel instanceof ControlPanel)) { - consolex.error('ControlPanel element not found in the DOM'); - } - controlPanel.clientID = clientID - controlPanel.eventBus = eventBus - controlPanel.uiState = uiState - controlPanel.game = game + const playerInfo = document.querySelector( + "player-info-overlay" + ) as PlayerInfoOverlay; + if (!(playerInfo instanceof PlayerInfoOverlay)) { + consolex.error("player info overlay not found"); + } + playerInfo.eventBus = eventBus; + playerInfo.clientID = clientID; + playerInfo.transform = transformHandler; + playerInfo.game = game; - const eventsDisplay = document.querySelector('events-display') as EventsDisplay; - if (!(eventsDisplay instanceof EventsDisplay)) { - consolex.error('events display not found') - } - eventsDisplay.eventBus = eventBus - eventsDisplay.game = game - eventsDisplay.clientID = clientID + const winModel = document.querySelector("win-modal") as WinModal; + if (!(winModel instanceof WinModal)) { + console.error("win modal not found"); + } + winModel.eventBus = eventBus; + winModel.game = game; - const playerInfo = document.querySelector('player-info-overlay') as PlayerInfoOverlay - if (!(playerInfo instanceof PlayerInfoOverlay)) { - consolex.error('player info overlay not found') - } - playerInfo.eventBus = eventBus - playerInfo.clientID = clientID - playerInfo.transform = transformHandler - playerInfo.game = game + const optionsMenu = document.querySelector("options-menu") as OptionsMenu; + if (!(optionsMenu instanceof OptionsMenu)) { + console.error("options menu not found"); + } + optionsMenu.eventBus = eventBus; + optionsMenu.game = game; + const topBar = document.querySelector("top-bar") as TopBar; + if (!(topBar instanceof TopBar)) { + console.error("top bar not found"); + } + topBar.game = game; - const winModel = document.querySelector('win-modal') as WinModal - if (!(winModel instanceof WinModal)) { - console.error('win modal not found') - } - winModel.eventBus = eventBus - winModel.game = game + const layers: Layer[] = [ + new TerrainLayer(game), + new TerritoryLayer(game, eventBus), + new StructureLayer(game, eventBus), + new UnitLayer(game, eventBus, clientID), + new NameLayer(game, game.config().theme(), transformHandler, clientID), + eventsDisplay, + new RadialMenu( + eventBus, + game, + transformHandler, + clientID, + emojiTable as EmojiTable, + buildMenu, + uiState + ), + new SpawnTimer(game, transformHandler), + leaderboard, + controlPanel, + playerInfo, + winModel, + optionsMenu, + topBar, + ]; - const optionsMenu = document.querySelector('options-menu') as OptionsMenu - if (!(optionsMenu instanceof OptionsMenu)) { - console.log('options menu not found') - } - optionsMenu.eventBus = eventBus - optionsMenu.game = game - - - const layers: Layer[] = [ - new TerrainLayer(game), - new TerritoryLayer(game, eventBus), - new StructureLayer(game, eventBus), - new UnitLayer(game, eventBus, clientID), - new NameLayer(game, game.config().theme(), transformHandler, clientID), - eventsDisplay, - new RadialMenu(eventBus, game, transformHandler, clientID, emojiTable as EmojiTable, buildMenu, uiState), - new SpawnTimer(game, transformHandler), - leaderboard, - controlPanel, - playerInfo, - winModel, - optionsMenu - ] - - return new GameRenderer(game, eventBus, canvas, transformHandler, uiState, layers) + return new GameRenderer( + game, + eventBus, + canvas, + transformHandler, + uiState, + layers + ); } - export class GameRenderer { + private context: CanvasRenderingContext2D; - private context: CanvasRenderingContext2D + constructor( + private game: GameView, + private eventBus: EventBus, + private canvas: HTMLCanvasElement, + public transformHandler: TransformHandler, + public uiState: UIState, + private layers: Layer[] + ) { + this.context = canvas.getContext("2d"); + } - constructor(private game: GameView, private eventBus: EventBus, private canvas: HTMLCanvasElement, public transformHandler: TransformHandler, public uiState: UIState, private layers: Layer[]) { - this.context = canvas.getContext("2d") - } + initialize() { + this.eventBus.on(RedrawGraphicsEvent, (e) => { + this.layers.forEach((l) => { + if (l.redraw) { + l.redraw(); + } + }); + }); - initialize() { - this.eventBus.on(RedrawGraphicsEvent, (e) => { - this.layers.forEach(l => { - if (l.redraw) { - l.redraw() - } - }) - }) + this.layers.forEach((l) => l.init()); - this.layers.forEach(l => l.init()) + document.body.appendChild(this.canvas); + window.addEventListener("resize", () => this.resizeCanvas()); + this.resizeCanvas(); - document.body.appendChild(this.canvas); - window.addEventListener('resize', () => this.resizeCanvas()); - this.resizeCanvas(); + this.transformHandler = new TransformHandler( + this.game, + this.eventBus, + this.canvas + ); - this.transformHandler = new TransformHandler(this.game, this.eventBus, this.canvas) + requestAnimationFrame(() => this.renderGame()); + } - requestAnimationFrame(() => this.renderGame()); - } + resizeCanvas() { + this.canvas.width = window.innerWidth; + this.canvas.height = window.innerHeight; + //this.redraw() + } - resizeCanvas() { - this.canvas.width = window.innerWidth; - this.canvas.height = window.innerHeight; - //this.redraw() - } + renderGame() { + const start = performance.now(); + // Set background + this.context.fillStyle = this.game + .config() + .theme() + .backgroundColor() + .toHex(); + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); - renderGame() { - const start = performance.now() - // Set background - this.context.fillStyle = this.game.config().theme().backgroundColor().toHex(); - this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Save the current context state + this.context.save(); - // Save the current context state - this.context.save(); + this.transformHandler.handleTransform(this.context); - this.transformHandler.handleTransform(this.context) + this.layers.forEach((l) => { + if (l.shouldTransform?.()) { + l.renderLayer?.(this.context); + } + }); - this.layers.forEach(l => { - if (l.shouldTransform?.()) { - l.renderLayer?.(this.context) - } - }) + this.context.restore(); - this.context.restore() + this.layers.forEach((l) => { + if (!l.shouldTransform?.()) { + l.renderLayer?.(this.context); + } + }); - this.layers.forEach(l => { - if (!l.shouldTransform?.()) { - l.renderLayer?.(this.context) - } - }) + requestAnimationFrame(() => this.renderGame()); - requestAnimationFrame(() => this.renderGame()); + const duration = performance.now() - start; + if (duration > 50) { + console.warn( + `tick ${this.game.ticks()} took ${duration}ms to render frame` + ); + } + } - const duration = performance.now() - start - if (duration > 50) { - console.warn(`tick ${this.game.ticks()} took ${duration}ms to render frame`) - } - } + tick() { + this.layers.forEach((l) => l.tick?.()); + } - tick() { - this.layers.forEach(l => l.tick?.()) - } - - resize(width: number, height: number): void { - this.canvas.width = Math.ceil(width / window.devicePixelRatio); - this.canvas.height = Math.ceil(height / window.devicePixelRatio); - } - -} \ No newline at end of file + resize(width: number, height: number): void { + this.canvas.width = Math.ceil(width / window.devicePixelRatio); + this.canvas.height = Math.ceil(height / window.devicePixelRatio); + } +} diff --git a/src/client/graphics/layers/ControlPanel.ts b/src/client/graphics/layers/ControlPanel.ts index 6887a1627..596ece856 100644 --- a/src/client/graphics/layers/ControlPanel.ts +++ b/src/client/graphics/layers/ControlPanel.ts @@ -114,7 +114,7 @@ export class ControlPanel extends LitElement implements Layer { return html`