资讯专栏INFORMATION COLUMN

前端算法之弹幕设计

Bryan / 1129人阅读

摘要:本文愿从弹幕设计这个场景来描述算法在前端中的应用,我们先来看下实现效果图弹幕效果开场之前我们先来描述弹幕开发的难度,再集中精力描述算法设计的思路。轨道轨道这个角色很重要,它可以解决弹幕位置计算速度控制碰撞检测问题。

大家都说前端写页面较多,几乎用不到算法。本文愿从弹幕设计这个场景来描述算法在前端中的应用,我们先来看下实现效果:

                                    图1.1 弹幕效果

开场之前我们先来描述弹幕开发的难度,再集中精力描述算法设计的思路。

如何保证不同字号的弹幕不碰撞

弹幕的位置计算

弹幕的速度控制及动画实现

弹幕与视频的同步

如何保证不同字号的弹幕不碰撞

如果弹幕采用相同的字号,碰撞的问题处理起来比较简单,只要考虑相邻弹幕的播放速度和偏移的位置就可以计算出来。然而使用不同字号的弹幕处理起来就麻烦了许多,弹幕的起始位置不可以线性的增加,比如第一行放了字幕,接下来的字幕可以按顺序从上至下依次放置即可。

弹幕的位置计算

只有设计好弹幕的初始位置,才可以动态、高效的管理不同字号弹幕的碰撞问题。打个比方,我们通过接口获取了2秒之内的弹幕数据1000条,每个字幕的长度、速度、字号都不同,怎么管理这些弹幕,示意图如下:

                                图2.1 弹幕管理示意图

这是第一种情况,按照从上到啊的顺序依次摆放以后会有几个问题:

弹幕五、六、七该怎么计算位置,按top值循环取模+累加吗?

当弹幕一或者弹幕三足够长的时候,如何准时的跳过当前位置计算?

当前屏幕的弹幕播放结束,如何再计算的时候利用空出来的位置

空出的位置是否满足当前弹幕的高度

……

一系列问题就不统统列举出来了,基于这个背景我们结合数学建模的思维方式,找到了弹幕场景相似度非常高的机场运营。我们可以把弹幕当做飞机,每个时间段播放多少弹幕和机场每个时间段放飞多少飞机一个道理。

首都国际机场一共有3条跑道,两条4E级跑道、一条4F级跑道,2016年的吞吐量为9000万人次。它的运行机制就是所有飞机通过搭台有顺序的共用3条跑道来完成运输任务的。

同理,我们也设计了几个个角色:一个是轨道(跑道)、一个是调度(塔台)、一个是弹幕(飞机),我们为每个角色设计一个类分为为Track、Main、Bullet。

轨道

轨道这个角色很重要,它可以解决弹幕位置计算、速度控制、碰撞检测问题。
首先,我们要来初始化轨道。通俗的说我们要修建几个跑道呢,我们不是实物,可以动态调整轨道的 数量,计算的原则:

轨道数量 = 播放器有效高度 / 设备基准字号

播放器有效高度:播放器的实际高度减去控制条的高度,因为弹幕不可以遮挡控制条。

设备基准字号:移动端是10px,pc端是12px;
为啥计算公式是这样的?因为我们要支持不同字号的弹幕。试想不同的字号对物理空间的占用是不同的,然而如果要求轨道的尺寸是动态的,那就带来很复杂的计算。本文提出“虚拟轨道”的概念,在交通管制中最常见的就是道路合并或者改向。我们也是采用将相邻的物理轨道临时合并为一条轨道。这样就可以轻松的解决不同字号的轨道占用问题。原理图如下:

                        图2.2 轨道计算示意图

其次我们来回忆下机场的工作流程:

机长呼叫塔台,CZ6132请求起飞

目前跑道均被占用,请等待

N时刻后再次执行步骤1

目前跑道 A1 空闲,准许进入

执行步骤3

塔台查看跑道使用情况

进入跑道,起飞完成

机长通知塔台,本次起飞完成,释放跑道的占用

其他飞机同样执行上述步骤

按照这个思路,我们的弹幕工作流程:

弹幕进入播放器

轨道根据弹幕的播放速度、尺寸计算是否有合适的轨道提供

没有

通知弹幕尚无合适轨道提供,请等待;同时,弹幕队列中的其他弹幕依次执行步骤1

执行步骤3

播放器加载弹幕DOM,开始播放,待播放完成

播放完成通知轨道更新轨道占用情况

其他弹幕同样执行上述步骤

                            图2.3 轨道可用性计算示意图

关于轨道的基本原理我们整理清楚了,当然还有不少细节比如如何和调度通信、如何和弹幕通信以及虚拟轨道检测算法等。有兴趣的同学可以参考代码吧。https://github.com/bytedance/...

弹幕
弹幕基本是实现“飞机”的角色,我们要求它具有自身的属性和方法。比如调度中心通过id能拿到它所有的基本信息,轨道控制也可以通过弹幕进行检查和更新。当然弹幕也必须具备状态自动更新、移动、播放结束通知、自动销毁等功能。

调度

调度就是搭台的化身,承接着轨道、弹幕的控制,也保持着与播放器的步调一致。它的职责如下:

播放器交互控制

弹幕队列控制

自身状态更新

数据格式转换

动画执行
还是直接用流程图来描述更直接些:

在弹幕启动之后,首先要检查本地是否已有缓存数据,没有的话直接请求数据并缓存,然后执行数据读取,首次过滤数据进入弹幕队列,同时启动定时器。弹幕队列的数据会定期请求轨道,检测队列里的弹幕是否可以进入,一旦确认后轨道做好登记,弹幕就可以进入播放器开启动画播放了。定时器每隔2秒就会再次更新数据进入到弹幕队列(这块不同的业务可以定制不同的规则)。弹幕播放结束后会通知调度和轨道,调度会在弹幕队列中移除该弹幕实例,轨道也会移除该弹幕实例的轨道占用。

所有代码实现来自带解析器、能节省流量的西瓜播放器, Github

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/11078.html

相关文章

  • HTML5 CANVAS 弹幕插件--DanMuer.js(V3.2.5)

    摘要:主要是因为第二版中播放器模块和弹幕模块耦合得太严重了,远远达不到我想要的效果,所以续写了第三版。这里的通道是指弹幕从右往左运行时所在的那一行位置,这些通道是在尺寸变化时生成的,不同类型的弹幕都有其通道集合。 最新版本 V 3.2.5 新增了图片弹幕类型,修改了demo展示页面,调整了部分代码,具体请参看git里的CHANGELOG.md和README.md 文章里主要讲实现方法和设计思...

    FleyX 评论0 收藏0
  • HTML5 CANVAS 弹幕插件--DanMuer.js(V3.2.5)

    摘要:主要是因为第二版中播放器模块和弹幕模块耦合得太严重了,远远达不到我想要的效果,所以续写了第三版。这里的通道是指弹幕从右往左运行时所在的那一行位置,这些通道是在尺寸变化时生成的,不同类型的弹幕都有其通道集合。 最新版本 V 3.2.5 新增了图片弹幕类型,修改了demo展示页面,调整了部分代码,具体请参看git里的CHANGELOG.md和README.md 文章里主要讲实现方法和设计思...

    qpwoeiru96 评论0 收藏0

发表评论

0条评论

Bryan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<