mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 08:11:54 +00:00
troop/worker slider shows current ratio
This commit is contained in:
@@ -10,10 +10,10 @@ import { SendSetTargetTroopRatioEvent } from '../../Transport';
|
|||||||
|
|
||||||
@customElement('control-panel')
|
@customElement('control-panel')
|
||||||
export class ControlPanel extends LitElement implements Layer {
|
export class ControlPanel extends LitElement implements Layer {
|
||||||
private game: Game
|
private game: Game;
|
||||||
public clientID: ClientID
|
public clientID: ClientID;
|
||||||
public eventBus: EventBus
|
public eventBus: EventBus;
|
||||||
public uiState: UIState
|
public uiState: UIState;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private attackRatio: number = .2;
|
private attackRatio: number = .2;
|
||||||
@@ -21,6 +21,9 @@ export class ControlPanel extends LitElement implements Layer {
|
|||||||
@state()
|
@state()
|
||||||
private targetTroopRatio = 1;
|
private targetTroopRatio = 1;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private currentTroopRatio = 1;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _population: number;
|
private _population: number;
|
||||||
|
|
||||||
@@ -43,40 +46,42 @@ export class ControlPanel extends LitElement implements Layer {
|
|||||||
private _manpower: number = 0;
|
private _manpower: number = 0;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _gold: number
|
private _gold: number;
|
||||||
|
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _goldPerSecond: number
|
private _goldPerSecond: number;
|
||||||
|
|
||||||
init(game: Game) {
|
init(game: Game) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.attackRatio = .20
|
this.attackRatio = .20;
|
||||||
this.uiState.attackRatio = this.attackRatio
|
this.uiState.attackRatio = this.attackRatio;
|
||||||
|
this.currentTroopRatio = this.targetTroopRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick() {
|
tick() {
|
||||||
// Update game state based on numTroops value if needed
|
|
||||||
if (!this._isVisible && !this.game.inSpawnPhase()) {
|
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()) {
|
if (player == null || !player.isAlive()) {
|
||||||
this.setVisibile(false)
|
this.setVisibile(false);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this._population = player.population()
|
|
||||||
this._maxPopulation = this.game.config().maxPopulation(player)
|
this._population = player.population();
|
||||||
this._gold = player.gold()
|
this._maxPopulation = this.game.config().maxPopulation(player);
|
||||||
this._troops = player.troops()
|
this._gold = player.gold();
|
||||||
this._workers = player.workers()
|
this._troops = player.troops();
|
||||||
this.popRate = this.game.config().populationIncreaseRate(player) * 10
|
this._workers = player.workers();
|
||||||
this._goldPerSecond = this.game.config().goldAdditionRate(player) * 10
|
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) {
|
onAttackRatioChange(newRatio: number) {
|
||||||
this.uiState.attackRatio = newRatio
|
this.uiState.attackRatio = newRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLayer(context: CanvasRenderingContext2D) {
|
renderLayer(context: CanvasRenderingContext2D) {
|
||||||
@@ -88,32 +93,28 @@ export class ControlPanel extends LitElement implements Layer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setVisibile(visible: boolean) {
|
setVisibile(visible: boolean) {
|
||||||
this._isVisible = visible
|
this._isVisible = visible;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
targetTroops(): number {
|
targetTroops(): number {
|
||||||
return this._manpower * this.targetTroopRatio
|
return this._manpower * this.targetTroopRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
onTroopChange(newRatio: number) {
|
onTroopChange(newRatio: number) {
|
||||||
this.eventBus.emit(new SendSetTargetTroopRatioEvent(newRatio))
|
this.eventBus.emit(new SendSetTargetTroopRatioEvent(newRatio));
|
||||||
}
|
}
|
||||||
|
|
||||||
delta(): number {
|
delta(): number {
|
||||||
const d = this._population - this.targetTroops()
|
const d = this._population - this.targetTroops();
|
||||||
// if (Math.abs(d) < this._manpower / 200) {
|
return d;
|
||||||
// return 0
|
|
||||||
// }
|
|
||||||
return d
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-panel {
|
.control-panel {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
@@ -127,13 +128,62 @@ export class ControlPanel extends LitElement implements Layer {
|
|||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
|
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slider-container {
|
.slider-container {
|
||||||
|
position: relative;
|
||||||
margin-bottom: 15px;
|
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 {
|
.control-panel-info {
|
||||||
color: white;
|
color: white;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
@@ -141,26 +191,77 @@ export class ControlPanel extends LitElement implements Layer {
|
|||||||
background-color: rgba(0, 0, 0, 0.3);
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-row {
|
.info-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-label {
|
.info-label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
display: block;
|
display: block;
|
||||||
color: white;
|
color: white;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
input[type="range"] {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.slider-value {
|
.slider-value {
|
||||||
color: white;
|
color: white;
|
||||||
text-align: right;
|
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() {
|
render() {
|
||||||
@@ -184,21 +285,39 @@ export class ControlPanel extends LitElement implements Layer {
|
|||||||
<span>${renderNumber(this._goldPerSecond)}</span>
|
<span>${renderNumber(this._goldPerSecond)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="slider-container">
|
<div class="slider-container">
|
||||||
<label for="numTroops">Troops: ${renderTroops(this._troops)} | Workers: ${renderTroops(this._workers)}</label>
|
<label>Troops: ${renderTroops(this._troops)} | Workers: ${renderTroops(this._workers)}</label>
|
||||||
<input type="range" id="numTroops" min="1" max="10" .value=${this.targetTroopRatio * 10}
|
<div class="slider-track"></div>
|
||||||
@input=${(e: Event) => {
|
<div class="slider-fill" style="width: ${this.currentTroopRatio * 100}%"></div>
|
||||||
this.targetTroopRatio = parseInt((e.target as HTMLInputElement).value) / 10;
|
<div class="slider-thumb" style="left: ${this.targetTroopRatio * 100}%"></div>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
.value=${this.targetTroopRatio * 100}
|
||||||
|
@input=${(e: Event) => {
|
||||||
|
this.targetTroopRatio = parseInt((e.target as HTMLInputElement).value) / 100;
|
||||||
this.onTroopChange(this.targetTroopRatio);
|
this.onTroopChange(this.targetTroopRatio);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="slider-container">
|
|
||||||
<label for="numTroops">Attack Ratio: ${this.attackRatio * 100}%</label>
|
<div class="attack-slider">
|
||||||
<input type="range" id="numTroops" min="1" max="10" value=${this.attackRatio * 10}
|
<label>Attack Ratio: ${(this.attackRatio * 100).toFixed(0)}%</label>
|
||||||
@input=${(e: Event) => {
|
<div class="slider-track"></div>
|
||||||
this.attackRatio = parseInt((e.target as HTMLInputElement).value) / 10;
|
<div class="slider-fill" style="width: ${this.attackRatio * 100}%"></div>
|
||||||
|
<div class="slider-thumb" style="left: ${this.attackRatio * 100}%"></div>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
.value=${this.attackRatio * 100}
|
||||||
|
@input=${(e: Event) => {
|
||||||
|
this.attackRatio = parseInt((e.target as HTMLInputElement).value) / 100;
|
||||||
this.onAttackRatioChange(this.attackRatio);
|
this.onAttackRatioChange(this.attackRatio);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ export class DefaultConfig implements Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
troopAdjustmentRate(player: Player): number {
|
troopAdjustmentRate(player: Player): number {
|
||||||
const maxDiff = this.maxPopulation(player) / 300
|
const maxDiff = this.maxPopulation(player) / 1000
|
||||||
const target = player.population() * player.targetTroopRatio()
|
const target = player.population() * player.targetTroopRatio()
|
||||||
const diff = target - player.troops()
|
const diff = target - player.troops()
|
||||||
if (Math.abs(diff) < maxDiff) {
|
if (Math.abs(diff) < maxDiff) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const devConfig = new class extends DefaultConfig {
|
|||||||
return 95
|
return 95
|
||||||
}
|
}
|
||||||
numSpawnPhaseTurns(): number {
|
numSpawnPhaseTurns(): number {
|
||||||
return 40
|
return 20
|
||||||
}
|
}
|
||||||
gameCreationRate(): number {
|
gameCreationRate(): number {
|
||||||
return 20 * 1000
|
return 20 * 1000
|
||||||
|
|||||||
Reference in New Issue
Block a user