From 3c3b19b2cebeb756fd5a2d5063018c145755deec Mon Sep 17 00:00:00 2001 From: josedario87 Date: Sun, 10 Aug 2025 18:14:53 -0600 Subject: [PATCH] mejoras de UI PlayerStats --- client/src/services/colyseus.ts | 18 ++++++- client/src/views/DemoGame.vue | 14 ++---- client/src/views/Lobby.vue | 41 +++++++++++++++- client/src/views/games/PlayerStats.vue | 65 ++++++++++++++++++++++++++ server/src/rooms/GameRoom.ts | 6 +++ server/src/rooms/LobbyRoom.ts | 21 ++++++++- server/src/rooms/schemas/LobbyState.ts | 4 +- server/src/rooms/schemas/Player.ts | 2 + 8 files changed, 155 insertions(+), 16 deletions(-) create mode 100644 client/src/views/games/PlayerStats.vue diff --git a/client/src/services/colyseus.ts b/client/src/services/colyseus.ts index da95476..0a3da5a 100644 --- a/client/src/services/colyseus.ts +++ b/client/src/services/colyseus.ts @@ -29,6 +29,7 @@ class ColyseusService { public gameRoom: Ref = ref(null); public playerName: Ref = ref(""); public sessionId: Ref = ref(""); + public playerColor: Ref = ref("#667eea"); constructor() { const defaultHost = typeof window !== "undefined" ? window.location.hostname : "localhost"; @@ -52,12 +53,17 @@ class ColyseusService { room.onMessage("welcome", (data) => { this.sessionId.value = data.sessionId; this.playerName.value = data.assignedName; + if (data.color) this.playerColor.value = data.color; }); room.onMessage("nameUpdated", (data) => { this.playerName.value = data.name; }); + room.onMessage("colorUpdated", (data) => { + if (data?.color) this.playerColor.value = data.color; + }); + return room; } catch (error) { console.error("Failed to join lobby:", error); @@ -71,6 +77,12 @@ class ColyseusService { } } + async setPlayerColor(color: string): Promise { + if (this.lobbyRoom.value) { + this.lobbyRoom.value.send("setColor", color); + } + } + async quickPlay(): Promise { if (!this.lobbyRoom.value) { throw new Error("Not in lobby"); @@ -86,7 +98,8 @@ class ColyseusService { // Join the game room directly using the roomId console.log('Joining game room with name:', this.playerName.value); const gameRoom = await this.client.joinById(data.roomId, { - playerName: this.playerName.value + playerName: this.playerName.value, + playerColor: this.playerColor.value }); // Ensure the room id is set @@ -124,7 +137,8 @@ class ColyseusService { async joinGameRoom(roomId: string): Promise { try { const gameRoom = await this.client.joinById(roomId, { - playerName: this.playerName.value + playerName: this.playerName.value, + playerColor: this.playerColor.value }); this.gameRoom.value = gameRoom; diff --git a/client/src/views/DemoGame.vue b/client/src/views/DemoGame.vue index 641fe51..67f6285 100644 --- a/client/src/views/DemoGame.vue +++ b/client/src/views/DemoGame.vue @@ -16,15 +16,7 @@
-
-
{{ p.name }}
-
Role: {{ p.role || '—' }}
-
- 🦃 {{ p.pavoTokens }} - 🌽 {{ p.eloteTokens }} - 😶 {{ p.shameTokens }} -
-
+
@@ -75,6 +67,7 @@ import G2 from './games/G2.vue'; import G3 from './games/G3.vue'; import G4 from './games/G4.vue'; import G5 from './games/G5.vue'; +import PlayerStats from './games/PlayerStats.vue'; import ChatWidget from './games/ChatWidget.vue'; const router = useRouter(); @@ -159,12 +152,14 @@ onMounted(() => { pavoTokens: player.pavoTokens, eloteTokens: player.eloteTokens, shameTokens: player.shameTokens, + color: player.color, }); } $(player).listen("role", (v: string) => { const p = players.value.find(x => x.sessionId === key); if (p) p.role = v; }); $(player).listen("pavoTokens", (v: number) => { const p = players.value.find(x => x.sessionId === key); if (p) p.pavoTokens = v; }); $(player).listen("eloteTokens", (v: number) => { const p = players.value.find(x => x.sessionId === key); if (p) p.eloteTokens = v; }); $(player).listen("shameTokens", (v: number) => { const p = players.value.find(x => x.sessionId === key); if (p) p.shameTokens = v; }); + $(player).listen("color", (v: string) => { const p = players.value.find(x => x.sessionId === key); if (p) p.color = v; }); }); $(room.state).players.onRemove((player: any, key: string) => { const i = players.value.findIndex(p => p.sessionId === key); @@ -212,7 +207,6 @@ function leaveGame() { colyseusService.leaveGame(); .btn-leave { background:#f44336; color:white; } .players-section { display:grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; margin: 12px 0; } .player-card { padding: 12px; background:#f8f9fa; border-radius: 10px; } -.player-card.current-player { outline: 2px solid #667eea; } .player-role { color:#666; margin-top: 4px; } .player-tokens { display:flex; gap: 12px; margin-top: 8px; } .waiting-area { text-align:center; padding: 24px 0; } diff --git a/client/src/views/Lobby.vue b/client/src/views/Lobby.vue index d6db03f..f6aee25 100644 --- a/client/src/views/Lobby.vue +++ b/client/src/views/Lobby.vue @@ -19,6 +19,13 @@
Playing as: {{ playerName || 'guest' }}
+
+ + +
+
+ +
@@ -72,6 +79,7 @@ + + diff --git a/server/src/rooms/GameRoom.ts b/server/src/rooms/GameRoom.ts index 9331605..b691e8c 100644 --- a/server/src/rooms/GameRoom.ts +++ b/server/src/rooms/GameRoom.ts @@ -180,8 +180,14 @@ export class GameRoom extends Room { // Use the playerName passed from the lobby - don't generate a new one! const playerName = options.playerName || "player"; + const playerColor = (options.playerColor && typeof options.playerColor === 'string') ? options.playerColor : "#667eea"; const player = this.state.addPlayer(client.sessionId, playerName); + // Persist selected color + const p = this.state.players.get(client.sessionId); + if (p) { + p.color = playerColor; + } client.send("playerInfo", { sessionId: client.sessionId, diff --git a/server/src/rooms/LobbyRoom.ts b/server/src/rooms/LobbyRoom.ts index 7449780..df96942 100644 --- a/server/src/rooms/LobbyRoom.ts +++ b/server/src/rooms/LobbyRoom.ts @@ -13,6 +13,10 @@ export class LobbyRoom extends Room { this.handleSetName(client, playerName); }); + this.onMessage("setColor", (client, color: string) => { + this.handleSetColor(client, color); + }); + this.onMessage("quickPlay", (client) => { this.handleQuickPlay(client); }); @@ -36,7 +40,8 @@ export class LobbyRoom extends Room { client.send("welcome", { sessionId: client.sessionId, - assignedName: uniqueName + assignedName: uniqueName, + color: this.state.players.get(client.sessionId)?.color || "#667eea" }); this.updateAvailableRooms(); @@ -80,6 +85,18 @@ export class LobbyRoom extends Room { }); } + private handleSetColor(client: Client, color: string) { + const currentPlayer = this.state.players.get(client.sessionId); + if (!currentPlayer) return; + const sanitized = (color || '').toString().trim(); + // Basic validation for hex color (#rgb or #rrggbb) + if (!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(sanitized)) { + return; + } + currentPlayer.color = sanitized; + client.send("colorUpdated", { color: sanitized }); + } + private async handleQuickPlay(client: Client) { const player = this.state.players.get(client.sessionId); if (!player || player.inGame) return; @@ -166,4 +183,4 @@ export class LobbyRoom extends Room { console.error("[LobbyRoom] Error updating available rooms:", error); } } -} \ No newline at end of file +} diff --git a/server/src/rooms/schemas/LobbyState.ts b/server/src/rooms/schemas/LobbyState.ts index 8d19572..824d3f1 100644 --- a/server/src/rooms/schemas/LobbyState.ts +++ b/server/src/rooms/schemas/LobbyState.ts @@ -4,12 +4,14 @@ export class LobbyPlayer extends Schema { @type("string") sessionId: string = ""; @type("string") name: string = ""; @type("boolean") inGame: boolean = false; + @type("string") color: string = "#667eea"; constructor(sessionId: string, name: string) { super(); this.sessionId = sessionId; this.name = name; this.inGame = false; + this.color = "#667eea"; } } @@ -58,4 +60,4 @@ export class LobbyState extends Schema { player.inGame = inGame; } } -} \ No newline at end of file +} diff --git a/server/src/rooms/schemas/Player.ts b/server/src/rooms/schemas/Player.ts index 54428ac..9cc75e4 100644 --- a/server/src/rooms/schemas/Player.ts +++ b/server/src/rooms/schemas/Player.ts @@ -9,6 +9,7 @@ export class Player extends Schema { @type("number") pavoTokens: number = 0; @type("number") eloteTokens: number = 0; @type("number") shameTokens: number = 0; + @type("string") color: string = "#667eea"; constructor(sessionId: string, name: string) { super(); @@ -20,6 +21,7 @@ export class Player extends Schema { this.pavoTokens = 0; this.eloteTokens = 0; this.shameTokens = 0; + this.color = "#667eea"; } incrementClicks(): void {