快速开始:跑通第一局
本指南用两个浏览器窗口跑通一局两人对战:你的服务端建房并签发票据,alice 和 bob 在 Web 客户端加入、准备、互相看到对方的操作,最后你的服务端结束房间并收到结算回调。概念和规则见游戏房间概述。
1. 确认已开通
在控制台选好租户和应用,打开应用的「游戏房间」页。看到「接入」页和可用大区,说明已经可以使用;看到「当前套餐不含游戏房间」「游戏房间暂未开放」等提示时,按开通处理。

换取 App Token、创建用户和获取登录凭证的步骤同发送第一条消息。下文的 $IM_API、$ORG、$APP、$APP_TOKEN 含义见服务端接入概述。
2. 建房
在你的服务端执行:
curl -X PUT "$IM_API/$ORG/$APP/game/rooms/demo-match-1" \
-H "Authorization: Bearer $APP_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"第一局","max_players":2,"start_mode":"all_ready","tick_rate":20}'返回 201 和房间,room.status 为 open,room.region 是分到的大区。房间的全部参数见创建房间。
3. 签发加入票据
假设 alice 和 bob 已经是本应用的用户:
curl -X POST "$IM_API/$ORG/$APP/game/rooms/demo-match-1/tickets" \
-H "Authorization: Bearer $APP_TOKEN" -H "Content-Type: application/json" \
-d '{"users":[{"username":"alice","seat":0},{"username":"bob","seat":1}],"ttl_seconds":120}'响应的 tickets 里每人一张 ticket。通过你自己的、已鉴权的业务接口分别交给 alice 和 bob,不要交给其他人,也不要写进日志。票据 120 秒内有效,过期或丢了直接再签一次。
4. 玩家加入并对战
先按 Web 快速集成安装 @deeprespond/im-web(1.1.0 及以上)并登录。下面的代码在 alice 和 bob 的页面里各运行一次,ticketFromBusinessServer 是第 3 步交给这个玩家的票据:
const room = await im.game.join('demo-match-1', { ticket: ticketFromBusinessServer });
console.log('我的座位', room.seat, '成员', room.members);
// 每一帧:按帧号顺序收到所有座位这一帧的操作
room.onFrame((frame) => {
for (const input of frame.inputs) {
console.log(`第 ${frame.frame} 帧,座位 ${input.seat}:`, input.data);
}
});
room.onRoomState((e) => {
if (e.state === 'started') console.log('开局,从第', e.startFrame, '帧开始');
});
room.onClose((e) => console.log('对局结束', e.reason, e.result));
// 两个人都准备后开局(start_mode 为 all_ready)
room.ready();
// 开局后每帧发送本地操作(这里用一个字节代表按键)
setInterval(() => room.sendInput(new Uint8Array([room.seat === 0 ? 1 : 2])), 50);两个页面都准备后,控制台输出 开局,之后每帧都能看到双方的操作。关掉其中一个页面的网络再打开,它会自动重连回到原座位,缺的帧按顺序补齐。
5. 结束对局
在你的服务端执行:
curl -X POST "$IM_API/$ORG/$APP/game/rooms/demo-match-1/close" \
-H "Authorization: Bearer $APP_TOKEN" -H "Content-Type: application/json" \
-d '{"reason":"对局结束","result":{"winner":"alice"}}'返回 202。两个页面的 onClose 收到 reason 为 room_closed、result 为 { winner: 'alice' },SDK 不再重连。
6. 接收结算回调
在控制台「回调」页添加你的回调地址,订阅 game_room.closed。房间结束后几秒内你会收到这样的事件(只列出主要字段):

{
"type": "game_room.closed",
"data": {
"room_id": "demo-match-1",
"close_reason": "closed_by_server",
"duration_ms": 95000,
"result": { "winner": "alice" },
"members": [
{ "username": "alice", "seat": 0, "connected_ms": 98000, "billable_minutes": 2, "leave_reason": "room_closed" },
{ "username": "bob", "seat": 1, "connected_ms": 97000, "billable_minutes": 2, "leave_reason": "room_closed" }
]
}
}加入失败时
先看 im.game.errorKind(err) 的分类,再按这个顺序检查:
| 分类 | 先查什么 |
|---|---|
game_disabled | 套餐是否包含游戏房间、平台是否开放、应用是否被单独关闭 |
ticket_invalid | 票据是否给了正确的用户、是否过期或已经用过;让你的服务端重新签发 |
room_closed | 房间 ID 是否正确,房间是否已经结束 |
room_full、joined_on_other_device | 座位是否已满,这个用户是否已在别的设备上加入 |
node_unavailable、network | 稍后重试;仍然失败时记下错误码和请求 ID 联系我们 |
完整的错误表见 Web 客户端接入。
