Create build menu

This commit is contained in:
Evan
2024-11-02 21:40:03 -07:00
parent e77bb5e118
commit c3c3c27c73
6 changed files with 191 additions and 14 deletions
+9 -1
View File
@@ -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) {
+1
View File
@@ -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) => {