본문으로 건너뛰기

로비 시스템

로비는 게임이 시작되기 전 플레이어들이 모이는 대기 공간입니다.

로비 구현

로비는 게임 룸의 특별한 상태로 구현할 수 있습니다:

typescript
const game = new GameRoom({
  appId: 'YOUR_APP_ID',
  clientId: 'player_123',
  publicKey: 'cb_pk_...'
})

await game.connect()

// 로비 룸 생성
const state = await game.createRoom({
  roomId: 'lobby-123',
  metadata: {
    type: 'lobby',
    status: 'waiting',  // waiting | starting | in_game
    hostId: 'player_123'
  }
})

로비 상태 관리

typescript
interface LobbyState {
  status: 'waiting' | 'countdown' | 'starting' | 'in_game'
  hostId: string
  players: {
    id: string
    ready: boolean
    team: 'red' | 'blue'
  }[]
  settings: {
    map: string
    gameMode: string
    maxRounds: number
  }
  countdown?: number
}

// 준비 상태 토글
game.sendAction({
  type: 'toggle_ready',
  data: { ready: true }
})

// 팀 변경
game.sendAction({
  type: 'change_team',
  data: { team: 'blue' }
})

// 설정 변경 (호스트만)
game.sendAction({
  type: 'update_settings',
  data: {
    map: 'arena',
    gameMode: 'deathmatch'
  }
})

로비 UI 예시

typescript
// 상태 업데이트 수신
game.on('onStateUpdate', (gameState) => {
  const lobby = gameState.state as LobbyState

  // UI 업데이트
  updatePlayerList(lobby.players)
  updateSettings(lobby.settings)
  updateStatus(lobby.status)

  // 카운트다운 표시
  if (lobby.countdown !== undefined) {
    showCountdown(lobby.countdown)
  }
})

// 플레이어 목록 렌더링
function updatePlayerList(players: LobbyState['players']) {
  const redTeam = players.filter(p => p.team === 'red')
  const blueTeam = players.filter(p => p.team === 'blue')

  renderTeam('red', redTeam)
  renderTeam('blue', blueTeam)
}

게임 시작 흐름

typescript
// 호스트가 게임 시작
function startGame() {
  const allReady = players.every(p => p.ready || p.id === hostId)

  if (!allReady) {
    alert('모든 플레이어가 준비되지 않았습니다')
    return
  }

  game.sendAction({
    type: 'start_game',
    data: {}
  })
}

// 카운트다운 처리
game.on('onStateUpdate', (gameState) => {
  const lobby = gameState.state as LobbyState

  if (lobby.status === 'countdown') {
    showCountdown(lobby.countdown)
  }

  if (lobby.status === 'in_game') {
    // 게임 씬으로 전환
    transitionToGame(gameState)
  }
})

로비 채팅

typescript
// 채팅 메시지 전송
function sendChatMessage(message: string) {
  game.sendChat(message)
}

// 채팅 메시지 수신
game.on('onChat', (msg) => {
  addChatMessage({
    sender: msg.clientId,
    text: msg.message,
    time: msg.serverTime
  })
})

호스트 마이그레이션

호스트가 나가면 다른 플레이어에게 호스트 권한 이전:

typescript
game.on('onPlayerLeft', (player) => {
  const lobby = game.state?.state as LobbyState

  // 호스트가 나간 경우
  if (player.clientId === lobby.hostId) {
    // 남은 플레이어 중 첫 번째를 새 호스트로
    const remaining = game.state?.players.filter(
      p => p.clientId !== player.clientId
    )

    if (remaining && remaining.length > 0) {
      const newHost = remaining[0].clientId
      game.sendAction({
        type: 'migrate_host',
        data: { newHostId: newHost }
      })
    }
  }
})