← กรณีการใช้งาน

ห้องและล็อบบี้เกมผู้เล่นหลายคน

เกมปาร์ตี้ ควิซ บอร์ดเกม และเกมการ์ด: ห้องที่เข้าด้วยรหัส ที่นั่ง หัวห้อง สถานะพร้อม และแชต สร้างบนช่อง presence และอีเวนต์ฝั่งไคลเอนต์โดยไม่ต้องมีเกมเซิร์ฟเวอร์

เกมปาร์ตี้ ควิซ บอร์ดเกม เกมการ์ด และห้องดูด้วยกัน เริ่มต้นแบบเดียวกันหมด: รหัสห้อง รายชื่อคนที่อยู่ในห้อง ปุ่มพร้อม และหัวห้องที่กดเริ่ม ส่วนนี้ไม่ต้องใช้เกมเซิร์ฟเวอร์ ห้องคือช่อง presence และแพ็กเกจโอเพนซอร์ส @hibira-io/lobby จะเปลี่ยนมันเป็นที่นั่ง หัวห้อง สถานะพร้อม การเตะออก การเริ่มเกม และแชตในห้องบนเบราว์เซอร์

สิ่งที่ผู้เล่นได้รับ

  • ห้องที่เข้าได้ด้วยรหัสหรือลิงก์ ที่นั่งค่อยๆ เต็ม และเมื่อเต็มจะขึ้นว่า "ห้องเต็ม" ชัดเจน
  • สถานะพร้อม ป้ายหัวห้อง และปุ่มเริ่ม ที่ทุกคนเห็นพร้อมกัน
  • แชตในห้องพร้อมสถานะ "กำลังพิมพ์…" และเมื่อหัวห้องออก คนถัดไปจะเป็นหัวห้องแทน

ฟีเจอร์ที่ใช้

  • ช่อง presence (presence-) สำหรับรายชื่อคนในแต่ละห้อง
  • อีเวนต์ฝั่งไคลเอนต์ (client-*) สำหรับสถานะพร้อม การตั้งค่า การเริ่มเกม แชต และการเล่นระหว่างเกม ส่งจากเบราว์เซอร์ถึงเบราว์เซอร์
  • HTTP API (GET /channels?filter_by_prefix=presence-room-&info=user_count) ทำรายการห้องได้โดยไม่ต้องมีฐานข้อมูล
  • @hibira-io/lobby ที่รวมทั้งหมดนี้เป็นตรรกะของห้อง

ขั้นที่ 1: ยืนยันสิทธิ์เข้าห้องบนเซิร์ฟเวอร์

endpoint ยืนยันสิทธิ์จะตัดสินว่าใครเข้าได้ ลงลายเซ็นเวลาที่ผู้เล่นแต่ละคนเข้าห้อง และปฏิเสธเมื่อห้องเต็ม ผู้เล่นทุกคนเรียงลำดับห้องตามเวลานี้ จึงเห็นตรงกันว่าใครนั่งที่ไหนและใครเป็นหัวห้อง:

import Pusher from 'pusher';
import { authorizeRoom, listRooms, RoomFullError } from '@hibira-io/lobby/server';

const hibira = new Pusher({ appId, key, secret, host: 'ws.hibira.io', useTLS: true });

app.post('/rooms/auth', requireLogin, express.urlencoded({ extended: false }), async (req, res) => {
  try {
    res.json(await authorizeRoom(hibira, {
      socketId: req.body.socket_id,
      channel: req.body.channel_name,
      userId: req.user.id,
      userInfo: { name: req.user.name },
      capacity: 4,
    }));
  } catch (err) {
    res.status(err instanceof RoomFullError ? 403 : 500).end();
  }
});

// Room browser: [{ id: 'KQTZ', channel: 'presence-room-KQTZ', members: 3 }]
app.get('/rooms', async (req, res) => res.json(await listRooms(hibira)));

ขั้นที่ 2: เข้าห้องบนเบราว์เซอร์

เปิด อนุญาตอีเวนต์ฝั่งไคลเอนต์ ในการตั้งค่าแอปก่อน แล้ว:

import { Room } from '@hibira-io/lobby';

const room = Room.join(pusher, 'presence-room-KQTZ', { capacity: 4 });

room.on('members', ({ players, host }) => renderSeats(players, host));
room.on('message', (m) => chat.append(m.info.name, m.text));
room.on('full', () => show('This room is full'));

readyButton.onclick = () => room.setReady(!room.me.ready);
chatForm.onsubmit = () => room.send(input.value);
input.oninput = () => room.sendTyping();

room.players แสดงผู้เล่นตามลำดับที่นั่ง แต่ละคนมีค่า ready และ host การกระทำของคุณเองแสดงผลทันที และอีเวนต์ที่มีแต่หัวห้องส่งได้ ถ้าคนอื่นส่งมาจะถูกละเว้น

ขั้นที่ 3: เริ่มเกม

หัวห้องกดเริ่มเมื่อทุกคนพร้อม ข้อมูลที่ส่งให้ start() จะไปถึงผู้เล่นทุกคน เช่น จังหวะของแต่ละรอบ seed สุ่ม หรือที่อยู่ของเกมเซิร์ฟเวอร์:

if (room.isHost && room.allReady) room.start({ seed: 1234, rounds: 5 });

room.on('start', ({ data }) => game.begin(data));

การเล่นระหว่างเกมส่งเป็นอีเวนต์ฝั่งไคลเอนต์ในช่องเดียวกันได้ room.channel.trigger('client-move', move) หรือส่งผ่านเกมเซิร์ฟเวอร์ถ้าเกมต้องใช้

แบบเดียวกันใน Laravel

คืนเวลาที่เข้าห้องจาก callback ของช่อง presence แล้วใช้ช่องของ Echo.join():

// routes/channels.php
Broadcast::channel('room.{code}', function ($user, $code) {
    return ['id' => $user->id, 'name' => $user->name, 'joined_at' => (int) floor(microtime(true) * 1000)];
});
const room = new Room(Echo.join(`room.${code}`).subscription, { capacity: 4 });

ลองเล่น

ตัวอย่าง Reaction rooms เป็นเกม Next.js ที่สมบูรณ์: รายการห้อง ที่นั่งสี่ที่ ปุ่มพร้อม แชต และเกมวัดความไวห้ารอบ ใช้แอปแพ็กเกจฟรีได้

เคล็ดลับ

  • ห้องหนึ่งรับได้สูงสุด 100 คน ตามขีดจำกัดของช่อง presence
  • อีเวนต์ฝั่งไคลเอนต์แต่ละครั้งนับเป็นหนึ่งข้อความ ไม่ว่าจะมีผู้เล่นรับกี่คน เกมสั้นๆ สำหรับสี่คนส่งเพียงไม่กี่สิบครั้ง
  • หลังเกมเริ่ม ระบบเชื่อใจไคลเอนต์ ถ้าการโกงเป็นเรื่องสำคัญ ให้ตรวจผลบนเซิร์ฟเวอร์ หรือเก็บสถานะเกมไว้บนเกมเซิร์ฟเวอร์และใช้ห้องเป็นล็อบบี้เท่านั้น
  • พัฒนาด้วย Unity? ดู ล็อบบี้ การจับคู่ และกระดานคะแนนใน Unity