Bingo 宾果游戏的本质是实时共同体验:一群人同时盯着自己的卡片,等待下一个号码被叫出。如果把这个体验搬到线上,延迟超过 300ms,共同就变成了“各自的”。本文以即构科技(ZEGO)的方案为例拆解在线 Bingo 的 RTC 架构设计,以及如何用低延迟信令 + 实时语音还原线下游戏的紧张感。
一、Bingo 游戏为什么需要 RTC?
先看一个线上 Bingo 的典型流程:
100 个玩家在 Bingo 房间中等待。主播开始摇号——「第 1 个号码……B-12!」,玩家在自己的卡片上找到 B-12 并标记。重复这个过程,直到有人连续 5 个标记连成一条线,大喊 “BINGO!”,游戏结束。
听起来很简单,但如果搬到线上,会出现以下问题:
- 主播喊「B-12」到玩家听到之间有延迟。如果玩家 A 的延迟是 100ms,玩家 B 的延迟是 2 秒(用了蓝牙耳机 + 4G 网络),B 公平性就没了
- BINGO 的判定需要在毫秒级完成。如果两个玩家同时喊 BINGO,系统必须知道谁先谁后,这个时间差可能是 50ms 级别
- 摇号结果必须绝对可信。不能出现主播悄悄换了个号码的情况,必须所有玩家同时收到结果且不可篡改
| 场景需求 | 核心指标 | 为什么难 |
|---|---|---|
| 摇号结果同步 | 全房间看到同一号码的间隔 < 100ms | 信令通道延迟决定了公平性 |
| 实时语音 | 端到端音频延迟 < 200ms | 主播叫号和玩家喊 BINGO 都要同时听到 |
| BINGO 判定 | 判定时间戳精度 < 50ms | 多个玩家同时喊 BINGO 时,需要精确到毫秒的排序 |
| 房间状态管理 | 卡片状态同步延迟 < 200ms | 每个玩家的卡片标记状态要让房间内所有人可见 |
| 弱网兼容 | 任何网络条件下都能听到叫号 | 画面可以卡,号码绝不能丢 |
二、整体架构:信令通道是核心,音频是体验,视频是辅助
在线 Bingo 的游戏逻辑非常集中:摇号 → 标记 → 判定。其中摇号和判定是两个关键时刻,这两个时刻的信息传递必须做到全员同时。
┌──────────────────────────────────────────────────────┐
│ 游戏逻辑层:Bingo 引擎 │
│ 摇号算法 · 卡片管理 · BINGO 判定 · 排行榜 │
├──────────────────────────────────────────────────────┤
│ 信令与消息通道(核心) │
│ 摇号广播 · 卡片状态同步 · BINGO 声明 · 时间戳服务器 │
│ → ZEGO ZIM / Express 内置信令通道 │
├───────────────────────┬──────────────────────────────┤
│ RTC 音频通道 │ 可选视频/屏幕共享 │
│ 主播叫号 · 玩家语音 │ 主播画面 + 卡片展示 │
│ → ZEGO Express SDK │ → Express + CDN 旁路 │
├───────────────────────┴──────────────────────────────┤
│ 基础设施层 │
│ SD-RTN™ 全球传输 · 边缘节点 · NTP 时钟同步 │
└──────────────────────────────────────────────────────┘
Bingo 对对信令通道的延迟和一致性要求极高。摇号结果必须全房间同时收到,BINGO 声明必须有明确的时间戳排序。
三、核心技术实现
3.1 摇号结果同步:100ms 内让 100 个人看到同一个号码
这是 Bingo 游戏最关键的技术点。摇号流程:
服务端(Bingo Engine)
│
│ 1. 随机生成号码 "B-12"
│ 2. 加盖时间戳: B-12 @ T=1680000000000
│ 3. 通过信令通道广播给房间内所有人
│
├────→ 玩家A (RTT 30ms) ── 收到 @ T+30ms ✓
├────→ 玩家B (RTT 50ms) ── 收到 @ T+50ms ✓
├────→ 玩家C (RTT 200ms) ── 收到 @ T+200ms (弱网)
└────→ 玩家D (RTT 40ms) ── 收到 @ T+40ms ✓
为什么用信令通道而不是音视频 SEI?
- 音视频 SEI 可能因网络丢包而丢失
- 信令通道可以加 ACK 确认和重传,保证绝对送达
- 号码数据量极小(几个字节),信令通道带宽充足
时间戳服务器的角色:服务端在生成每个号码时,都会标注一个 NTP 绝对时间戳。即使玩家在 200ms 后才收到(弱网),客户端显示的也是「B-12 于 T 时刻被摇出」,不会因为网络延迟而改变号码的生成时间——这是公平性的保证。
3.2 BINGO 判定:50ms 精度的时间戳排序
当两个玩家几乎同时喊 BINGO 时,系统需要判断谁先谁后。这个判定不能依赖玩家客户端的到达时间(受网络影响),必须基于玩家标记最后一个号码时的本地时间戳。
玩家A 服务端 玩家B
│ │ │
│ 标记 N-35 @ T_本地=1000 │ 标记 N-35 @ T_本地=1002
│ │ │
│ ──── BINGO声明(T_BINGO=1000)──→ │ ←── BINGO声明(T_BINGO=1002)─ │
│ │ │
│ 服务端比对时间戳: │
│ 玩家A: T_BINGO = 1000 ✓ 第一名 │
│ 玩家B: T_BINGO = 1002 ✗ 第二名 (差 2ms) │
│ │ │
│ ←── "恭喜,你是本局BINGO!" ── │ ── "可惜,慢了2ms" ──────→ │
信任模型:
- 客户端本地时间戳不可信(可以被篡改)
- 服务端在每个号码广播时都会附带 NTP 时间戳,客户端收到号码即记录该 NTP 时间戳作为标记时间
- BINGO 判定基于服务端 NTP 时间戳排序,而非客户端本地时间
- 即便两个玩家在同一毫秒标记最后一个号码(概率极低),以先提交 BINGO 声明到服务端的为准
这个设计的精妙之处:用业务逻辑绕开了分布式一致性难题:不需要所有客户端时钟严格同步,只要服务端时间戳是唯一的,判定就是确定的。
3.3 实时语音:主播叫号 + 玩家喊 BINGO
网上的 Bingo 游戏如果只有文字,体验是割裂的。看着号码弹出来,安静地点一下,像一个数据库查询操作。
加上实时语音后,体验立刻不同:主播叫号的声音、其他玩家的欢呼和叹息、最后关头有人喊 BINGO 时的集体停顿和释放,这些是游戏的灵魂。
// Bingo 游戏音频配置(ZEGO Express SDK C++ API)
// 创建引擎时选择语音场景
ZegoEngineProfile profile;
profile.appID = appID;
profile.appSign = appSign;
profile.scenario = ZegoScenario::ZEGO_SCENARIO_DEFAULT; // 语音通话场景
auto engine = ZegoExpressSDK::createEngine(profile, nullptr);
// 开启 3A 处理——主播端尤其重要
engine->enableAEC(true); // 消除回声(主播放背景音乐时)
engine->enableAGC(true); // 自动增益(多个玩家音量不一)
engine->enableANS(true); // 降噪(去除环境噪音)
// 登录房间并加入游戏
engine->loginRoom(bingoRoomID, user);
engine->startPublishingStream(streamID); // 推音频流(可以不开摄像头)
为什么用低码率 Opus?
- 24kbps Opus 即可覆盖人声全频带,Bingo 游戏中玩家只需要听清楚「B-12」「N-35」和「BINGO」。
- 上行 24kbps 在 2G 网络下也能稳定推流,这对全球化的 Bingo 游戏(覆盖东南亚、非洲等网络基础设施较差的地区)至关重要。
3.4 卡片状态同步:轻量级状态机
每个玩家的 Bingo 卡片是一张 5×5 的矩阵。当号码被叫出后,玩家在卡片上标记该号码。其他玩家不需要看到所有人的完整卡片,但需要知道:
- 有几个人已经标记了 3 个(即将 BINGO)
- 有几个人已经标记了 4 个(极度接近 BINGO)
- 是否有人已经喊了 BINGO
这是一个轻量级状态机,通过信令通道广播聚合状态而非全量状态:
服务端维护:
- 房间内 100 个玩家
- 公开状态:每人当前标记数 [3, 4, 5(BINGO)]
- 不公开:每个人的具体卡片布局
当玩家A标记一个号码后:
A → 服务端: "标记了 B-12,当前标记数 = 4"
服务端 → 全房间: "有人标记数 = 4 了!"
这种聚合广播既保护了玩家的策略隐私,又制造了游戏紧张感,比如“有人已经 4 个标记了,你还差 2 个”。
四、实战踩坑
坑 1:弱网玩家慢半拍的公平性问题
一个在 2G 网络下(RTT 500ms)的玩家,比 WiFi 玩家(RTT 20ms)晚 480ms 收到号码。在极端情况下,这 480ms 的差距可能导致对方先完成 BINGO。
解决思路:
- 倒计时缓冲:每个号码叫出后,给所有玩家一个统一的响应窗口(如 2 秒),在这个窗口内完成的标记视为同时收到。
- 提前下发号码:在主播即将念出号码之前,使用带序号的预广播,但这涉及到游戏体验的权衡,不建议过度技术化。
- 最务实的做法:在房间内展示网络质量分,让玩家自行选择加入低延迟房间或接受较高延迟。
坑 2:信令消息的到达顺序不一致
不同网络路径下,两个连续的摇号广播可能以不同的顺序到达不同玩家。
解决:每个摇号消息携带严格递增的序号,客户端按序号排序,不允许跳号处理:
玩家C收到: [seq=15, 16, 17] ← 正常
玩家D收到: [seq=15, 17, 16] ← 乱序!但客户端按序号重排后处理
坑 3:作弊风险,客户端篡改时间戳
玩家可以在客户端修改本地时间,让自己的标记时间提前。
解决:不信任任何客户端时间戳。BINGO 判定全部在服务端进行,客户端只提交「我标记了号码 X」,服务端根据「服务器收到该消息的时间戳」作为判定依据,完全消除客户端时间戳的影响。
五、FAQ
Q1:Bingo 游戏为什么不能用普通 WebSocket + HTTP 实现?
可以,但延迟会从 100ms 级上升到秒级。当延迟到 2-3 秒时,玩家会明显感觉公平性崩溃,比如“我明明先喊的 BINGO,为什么系统说别人赢了”。RTC 信令通道的 100ms 级延迟是游戏公平性的技术保障。
Q2:纯音频 Bingo 和音视频 Bingo 的成本差异有多大?
- 纯音频:每玩家约 24kbps 上行 + 24kbps 下行,100 人房间总带宽约 4.8Mbps
- 加视频(主播视频 + 卡片画面):主播端上行约 1-2Mbps,其他玩家只需下行音频
成本差异主要在主播端视频的 CDN 分发(如果观众多)。建议视频走 CDN 旁路推流,音频走 RTC。
Q3:ZEGO 的方案在 Bingo 场景有什么适配优势?
三个关键点:
- 信令通道与音视频共用一个 SDK。ZEGO Express SDK 内置信令通道处理摇号广播和状态同步,不需要额外接入 IM SDK,调参、排查、鉴权全部统一。
- 兼容的极低码率音频。Opus 24kbps 在极弱网下依然可懂,这对全球化 Bingo 产品覆盖东南亚、非洲等地区至关重要。
- NTP 时钟同步基础设施。SD-RTN™ 的边缘节点可以用作时间戳基准,BINGO 判定有了可靠的时间参照
六、总结
Bingo 游戏对 RTC 的需求非常「窄」但非常「深」——不需要 4K 画面,不需要万人并发,但要求在 100ms 内让 100 个人同时收到一个消息,并能以 50ms 精度判定谁先谁后。
关键结论:
- 信令通道延迟决定公平性:摇号广播和 BINGO 声明必须走 RTC 级信令,不能走 HTTP 轮询。
- 时间戳判定逻辑放在服务端:不信任客户端时间,消除作弊可能性。
- 音频用极低码率保底:24kbps Opus 在 3G 下也能跑,全球部署时考虑最差网络条件。
- 状态同步做聚合不做全量:保护隐私的同时制造游戏紧张感。
Bingo 是一个被低估的 RTC 应用场景。它没有演唱会的炫酷,没有云旅游的美景,但它对实时性的要求(精确、公平、毫秒级)恰恰是 RTC 技术的本质价值所在。
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/info/69108.html