弹幕排布:让滚动评论互不重叠
弹幕 (danmaku) 从屏幕右缘飞入、向左滚出。高峰期成百上千条同时出现,如何让它们<b>互不压字</b>?业界的事实标准是把屏幕横向切成等高的<b>轨道 (track / lane)</b>,弹幕只能落在某条轨道上,于是二维的重叠问题收敛成「同一轨道内,后一条会不会追上前一条」这个一维判定。本系列从轨道模型出发,逐步给出等速与变速两种判定,以及轨道占满后的降级取舍。
没有 RFC 那样的官方规范,但「轨道分层 + first-fit + 入场 / 追及判定 + 降级策略」是各家弹幕引擎 (Niconico、Bilibili 及众多开源实现) 公认的解法套路。数学内核只有两点:等速 → 只判进场间距;变速归一 → 解追及不等式。
模型:把屏幕切成轨道
为什么「切轨道」能把二维重叠降为一维追尾。
轨道模型:重叠从哪里来
对照无轨道吸附(随机高度、密集时压字)与轨道吸附 + first-fit(吸到空闲轨道、画面清爽)两种排布。轨道高度 = 行高,轨道之间纵向永不相交,于是只剩同轨道的横向追尾要管。
判定:何时进场不追尾
等速看一眼即可;变速归一要解一条不等式。
等速弹幕:入场只看间距
所有弹幕同速时,只要进场瞬间不撞、之后间距恒定就永不追尾。判定退化为一次性检查:该轨最后一条的右端是否已全部进屏 x + w ≤ W。单步逐条进场,探出右缘 = 占用、完全在屏 = 可用,代码行同步高亮。
变速归一:追及不等式
若要求每条弹幕停留时长一致,速度随宽度变化 v = (W+w)/T,宽的飞得快、可能追上前面的窄弹幕。拖动两条弹幕的宽度与发射间隔 Δ,单轨循环演示追尾,求出最小安全间隔 Δ_min = T·max(w/(W+w))。
策略:选轨与满载降级
first-fit 选轨,以及轨道占满时丢弃 / 排队 / 叠加的取舍。
选轨与降级:first-fit、丢弃、排队、叠加
常规选轨是自上而下取第一条可用轨道。真正的取舍在「全满怎么办」:丢弃(清爽但漏显)、排队(全显但延迟积压)、叠加(全显但压字)。可调到达率把轨道打满,实时对比三者的计数与画面。
它真实跑在哪里
相关链接
- Danmaku subtitling — Wikipedia en.wikipedia.org 弹幕字幕的由来 (Niconico → Bilibili)、滚动 / 顶部 / 底部三类弹幕的区分与文化背景。
- Interval scheduling / partitioning — Wikipedia en.wikipedia.org 把弹幕抽象为区间:互不重叠地放进最少的轨道,即 interval partitioning,first-fit 贪心是其标准解。
- Overtaking (kinematics) — Wikipedia en.wikipedia.org 追及问题的运动学背景:两个匀速物体何时相遇 / 追上,正是变速归一页追及不等式的物理原型。
- CommentCoreLibrary github.com 老牌开源弹幕渲染引擎,内部 CommentSpaceAllocator 即「轨道分配 + 进场判定 + 满载回退」的工程化实现。
- weizhenye/Danmaku github.com 轻量开源弹幕引擎,支持等速与「等时长」(变速归一) 两种滚动模式,可对照本系列的等速 / 变速判定。