From 7b1bab1e0fd809bfe2ce624eff7468331249cbe1 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 4 Nov 2024 19:17:12 -0800 Subject: [PATCH] troop/worker slider shows current ratio --- src/client/graphics/layers/ControlPanel.ts | 211 ++++++++++++++++----- src/core/configuration/DefaultConfig.ts | 2 +- src/core/configuration/DevConfig.ts | 2 +- 3 files changed, 167 insertions(+), 48 deletions(-) diff --git a/src/client/graphics/layers/ControlPanel.ts b/src/client/graphics/layers/ControlPanel.ts index 855c33669..9bd4a4da2 100644 --- a/src/client/graphics/layers/ControlPanel.ts +++ b/src/client/graphics/layers/ControlPanel.ts @@ -10,10 +10,10 @@ import { SendSetTargetTroopRatioEvent } from '../../Transport'; @customElement('control-panel') export class ControlPanel extends LitElement implements Layer { - private game: Game - public clientID: ClientID - public eventBus: EventBus - public uiState: UIState + private game: Game; + public clientID: ClientID; + public eventBus: EventBus; + public uiState: UIState; @state() private attackRatio: number = .2; @@ -21,6 +21,9 @@ export class ControlPanel extends LitElement implements Layer { @state() private targetTroopRatio = 1; + @state() + private currentTroopRatio = 1; + @state() private _population: number; @@ -43,40 +46,42 @@ export class ControlPanel extends LitElement implements Layer { private _manpower: number = 0; @state() - private _gold: number - + private _gold: number; @state() - private _goldPerSecond: number + private _goldPerSecond: number; init(game: Game) { this.game = game; - this.attackRatio = .20 - this.uiState.attackRatio = this.attackRatio + this.attackRatio = .20; + this.uiState.attackRatio = this.attackRatio; + this.currentTroopRatio = this.targetTroopRatio; } tick() { - // Update game state based on numTroops value if needed if (!this._isVisible && !this.game.inSpawnPhase()) { - this.setVisibile(true) + this.setVisibile(true); } - const player = this.game.playerByClientID(this.clientID) + const player = this.game.playerByClientID(this.clientID); if (player == null || !player.isAlive()) { - this.setVisibile(false) - return + this.setVisibile(false); + return; } - this._population = player.population() - this._maxPopulation = this.game.config().maxPopulation(player) - this._gold = player.gold() - this._troops = player.troops() - this._workers = player.workers() - this.popRate = this.game.config().populationIncreaseRate(player) * 10 - this._goldPerSecond = this.game.config().goldAdditionRate(player) * 10 + + this._population = player.population(); + this._maxPopulation = this.game.config().maxPopulation(player); + this._gold = player.gold(); + this._troops = player.troops(); + this._workers = player.workers(); + this.popRate = this.game.config().populationIncreaseRate(player) * 10; + this._goldPerSecond = this.game.config().goldAdditionRate(player) * 10; + + this.currentTroopRatio = player.troops() / player.population(); } onAttackRatioChange(newRatio: number) { - this.uiState.attackRatio = newRatio + this.uiState.attackRatio = newRatio; } renderLayer(context: CanvasRenderingContext2D) { @@ -88,32 +93,28 @@ export class ControlPanel extends LitElement implements Layer { } setVisibile(visible: boolean) { - this._isVisible = visible + this._isVisible = visible; this.requestUpdate(); } - targetTroops(): number { - return this._manpower * this.targetTroopRatio + return this._manpower * this.targetTroopRatio; } onTroopChange(newRatio: number) { - this.eventBus.emit(new SendSetTargetTroopRatioEvent(newRatio)) + this.eventBus.emit(new SendSetTargetTroopRatioEvent(newRatio)); } delta(): number { - const d = this._population - this.targetTroops() - // if (Math.abs(d) < this._manpower / 200) { - // return 0 - // } - return d + const d = this._population - this.targetTroops(); + return d; } - static styles = css` :host { display: block; } + .control-panel { position: fixed; bottom: 10px; @@ -127,13 +128,62 @@ export class ControlPanel extends LitElement implements Layer { backdrop-filter: blur(5px); transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; } + .hidden { opacity: 0; visibility: hidden; } + .slider-container { + position: relative; margin-bottom: 15px; + height: 48px; } + + .slider-track { + position: absolute; + width: 100%; + height: 8px; + background: rgba(255, 255, 255, 0.2); + border-radius: 4px; + top: 20px; + } + + .slider-fill { + position: absolute; + height: 8px; + background: rgba(0, 150, 255, 0.6); + border-radius: 4px; + top: 20px; + transition: width 0.3s ease-out; + } + + .slider-thumb { + position: absolute; + width: 16px; + height: 16px; + background: white; + border: 2px solid rgb(0, 150, 255); + border-radius: 50%; + top: 16px; + transform: translateX(-50%); + cursor: pointer; + transition: transform 0.1s ease; + } + + .slider-thumb:hover { + transform: translateX(-50%) scale(1.1); + } + + input[type="range"] { + position: absolute; + width: 100%; + top: 12px; + margin: 0; + opacity: 0; + cursor: pointer; + } + .control-panel-info { color: white; margin-bottom: 15px; @@ -141,26 +191,77 @@ export class ControlPanel extends LitElement implements Layer { background-color: rgba(0, 0, 0, 0.3); border-radius: 5px; } + .info-row { display: flex; justify-content: space-between; margin-bottom: 5px; } + .info-label { font-weight: bold; } + label { display: block; color: white; margin-bottom: 5px; } - input[type="range"] { - width: 100%; - } + .slider-value { color: white; text-align: right; } + + .attack-slider { + position: relative; + margin-bottom: 15px; + height: 48px; + } + + .attack-slider .slider-track { + position: absolute; + width: 100%; + height: 8px; + background: rgba(255, 255, 255, 0.2); + border-radius: 4px; + top: 20px; + } + + .attack-slider .slider-fill { + position: absolute; + height: 8px; + background: rgba(255, 0, 0, 0.6); + border-radius: 4px; + top: 20px; + transition: width 0.3s ease-out; + } + + .attack-slider .slider-thumb { + position: absolute; + width: 16px; + height: 16px; + background: white; + border: 2px solid rgb(255, 0, 0); + border-radius: 50%; + top: 16px; + transform: translateX(-50%); + cursor: pointer; + transition: transform 0.1s ease; + } + + .attack-slider .slider-thumb:hover { + transform: translateX(-50%) scale(1.1); + } + + .attack-slider input[type="range"] { + position: absolute; + width: 100%; + top: 12px; + margin: 0; + opacity: 0; + cursor: pointer; + } `; render() { @@ -184,21 +285,39 @@ export class ControlPanel extends LitElement implements Layer { ${renderNumber(this._goldPerSecond)} +
- - { - this.targetTroopRatio = parseInt((e.target as HTMLInputElement).value) / 10; + +
+
+
+ { + this.targetTroopRatio = parseInt((e.target as HTMLInputElement).value) / 100; this.onTroopChange(this.targetTroopRatio); - }}> + }} + >
-
- - { - this.attackRatio = parseInt((e.target as HTMLInputElement).value) / 10; + +
+ +
+
+
+ { + this.attackRatio = parseInt((e.target as HTMLInputElement).value) / 100; this.onAttackRatioChange(this.attackRatio); - }}> + }} + >
`; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index ceef2e7d4..332e4a534 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -163,7 +163,7 @@ export class DefaultConfig implements Config { } troopAdjustmentRate(player: Player): number { - const maxDiff = this.maxPopulation(player) / 300 + const maxDiff = this.maxPopulation(player) / 1000 const target = player.population() * player.targetTroopRatio() const diff = target - player.troops() if (Math.abs(diff) < maxDiff) { diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index 251d1178e..133237fdc 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -6,7 +6,7 @@ export const devConfig = new class extends DefaultConfig { return 95 } numSpawnPhaseTurns(): number { - return 40 + return 20 } gameCreationRate(): number { return 20 * 1000