Files
snatchgame/COLYSEUS-GUIA.md
josedario87 1912b3a76f docs: add contributor and Colyseus guides
feat(client): parametrize WS/API via VITE_WS_URL and VITE_API_URL; add .env.example and README env section
2025-08-07 17:10:08 -06:00

4.8 KiB

Colyseus: Guía de Integración para Snatchgame

Esta guía resume las APIs de Colyseus necesarias para: un lobby unificado, salas de juego (máx. 2 jugadores) y un dashboard para inspección/acciones por sala y globales.

Conceptos Clave

  • Rooms: unidades de ejecución con ciclo de vida (onCreate, onJoin, onLeave, onDispose).
  • Schema: sincroniza estado autoritativo del servidor a clientes con @type.
  • Mensajería: room.onMessage(type, handler), client.send(type, payload), room.broadcast(type, payload).
  • Matchmaker: descubrimiento/control de salas (matchMaker.query, remoteRoomCall, stats).
  • Monitor: panel listo para usar en Express (@colyseus/monitor).

Lobby Unificado

  • Definir una sala pública única lobby que gestione nombres, matchmaking y listado.
  • API útil: gameServer.define("lobby", LobbyRoom), setPrivate(false), enableRealtimeListing() en salas de juego para listar.
  • Mensajes recomendados: setName, quickPlay, joinRoom.

Ejemplo (server/src/rooms/LobbyRoom.ts):

export class LobbyRoom extends Room<LobbyState> {
  onCreate() {
    this.setState(new LobbyState());
    this.onMessage("setName", (client, name) => {/* validar + asignar */});
    this.onMessage("quickPlay", async (client) => {
      // Crear o elegir una sala "game" con cupo
      const rooms = await matchMaker.query({ name: "game", locked: false });
      const target = rooms.find(r => r.clients < r.maxClients) ||
                     await matchMaker.createRoom("game", { maxClients: 2 });
      client.send("gameJoined", { roomId: target.roomId || target.roomId });
    });
  }
}

Game Rooms (2 jugadores)

  • Definición: gameServer.define("game", GameRoom).filterBy(["maxClients"]).enableRealtimeListing().
  • Capacidad: maxClients = 2; en la clase de la sala.
  • Re-conexión: await this.allowReconnection(client, 30); para tolerancia a fallos.
  • Ticks: usar this.setSimulationInterval((deltaTime) => { /* actualizar timer */ }, 1000);.

Ejemplo (server/src/rooms/GameRoom.ts):

export class GameRoom extends Room<GameState> {
  maxClients = 2;
  onCreate() {
    this.setState(new GameState());
    this.onMessage("click", (client) => {/* sumar clicks si PLAYING */});
  }
  onJoin(client, { playerName }) {
    this.state.addPlayer(client.sessionId, playerName);
    if (this.state.players.size === 2) this.state.startGame();
  }
  onLeave(client) {
    this.state.players.get(client.sessionId)!.connected = false;
    this.allowReconnection(client, 30);
  }
}

Estado Autoritativo (Schema)

  • Definir modelos con @type y colecciones MapSchema/ArraySchema.
  • Patrón: solo el servidor muta estado; clientes envían mensajes de intención.

Ejemplo:

export class GameState extends Schema {
  @type({ map: Player }) players = new MapSchema<Player>();
  @type("string") gameStatus: GameStatus = GameStatus.WAITING;
  @type("number") timeRemaining = 600;
}

Dashboard y Control Administrativo

  • Monitor integrado: app.use("/colyseus", monitor()); para ver salas/CCU.
  • REST/Admin personalizado vía matchMaker:
    • Listar: await matchMaker.query({ name: "game" });
    • Llamar métodos remotos: await matchMaker.remoteRoomCall(roomId, "getState");
    • Acciones por sala: await matchMaker.remoteRoomCall(roomId, "broadcast", ["admin:pause"]);

Ejemplos (server/src/adminApi.ts):

router.get("/rooms", async (_, res) => {
  const rooms = await matchMaker.query({});
  res.json(rooms);
});
router.post("/rooms/:roomId/restart", async (req, res) => {
  await matchMaker.remoteRoomCall(req.params.roomId, "broadcast", ["admin:restart"]);
  res.json({ success: true });
});

Acciones globales (todas las salas "game"):

const rooms = await matchMaker.query({ name: "game" });
await Promise.all(rooms.map(r => matchMaker.remoteRoomCall(r.roomId, "broadcast", ["admin:pause"])));

Buenas Prácticas

  • Validar inputs en onMessage y nunca confiar en el cliente.
  • Usar metadata/filterBy para matchmaking por atributos.
  • Mantener maxClients y reglas de inicio/pausa dentro del servidor.
  • Exponer solo métodos necesarios para remoteRoomCall (p. ej., getState).

Referencias: documentación oficial Colyseus (Rooms, Schema, Matchmaker, Monitor).

Configuración de WebSocket (Cliente)

  • Variable de entorno en Vite: VITE_WS_URL.
  • Si no se define, el cliente usa ws(s)://<hostname>:3000 según el protocolo actual.
  • Ejemplos:
    • Desarrollo local: VITE_WS_URL=ws://localhost:3000
    • Producción (TLS): VITE_WS_URL=wss://api.midominio.com

Configuración de REST API (Cliente)

  • Variable de entorno en Vite: VITE_API_URL con la base completa del API (incluye /api).
  • Si no se define, el cliente usa http(s)://<hostname>:3000/api según el protocolo actual.
  • Ejemplos:
    • Desarrollo local: VITE_API_URL=http://localhost:3000/api
    • Producción (TLS): VITE_API_URL=https://api.midominio.com/api