mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:40:44 +00:00
add # troops to UI
This commit is contained in:
@@ -83,24 +83,23 @@
|
||||
* BUG: attacks starts slow but gets faster DONE 9/2/2024
|
||||
* BUG: can't join game if click with 1s before start DONE 9/2/2024
|
||||
* boat not going around world dist vs distwrapped DONE 9/2/2024
|
||||
|
||||
* test & deploy game
|
||||
* test & deploy game DONE 9/2/2024
|
||||
|
||||
--- v2 Release
|
||||
|
||||
* put number of troops ui DONE 9/3/2024
|
||||
* boats leave trails
|
||||
* names don't appear when zoomed out
|
||||
* don't join game for reason
|
||||
* make names bigger
|
||||
* send boat even if touching
|
||||
* put number of troops ui
|
||||
* boats leave trails
|
||||
* directed expansion
|
||||
* more random names for game id & client id
|
||||
* Make fake humans
|
||||
* directed expansion
|
||||
* win condition & popup
|
||||
* BUG: tiles get left behind during conquer; still problem?
|
||||
* UI: win condition & popup
|
||||
* UI: boats
|
||||
* UI: current attacks
|
||||
* UI: leader board
|
||||
* Load terrain dataImage in background
|
||||
* BUG: shore tiles left behind during conquer
|
||||
* BUG: when sending boat to TerraNullius, only takes one tile
|
||||
* REFACTOR: give terranullius an ID, game.player() returns terranullius
|
||||
* REFACTOR: ocean is considered TerraNullius ?
|
||||
|
||||
@@ -16,7 +16,7 @@ export function createClientGame(name: string, clientID: ClientID, ip: string |
|
||||
let eventBus = new EventBus()
|
||||
let game = createGame(terrainMap, eventBus, config)
|
||||
let terrainRenderer = new TerrainRenderer(game)
|
||||
let gameRenderer = new GameRenderer(game, terrainRenderer)
|
||||
let gameRenderer = new GameRenderer(game, clientID, terrainRenderer)
|
||||
|
||||
return new ClientGame(
|
||||
name,
|
||||
|
||||
@@ -5,6 +5,9 @@ import {DragEvent, ZoomEvent} from "../InputHandler";
|
||||
import {NameRenderer} from "./NameRenderer";
|
||||
import {TerrainRenderer} from "./TerrainRenderer";
|
||||
import {TerritoryRenderer} from "./TerritoryRenderer";
|
||||
import {ClientID} from "../../core/Schemas";
|
||||
import {renderTroops} from "./Utils";
|
||||
import {UIRenderer} from "./UIRenderer";
|
||||
|
||||
export class GameRenderer {
|
||||
private territoryCanvas: HTMLCanvasElement
|
||||
@@ -20,16 +23,16 @@ export class GameRenderer {
|
||||
|
||||
private nameRenderer: NameRenderer;
|
||||
private territoryRenderer: TerritoryRenderer;
|
||||
private uiRenderer: UIRenderer;
|
||||
|
||||
private theme: Theme
|
||||
|
||||
private exitButton: HTMLButtonElement;
|
||||
|
||||
|
||||
constructor(private gs: Game, private terrainRenderer: TerrainRenderer) {
|
||||
constructor(private gs: Game, private clientID: ClientID, private terrainRenderer: TerrainRenderer) {
|
||||
this.theme = gs.config().theme()
|
||||
this.nameRenderer = new NameRenderer(gs, this.theme)
|
||||
this.territoryRenderer = new TerritoryRenderer(gs)
|
||||
this.uiRenderer = new UIRenderer(gs, this.theme, clientID)
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -46,6 +49,7 @@ export class GameRenderer {
|
||||
this.nameRenderer.initialize()
|
||||
this.terrainRenderer.init()
|
||||
this.territoryRenderer.init()
|
||||
this.uiRenderer.init()
|
||||
|
||||
|
||||
document.body.appendChild(this.canvas);
|
||||
@@ -59,53 +63,9 @@ export class GameRenderer {
|
||||
this.territoryContext = this.territoryCanvas.getContext('2d')
|
||||
this.territoryContext.globalAlpha = 0.4;
|
||||
|
||||
this.createExitButton()
|
||||
|
||||
|
||||
requestAnimationFrame(() => this.renderGame());
|
||||
}
|
||||
|
||||
|
||||
|
||||
createExitButton() {
|
||||
this.exitButton = document.createElement('button');
|
||||
this.exitButton.innerHTML = '✕'; // HTML entity for "×" (multiplication sign)
|
||||
this.exitButton.style.position = 'fixed';
|
||||
this.exitButton.style.top = '20px';
|
||||
this.exitButton.style.right = '20px';
|
||||
this.exitButton.style.zIndex = '1000';
|
||||
this.exitButton.style.width = '40px';
|
||||
this.exitButton.style.height = '40px';
|
||||
this.exitButton.style.fontSize = '20px';
|
||||
this.exitButton.style.fontWeight = 'bold';
|
||||
this.exitButton.style.backgroundColor = 'rgba(255, 0, 0, 0.4)'; // More translucent red
|
||||
this.exitButton.style.color = 'white';
|
||||
this.exitButton.style.border = 'none';
|
||||
this.exitButton.style.borderRadius = '50%';
|
||||
this.exitButton.style.cursor = 'pointer';
|
||||
this.exitButton.style.display = 'flex';
|
||||
this.exitButton.style.justifyContent = 'center';
|
||||
this.exitButton.style.alignItems = 'center';
|
||||
this.exitButton.style.transition = 'background-color 0.3s';
|
||||
|
||||
this.exitButton.addEventListener('mouseover', () => {
|
||||
this.exitButton.style.backgroundColor = 'rgba(255, 0, 0, 0.5)'; // Less translucent on hover
|
||||
});
|
||||
|
||||
this.exitButton.addEventListener('mouseout', () => {
|
||||
this.exitButton.style.backgroundColor = 'rgba(255, 0, 0, 0.3)'; // Back to more translucent
|
||||
});
|
||||
|
||||
this.exitButton.addEventListener('click', () => this.onExitButtonClick());
|
||||
document.body.appendChild(this.exitButton);
|
||||
}
|
||||
|
||||
onExitButtonClick() {
|
||||
console.log('Button clicked!');
|
||||
window.location.reload();
|
||||
// Add your button action here
|
||||
}
|
||||
|
||||
resizeCanvas() {
|
||||
this.canvas.width = window.innerWidth;
|
||||
this.canvas.height = window.innerHeight;
|
||||
@@ -147,11 +107,13 @@ export class GameRenderer {
|
||||
this.context.restore()
|
||||
|
||||
this.renderUIBar()
|
||||
this.uiRenderer.render(this.context)
|
||||
|
||||
requestAnimationFrame(() => this.renderGame());
|
||||
}
|
||||
|
||||
|
||||
// TODO: move to UIRenderer
|
||||
renderUIBar() {
|
||||
if (!this.gs.inSpawnPhase()) {
|
||||
return
|
||||
@@ -191,21 +153,6 @@ export class GameRenderer {
|
||||
this.canvas.height = Math.ceil(height / window.devicePixelRatio);
|
||||
}
|
||||
|
||||
// paintTerritory(tile: Tile) {
|
||||
// this.clearCell(tile.cell())
|
||||
// // if (!tile.hasOwner()) {
|
||||
// // this.clearCell(tile.cell())
|
||||
// // return
|
||||
// // }
|
||||
// // this.territoryContext.clearRect(tile.cell().x, tile.cell().y, 1, 1);
|
||||
// if (tile.isBorder()) {
|
||||
// this.territoryContext.fillStyle = this.theme.borderColor(tile.owner().id()).toRgbString()
|
||||
// } else {
|
||||
// this.territoryContext.fillStyle = this.theme.territoryColor(tile.owner().id()).alpha(100).toHex()
|
||||
// }
|
||||
// this.territoryContext.fillRect(tile.cell().x, tile.cell().y, 1, 1);
|
||||
// }
|
||||
|
||||
paintCell(cell: Cell, color: Colord) {
|
||||
color = color.alpha(10) // Assign the result back to color
|
||||
this.territoryContext.fillStyle = color.toHslString()
|
||||
|
||||
@@ -3,6 +3,7 @@ import {PseudoRandom} from "../../core/PseudoRandom"
|
||||
import {calculateBoundingBox} from "../../core/Util"
|
||||
import {Theme} from "../../core/configuration/Config"
|
||||
import {placeName} from "./NameBoxCalculator"
|
||||
import {renderTroops} from "./Utils"
|
||||
|
||||
class RenderInfo {
|
||||
public isVisible = true
|
||||
@@ -123,19 +124,7 @@ export class NameRenderer {
|
||||
|
||||
context.fillText(render.player.name(), nameCenterX, nameCenterY - render.fontSize / 2);
|
||||
context.font = `bold ${render.fontSize}px ${this.theme.font()}`;
|
||||
let troopsStr: string = ""
|
||||
let troops = render.player.troops() / 10
|
||||
|
||||
if (troops > 100000) {
|
||||
troopsStr = String(Math.floor(troops / 1000)) + "K"
|
||||
} else if (troops > 10000) {
|
||||
troopsStr = String((troops / 1000).toFixed(1)) + "K"
|
||||
} else if (troops > 1000) {
|
||||
troopsStr = String((troops / 1000).toFixed(2)) + "K"
|
||||
}
|
||||
else {
|
||||
troopsStr = String(Math.floor(troops))
|
||||
}
|
||||
context.fillText(troopsStr, nameCenterX, nameCenterY + render.fontSize);
|
||||
|
||||
context.fillText(renderTroops(render.player.troops()), nameCenterX, nameCenterY + render.fontSize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import {Theme} from "../../core/configuration/Config";
|
||||
import {Game} from "../../core/Game";
|
||||
import {ClientID} from "../../core/Schemas";
|
||||
import {renderTroops} from "./Utils";
|
||||
|
||||
export class UIRenderer {
|
||||
private exitButton: HTMLButtonElement;
|
||||
|
||||
constructor(private game: Game, private theme: Theme, private clientID: ClientID) {
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
this.createExitButton()
|
||||
}
|
||||
|
||||
createExitButton() {
|
||||
this.exitButton = document.createElement('button');
|
||||
this.exitButton.innerHTML = '✕'; // HTML entity for "×" (multiplication sign)
|
||||
this.exitButton.style.position = 'fixed';
|
||||
this.exitButton.style.top = '20px';
|
||||
this.exitButton.style.right = '20px';
|
||||
this.exitButton.style.zIndex = '1000';
|
||||
this.exitButton.style.width = '40px';
|
||||
this.exitButton.style.height = '40px';
|
||||
this.exitButton.style.fontSize = '20px';
|
||||
this.exitButton.style.fontWeight = 'bold';
|
||||
this.exitButton.style.backgroundColor = 'rgba(255, 0, 0, 0.4)'; // More translucent red
|
||||
this.exitButton.style.color = 'white';
|
||||
this.exitButton.style.border = 'none';
|
||||
this.exitButton.style.borderRadius = '50%';
|
||||
this.exitButton.style.cursor = 'pointer';
|
||||
this.exitButton.style.display = 'flex';
|
||||
this.exitButton.style.justifyContent = 'center';
|
||||
this.exitButton.style.alignItems = 'center';
|
||||
this.exitButton.style.transition = 'background-color 0.3s';
|
||||
|
||||
this.exitButton.addEventListener('mouseover', () => {
|
||||
this.exitButton.style.backgroundColor = 'rgba(255, 0, 0, 0.5)'; // Less translucent on hover
|
||||
});
|
||||
|
||||
this.exitButton.addEventListener('mouseout', () => {
|
||||
this.exitButton.style.backgroundColor = 'rgba(255, 0, 0, 0.3)'; // Back to more translucent
|
||||
});
|
||||
|
||||
this.exitButton.addEventListener('click', () => this.onExitButtonClick());
|
||||
document.body.appendChild(this.exitButton);
|
||||
}
|
||||
|
||||
render(context) {
|
||||
const p = this.game.players().find(p => p.clientID() == this.clientID);
|
||||
let troopCount = p ? `${renderTroops(p.troops())}` : '';
|
||||
|
||||
context.save();
|
||||
context.fillStyle = 'black';
|
||||
context.textAlign = 'center';
|
||||
context.textBaseline = 'top';
|
||||
|
||||
const x = 65 + 18 * (troopCount.length - 2); // Right edge of the text area
|
||||
const y = 40; // Distance from the top
|
||||
|
||||
context.font = `bold ${60}px ${this.theme.font()}`;
|
||||
context.fillText(troopCount, x, y);
|
||||
context.restore();
|
||||
}
|
||||
|
||||
onExitButtonClick() {
|
||||
console.log('Button clicked!');
|
||||
window.location.reload();
|
||||
// Add your button action here
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export function renderTroops(troops: number): string {
|
||||
let troopsStr = ''
|
||||
|
||||
troops = troops / 10
|
||||
|
||||
if (troops > 100000) {
|
||||
troopsStr = String(Math.floor(troops / 1000)) + "K"
|
||||
} else if (troops > 10000) {
|
||||
troopsStr = String((troops / 1000).toFixed(1)) + "K"
|
||||
} else if (troops > 1000) {
|
||||
troopsStr = String((troops / 1000).toFixed(2)) + "K"
|
||||
}
|
||||
else {
|
||||
troopsStr = String(Math.floor(troops))
|
||||
}
|
||||
return troopsStr
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {PlayerInfo} from "../Game";
|
||||
import {Player, PlayerInfo} from "../Game";
|
||||
import {DefaultConfig} from "./DefaultConfig";
|
||||
|
||||
export const devConfig = new class extends DefaultConfig {
|
||||
@@ -25,4 +25,13 @@ export const devConfig = new class extends DefaultConfig {
|
||||
}
|
||||
return 5000
|
||||
}
|
||||
|
||||
troopAdditionRate(player: Player): number {
|
||||
let max = Math.sqrt(player.numTilesOwned()) * 2000 + 10000 + 10000
|
||||
max = Math.min(max, 1_000_000)
|
||||
|
||||
let toAdd = 10 + (player.troops() + Math.sqrt(player.troops() * player.numTilesOwned())) / 200 * 100
|
||||
|
||||
return Math.min(player.troops() + toAdd, max)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user