mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Create build menu
This commit is contained in:
@@ -13,6 +13,7 @@ import { EmojiTable } from "./layers/radial/EmojiTable";
|
||||
import { Leaderboard } from "./layers/Leaderboard";
|
||||
import { ControlPanel } from "./layers/ControlPanel";
|
||||
import { UIState } from "./UIState";
|
||||
import { BuildMenu } from "./layers/radial/BuildMenu";
|
||||
|
||||
|
||||
export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer {
|
||||
@@ -20,10 +21,17 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
|
||||
const uiState = { attackRatio: 20 }
|
||||
|
||||
// TODO maybe append this to dcoument instead of querying for them?
|
||||
const emojiTable = document.querySelector('emoji-table') as EmojiTable;
|
||||
if (!emojiTable || !(emojiTable instanceof EmojiTable)) {
|
||||
console.error('EmojiTable element not found in the DOM');
|
||||
}
|
||||
const buildMenu = document.querySelector('build-menu') as BuildMenu;
|
||||
if (!buildMenu || !(buildMenu instanceof BuildMenu)) {
|
||||
console.error('BuildMenu element not found in the DOM')
|
||||
}
|
||||
buildMenu.game = game
|
||||
buildMenu.eventBus = eventBus
|
||||
|
||||
const leaderboard = document.querySelector('leader-board') as Leaderboard;
|
||||
if (!emojiTable || !(leaderboard instanceof Leaderboard)) {
|
||||
@@ -55,7 +63,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
new NameLayer(game, game.config().theme(), transformHandler, clientID),
|
||||
new UILayer(eventBus, game, clientID, transformHandler),
|
||||
eventsDisplay,
|
||||
new RadialMenu(eventBus, game, transformHandler, clientID, emojiTable as EmojiTable, uiState),
|
||||
new RadialMenu(eventBus, game, transformHandler, clientID, emojiTable as EmojiTable, buildMenu, uiState),
|
||||
leaderboard,
|
||||
controlPanel,
|
||||
]
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import { LitElement, html, css } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { EventBus } from '../../../../core/EventBus';
|
||||
import { Cell, Game, Player } from '../../../../core/game/Game';
|
||||
import { SendNukeIntentEvent } from '../../../Transport';
|
||||
|
||||
interface BuildItem {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
cost: number;
|
||||
buildTime: number;
|
||||
}
|
||||
|
||||
const buildTable: BuildItem[][] = [
|
||||
[
|
||||
{ id: 'missile', name: 'Missile', icon: '🚀', cost: 100, buildTime: 5 },
|
||||
{ id: 'battleship', name: 'Battleship', icon: '🚢', cost: 500, buildTime: 20 }
|
||||
]
|
||||
];
|
||||
|
||||
@customElement('build-menu')
|
||||
export class BuildMenu extends LitElement {
|
||||
public game: Game;
|
||||
public eventBus: EventBus
|
||||
|
||||
|
||||
private myPlayer: Player
|
||||
private clickedCell: Cell
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.build-menu {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 9999;
|
||||
background-color: #1E1E1E;
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 95vw;
|
||||
max-height: 95vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.build-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.build-button {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 2px solid #444;
|
||||
background-color: #2C2C2C;
|
||||
color: white;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 8px;
|
||||
padding: 10px;
|
||||
}
|
||||
.build-button:hover {
|
||||
background-color: #3A3A3A;
|
||||
transform: scale(1.05);
|
||||
border-color: #666;
|
||||
}
|
||||
.build-button:active {
|
||||
background-color: #4A4A4A;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.build-icon {
|
||||
font-size: 40px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.build-name {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.build-cost {
|
||||
font-size: 12px;
|
||||
color: #FFD700;
|
||||
}
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.build-button {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 5px;
|
||||
}
|
||||
.build-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
.build-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
.build-cost {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 400px) {
|
||||
.build-button {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 3px;
|
||||
}
|
||||
.build-icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@state()
|
||||
private _hidden = true;
|
||||
|
||||
public onBuildSelected: (item: BuildItem) => void = () => {
|
||||
this.eventBus.emit(new SendNukeIntentEvent(this.myPlayer, this.clickedCell, null))
|
||||
this.hideMenu()
|
||||
};
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="build-menu ${this._hidden ? 'hidden' : ''}">
|
||||
${buildTable.map(row => html`
|
||||
<div class="build-row">
|
||||
${row.map(item => html`
|
||||
<button class="build-button" @click=${() => this.onBuildSelected(item)}>
|
||||
<span class="build-icon">${item.icon}</span>
|
||||
<span class="build-name">${item.name}</span>
|
||||
<span class="build-cost">${item.cost} 💰</span>
|
||||
</button>
|
||||
`)}
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
hideMenu() {
|
||||
this._hidden = true;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
showMenu(player: Player, clickedCell: Cell) {
|
||||
this.myPlayer = player
|
||||
this.clickedCell = clickedCell
|
||||
this._hidden = false;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
get isVisible() {
|
||||
return !this._hidden;
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,10 @@ import targetIcon from '../../../../../resources/images/TargetIconWhite.png';
|
||||
import emojiIcon from '../../../../../resources/images/EmojiIconWhite.png';
|
||||
import disabledIcon from '../../../../../resources/images/DisabledIcon.png';
|
||||
import donateIcon from '../../../../../resources/images/DonateIconWhite.png';
|
||||
import nukeIcon from '../../../../../resources/images/NukeIconWhite.png';
|
||||
import buildIcon from '../../../../../resources/images/BuildIcon.svg';
|
||||
import { EmojiTable } from "./EmojiTable";
|
||||
import { UIState } from "../../UIState";
|
||||
import { BuildMenu } from "./BuildMenu";
|
||||
|
||||
|
||||
enum Slot {
|
||||
@@ -25,7 +26,7 @@ enum Slot {
|
||||
Boat,
|
||||
Target,
|
||||
Emoji,
|
||||
Nuke,
|
||||
Build,
|
||||
}
|
||||
|
||||
export class RadialMenu implements Layer {
|
||||
@@ -38,7 +39,7 @@ export class RadialMenu implements Layer {
|
||||
[Slot.Boat, { name: "boat", disabled: true, action: () => { }, color: null, icon: null }],
|
||||
[Slot.Target, { name: "target", disabled: true, action: () => { } }],
|
||||
[Slot.Emoji, { name: "emoji", disabled: true, action: () => { } }],
|
||||
[Slot.Nuke, { name: "nuke", disabled: true, action: () => { } }],
|
||||
[Slot.Build, { name: "build", disabled: true, action: () => { } }],
|
||||
]);
|
||||
|
||||
private readonly menuSize = 190;
|
||||
@@ -55,6 +56,7 @@ export class RadialMenu implements Layer {
|
||||
private transformHandler: TransformHandler,
|
||||
private clientID: ClientID,
|
||||
private emojiTable: EmojiTable,
|
||||
private buildMenu: BuildMenu,
|
||||
private uiState: UIState
|
||||
) { }
|
||||
|
||||
@@ -230,8 +232,8 @@ export class RadialMenu implements Layer {
|
||||
return
|
||||
}
|
||||
|
||||
this.activateMenuElement(Slot.Nuke, "#ebe250", nukeIcon, () => {
|
||||
this.eventBus.emit(new SendNukeIntentEvent(myPlayer, this.clickedCell, null))
|
||||
this.activateMenuElement(Slot.Build, "#ebe250", buildIcon, () => {
|
||||
this.buildMenu.showMenu(myPlayer, this.clickedCell)
|
||||
})
|
||||
|
||||
if (tile.hasOwner()) {
|
||||
@@ -358,6 +360,7 @@ export class RadialMenu implements Layer {
|
||||
private onPointerUp(event: MouseUpEvent) {
|
||||
this.hideRadialMenu()
|
||||
this.emojiTable.hideTable()
|
||||
this.buildMenu.hideMenu()
|
||||
}
|
||||
|
||||
private showRadialMenu(x: number, y: number) {
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
<leader-board></leader-board>
|
||||
<control-panel></control-panel>
|
||||
<events-display></events-display>
|
||||
<build-menu></build-menu>
|
||||
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
|
||||
Reference in New Issue
Block a user