mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 12:51:30 +00:00
separate optionsmenu from playerinfo menu
This commit is contained in:
@@ -21,6 +21,7 @@ import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
|
||||
import { GameView } from "../../core/game/GameView";
|
||||
import { WinModal } from "./layers/WinModal";
|
||||
import { SpawnTimer } from "./layers/SpawnTimer";
|
||||
import { OptionsMenu } from "./layers/OptionsMenu";
|
||||
|
||||
|
||||
export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventBus: EventBus, clientID: ClientID): GameRenderer {
|
||||
@@ -77,11 +78,18 @@ export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventB
|
||||
|
||||
|
||||
const winModel = document.querySelector('win-modal') as WinModal
|
||||
if (!(playerInfo instanceof WinModal)) {
|
||||
if (!(winModel instanceof WinModal)) {
|
||||
console.error('win modal not found')
|
||||
}
|
||||
winModel.game = game
|
||||
|
||||
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),
|
||||
@@ -95,7 +103,8 @@ export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventB
|
||||
leaderboard,
|
||||
controlPanel,
|
||||
playerInfo,
|
||||
winModel
|
||||
winModel,
|
||||
optionsMenu
|
||||
]
|
||||
|
||||
return new GameRenderer(game, eventBus, canvas, transformHandler, uiState, layers)
|
||||
@@ -148,16 +157,16 @@ export class GameRenderer {
|
||||
this.transformHandler.handleTransform(this.context)
|
||||
|
||||
this.layers.forEach(l => {
|
||||
if (l.shouldTransform()) {
|
||||
l.renderLayer(this.context)
|
||||
if (l.shouldTransform?.()) {
|
||||
l.renderLayer?.(this.context)
|
||||
}
|
||||
})
|
||||
|
||||
this.context.restore()
|
||||
|
||||
this.layers.forEach(l => {
|
||||
if (!l.shouldTransform()) {
|
||||
l.renderLayer(this.context)
|
||||
if (!l.shouldTransform?.()) {
|
||||
l.renderLayer?.(this.context)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -170,7 +179,7 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.layers.forEach(l => l.tick())
|
||||
this.layers.forEach(l => l.tick?.())
|
||||
}
|
||||
|
||||
resize(width: number, height: number): void {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Game } from "../../../core/game/Game"
|
||||
|
||||
export interface Layer {
|
||||
init()
|
||||
tick()
|
||||
renderLayer(context: CanvasRenderingContext2D)
|
||||
shouldTransform(): boolean
|
||||
init?()
|
||||
tick?()
|
||||
renderLayer?(context: CanvasRenderingContext2D)
|
||||
shouldTransform?(): boolean
|
||||
redraw?(): void
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
import { LitElement, html, css } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { EventBus } from '../../../core/EventBus';
|
||||
import { PauseGameEvent } from '../../Transport';
|
||||
import { GameType } from '../../../core/game/Game';
|
||||
import { GameView } from '../../../core/game/GameView';
|
||||
import { Layer } from './Layer';
|
||||
|
||||
@customElement('options-menu')
|
||||
export class OptionsMenu extends LitElement implements Layer {
|
||||
public game: GameView;
|
||||
public eventBus: EventBus;
|
||||
|
||||
@state()
|
||||
private showPauseButton: boolean = true;
|
||||
|
||||
@state()
|
||||
private isPaused: boolean = false;
|
||||
|
||||
private isVisible = false
|
||||
|
||||
private onExitButtonClick() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
private onPauseButtonClick() {
|
||||
this.isPaused = !this.isPaused;
|
||||
this.eventBus.emit(new PauseGameEvent(this.isPaused));
|
||||
}
|
||||
|
||||
init() {
|
||||
console.log('init called from OptionsMenu')
|
||||
this.showPauseButton = this.game.config().gameConfig().gameType == GameType.Singleplayer;
|
||||
this.isVisible = true
|
||||
this.requestUpdate()
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.isVisible = true
|
||||
this.requestUpdate()
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isVisible) {
|
||||
return html``
|
||||
}
|
||||
return html`
|
||||
<div class="controls">
|
||||
<button
|
||||
class="control-button pause-button ${!this.showPauseButton ? 'hidden' : ''}"
|
||||
@click=${this.onPauseButtonClick}
|
||||
aria-label="${this.isPaused ? 'Resume game' : 'Pause game'}"
|
||||
>
|
||||
${this.isPaused ? '▶' : '⏸'}
|
||||
</button>
|
||||
<button
|
||||
class="control-button exit-button"
|
||||
@click=${this.onExitButtonClick}
|
||||
aria-label="Exit game"
|
||||
>×</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
position: fixed; /* Make sure it's fixed positioning */
|
||||
top: 20px; /* Position it where you want */
|
||||
right: 10px;
|
||||
z-index: 1000; /* Make sure it's higher than canvas */
|
||||
pointer-events: auto; /* Ensure it can receive clicks */
|
||||
}
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.control-button {
|
||||
background: rgba(30, 30, 30, 0.7);
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s, background-color 0.2s;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.control-button:hover {
|
||||
opacity: 1;
|
||||
background: rgba(40, 40, 40, 0.8);
|
||||
}
|
||||
|
||||
.pause-button {
|
||||
font-size: 20px;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.control-button {
|
||||
font-size: 16px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
.pause-button {
|
||||
font-size: 14px;
|
||||
padding: 3px 8px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import { TransformHandler } from '../TransformHandler';
|
||||
import { MouseMoveEvent } from '../../InputHandler';
|
||||
import { GameView, PlayerView, UnitView } from '../../../core/game/GameView';
|
||||
import { TileRef } from '../../../core/game/GameMap';
|
||||
import { PauseGameEvent } from '../../Transport';
|
||||
import { renderNumber, renderTroops } from '../../Utils';
|
||||
|
||||
function euclideanDistWorld(coord: { x: number, y: number }, tileRef: TileRef, game: GameView): number {
|
||||
@@ -50,15 +49,9 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
@state()
|
||||
private unit: UnitView | null = null;
|
||||
|
||||
@state()
|
||||
private showPauseButton: boolean = true;
|
||||
|
||||
@state()
|
||||
private _isInfoVisible: boolean = false;
|
||||
|
||||
@state()
|
||||
private _isPaused: boolean = false;
|
||||
|
||||
private _isActive = false;
|
||||
|
||||
private lastMouseUpdate = 0
|
||||
@@ -66,7 +59,6 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
init() {
|
||||
this.eventBus.on(MouseMoveEvent, (e: MouseMoveEvent) => this.onMouseEvent(e));
|
||||
this._isActive = true;
|
||||
this.showPauseButton = this.game.config().gameConfig().gameType == GameType.Singleplayer;
|
||||
}
|
||||
|
||||
private onMouseEvent(event: MouseMoveEvent) {
|
||||
@@ -109,15 +101,6 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private onExitButtonClick() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
private onPauseButtonClick() {
|
||||
this._isPaused = !this._isPaused;
|
||||
this.eventBus.emit(new PauseGameEvent(this._isPaused));
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.requestUpdate();
|
||||
}
|
||||
@@ -201,19 +184,17 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="controls">
|
||||
<button class="control-button pause-button ${!this.showPauseButton ? 'hidden' : ''}" @click=${this.onPauseButtonClick}>
|
||||
${this._isPaused ? '▶' : '⏸'}
|
||||
</button>
|
||||
<button class="control-button exit-button" @click=${this.onExitButtonClick}>×</button>
|
||||
</div>
|
||||
<div class="player-info ${!this._isInfoVisible ? 'hidden' : ''}">
|
||||
${this.player != null ? this.renderPlayerInfo(this.player) : ''}
|
||||
${this.unit != null ? this.renderUnitInfo(this.unit) : ''}
|
||||
</div>
|
||||
<div class="container">
|
||||
<options-menu
|
||||
.game=${this.game}
|
||||
.eventBus=${this.eventBus}
|
||||
></options-menu>
|
||||
<div class="player-info ${!this._isInfoVisible ? 'hidden' : ''}">
|
||||
${this.player != null ? this.renderPlayerInfo(this.player) : ''}
|
||||
${this.unit != null ? this.renderUnitInfo(this.unit) : ''}
|
||||
</div>
|
||||
`;
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
@@ -223,7 +204,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
|
||||
.container {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
top: 70px;
|
||||
right: 10px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
|
||||
@@ -125,9 +125,9 @@
|
||||
<control-panel></control-panel>
|
||||
<events-display></events-display>
|
||||
<build-menu></build-menu>
|
||||
<options-menu></options-menu>
|
||||
<player-info-overlay></player-info-overlay>
|
||||
<win-modal></win-modal>
|
||||
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
document.body.style.visibility = 'visible';
|
||||
|
||||
Reference in New Issue
Block a user