mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 07:50:45 +00:00
create leaderboard, max 18 char name
This commit is contained in:
@@ -10,6 +10,7 @@ import {Layer} from "./layers/Layer";
|
||||
import {EventsDisplay} from "./layers/EventsDisplay";
|
||||
import {RadialMenu} from "./layers/radial/RadialMenu";
|
||||
import {EmojiTable} from "./layers/radial/EmojiTable";
|
||||
import {Leaderboard} from "./layers/Leaderboard";
|
||||
|
||||
|
||||
export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer {
|
||||
@@ -19,6 +20,13 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
if (!emojiTable || !(emojiTable instanceof EmojiTable)) {
|
||||
console.error('EmojiTable element not found in the DOM');
|
||||
}
|
||||
|
||||
const leaderboard = document.querySelector('leader-board') as Leaderboard;
|
||||
if (!emojiTable || !(leaderboard instanceof Leaderboard)) {
|
||||
console.error('EmojiTable element not found in the DOM');
|
||||
}
|
||||
leaderboard.clientID = clientID
|
||||
|
||||
const layers: Layer[] = [
|
||||
new TerrainLayer(game),
|
||||
new TerritoryLayer(game, eventBus),
|
||||
@@ -26,6 +34,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
new UILayer(eventBus, game, clientID, transformHandler),
|
||||
new EventsDisplay(eventBus, game, clientID),
|
||||
new RadialMenu(eventBus, game, transformHandler, clientID, emojiTable as EmojiTable),
|
||||
leaderboard,
|
||||
]
|
||||
|
||||
return new GameRenderer(game, eventBus, canvas, transformHandler, layers)
|
||||
@@ -41,7 +50,7 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.layers.forEach(l => l.init())
|
||||
this.layers.forEach(l => l.init(this.game))
|
||||
|
||||
document.body.appendChild(this.canvas);
|
||||
window.addEventListener('resize', () => this.resizeCanvas());
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import {Game} from "../../../core/game/Game"
|
||||
import {TransformHandler} from "../TransformHandler"
|
||||
|
||||
export interface Layer {
|
||||
init()
|
||||
init(game: Game)
|
||||
tick()
|
||||
renderLayer(context: CanvasRenderingContext2D)
|
||||
shouldTransform(): boolean
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import {LitElement, html, css} from 'lit';
|
||||
import {customElement, property, state} from 'lit/decorators.js';
|
||||
import {Layer} from './Layer';
|
||||
import {Game, Player} from '../../../core/game/Game';
|
||||
import {ClientID} from '../../../core/Schemas';
|
||||
|
||||
interface Entry {
|
||||
name: string
|
||||
position: number
|
||||
score: number
|
||||
isMyPlayer: boolean
|
||||
}
|
||||
|
||||
@customElement('leader-board')
|
||||
export class Leaderboard extends LitElement implements Layer {
|
||||
|
||||
private game: Game
|
||||
public clientID: ClientID
|
||||
|
||||
init(game: Game) {
|
||||
this.game = game
|
||||
}
|
||||
|
||||
tick() {
|
||||
if (this._hidden && !this.game.inSpawnPhase()) {
|
||||
this.showLeaderboard()
|
||||
this.updateLeaderboard()
|
||||
}
|
||||
if (this._hidden) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.game.ticks() % 10 == 0) {
|
||||
this.updateLeaderboard()
|
||||
}
|
||||
}
|
||||
|
||||
private updateLeaderboard() {
|
||||
if (this.clientID == null) {
|
||||
return
|
||||
}
|
||||
const myPlayer = this.game.players().find(p => p.clientID() == this.clientID)
|
||||
if (myPlayer == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const sorted = this.game.players()
|
||||
.sort((a, b) => b.numTilesOwned() - a.numTilesOwned())
|
||||
|
||||
this.players = sorted
|
||||
.slice(0, 5)
|
||||
.map((player, index) => ({
|
||||
name: player.name(),
|
||||
position: index + 1,
|
||||
score: player.numTilesOwned(),
|
||||
isMyPlayer: player == myPlayer
|
||||
}));
|
||||
|
||||
if (this.players.find(p => p.isMyPlayer) == null) {
|
||||
let place = 0
|
||||
for (const p of sorted) {
|
||||
place++
|
||||
if (p == myPlayer) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.players.pop()
|
||||
this.players.push({
|
||||
name: myPlayer.name(),
|
||||
position: place,
|
||||
score: myPlayer.numTilesOwned(),
|
||||
isMyPlayer: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
this.requestUpdate()
|
||||
}
|
||||
|
||||
renderLayer(context: CanvasRenderingContext2D) {
|
||||
}
|
||||
shouldTransform(): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.leaderboard {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
z-index: 9999;
|
||||
background-color: #1E1E1E;
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||
border-radius: 10px;
|
||||
max-width: 300px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
width: 300px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #333;
|
||||
color: white;
|
||||
}
|
||||
th {
|
||||
background-color: #2C2C2C;
|
||||
color: white;
|
||||
}
|
||||
.myPlayer {
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #2C2C2C;
|
||||
}
|
||||
tr:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
`;
|
||||
|
||||
@property({type: Array})
|
||||
players: Entry[] = [];
|
||||
|
||||
@state()
|
||||
private _hidden = true;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="leaderboard ${this._hidden ? 'hidden' : ''}">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Player</th>
|
||||
<th>Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${this.players
|
||||
.map((player, index) => html`
|
||||
<tr class="${player.isMyPlayer ? 'myPlayer' : 'none'}">
|
||||
<td>${player.position}</td>
|
||||
<td>${player.name.slice(0, 12)}</td>
|
||||
<td>${player.score}</td>
|
||||
</tr>
|
||||
`)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
hideLeaderboard() {
|
||||
this._hidden = true;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
showLeaderboard() {
|
||||
this._hidden = false;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
get isVisible() {
|
||||
return !this._hidden;
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export class NameLayer implements Layer {
|
||||
return true
|
||||
}
|
||||
|
||||
public init() {
|
||||
public init(game: Game) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export class TerrainLayer implements Layer {
|
||||
tick() {
|
||||
}
|
||||
|
||||
init() {
|
||||
init(game: Game) {
|
||||
this.canvas = document.createElement('canvas');
|
||||
this.context = this.canvas.getContext("2d")
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export class TerritoryLayer implements Layer {
|
||||
tick() {
|
||||
}
|
||||
|
||||
init() {
|
||||
init(game: Game) {
|
||||
this.canvas = document.createElement('canvas');
|
||||
this.context = this.canvas.getContext("2d")
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export class UILayer implements Layer {
|
||||
tick() {
|
||||
}
|
||||
|
||||
init() {
|
||||
init(game: Game) {
|
||||
this.createExitButton()
|
||||
this.createWinModal()
|
||||
this.initRightClickMenu()
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
<div class="w-full max-w-3xl p-4 space-y-4">
|
||||
<!-- Username input -->
|
||||
<input type="text" id="username" placeholder="Enter your username"
|
||||
class="w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
|
||||
class="w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
maxlength="18">
|
||||
<!-- Button layout -->
|
||||
<div class="flex space-x-4 max-w-xs mx-auto">
|
||||
<!-- Single Player button -->
|
||||
@@ -80,13 +80,8 @@
|
||||
<div id="radialMenu" class="radial-menu"></div>
|
||||
|
||||
<emoji-table></emoji-table>
|
||||
<leader-board></leader-board>
|
||||
|
||||
<style>
|
||||
body {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
document.body.style.visibility = 'visible';
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import {LitElement, html, css} from 'lit';
|
||||
import {customElement, property} from 'lit/decorators.js';
|
||||
|
||||
@customElement('my-element')
|
||||
export class MyElement extends LitElement {
|
||||
@property()
|
||||
name = 'World';
|
||||
|
||||
render() {
|
||||
return html`<p>Hello, ${this.name}!</p>`;
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export class Executor {
|
||||
)
|
||||
} else if (intent.type == "spawn") {
|
||||
return new SpawnExecution(
|
||||
new PlayerInfo(intent.name, intent.playerType, intent.clientID, intent.playerID),
|
||||
new PlayerInfo(intent.name.slice(0, 18), intent.playerType, intent.clientID, intent.playerID),
|
||||
new Cell(intent.x, intent.y)
|
||||
)
|
||||
} else if (intent.type == "boat") {
|
||||
|
||||
Reference in New Issue
Block a user