大家都说前端写的页面很多,几乎没有用到算法。本文想从弹幕设计的场景来描述算法在前端的应用。先来看一下实现效果:图1.1弹幕效果开篇前先描述弹幕开发的难点,然后着重描述算法设计的思路。如何保证不同字号的弹幕不会和弹幕的位置发生碰撞?计算弹幕的速度控制和动画,实现弹幕与视频的同步。如何保证不同字号的弹幕不冲突。比较简单,只要考虑相邻弹幕的播放速度和偏移位置,就可以计算出来。但是,使用不同字体大小的弹幕要麻烦很多。弹幕起始位置不能线性增加。例如,如果字幕放在第一行,则后面的字幕可以按从上到下的顺序放置。弹幕位置计算只有设计好弹幕的初始位置,才能动态高效地管理不同字号弹幕的碰撞问题。比如我们通过接口获取2秒内1000条弹幕数据,每条字幕的长度、速度、字体大小都不一样。这些弹幕的管理方法如下:图2.1弹幕管理示意图这是第一种情况,从上到啊依次排列后,会出现几个问题:如何计算弹幕的位置五六七,根据最高值取模+累加?当弹幕1或弹幕3足够长时,如何准时跳过当前位置计算?当当前屏幕的弹幕弹完后,如何利用腾出的位置来计算腾出的位置是否满足当前弹幕的高度……一系列的问题就不一一列举了。基于这样的背景,我们结合数学建模的思路,在弹幕场景中找到了一个相似度非常高的机场运营。我们可以把弹幕看成是一架飞机。每个时间段播放多少弹幕,就等于每个时间段机场放多少架飞机。首都国际机场拥有3条跑道,2条4E跑道和1条4F跑道,2016年旅客吞吐量9000万人次,其运行机制是所有飞机共用3条跑道完成运输任务。同样的,我们也设计了几个角色:一个是轨道(跑道),一个是调度(塔台),一个是弹幕(飞机)。我们为每个角色设计一个类,分为Track,Main,Bullet。Track轨道的作用非常重要,它可以解决弹幕位置计算、速度控制、碰撞检测等问题。首先,我们要初始化轨道。通俗地说,我们要建多少条跑道?我们不是真实的物体,我们可以动态调整轨道数量。计算原则为:曲目数=播放器有效高度/设备参考字体大小。玩家有效高度:玩家实际身高减去控制条的高度,因为弹幕无法覆盖控制条。设备参考字体大小:移动端10px,PC端12px;为什么计算公式是这样的?因为我们要支持不同字号的弹幕。试想一下,不同的字体大小占据不同的物理空间。但是如果要求轨道的大小是动态的,会带来非常复杂的计算。本文提出了“虚拟轨道”的概念。交通控制中最常见的方式是道路合并或分流。我们还将相邻的物理轨道暂时合并为一个轨道。这样就可以轻松解决不同字体大小的轨道占用问题。原理图如下:图2.2轨道计算示意图接下来我们回顾一下机场的工作流程:机长呼叫塔台,CZ6132请求起飞,当前跑道被占用。请等待N次,然后重新执行步骤1。当前跑道A1空闲,允许执行。Step3塔台检查跑道使用情况,进入跑道。机长通知塔台起飞完成。释放跑道。其他占用跑道的飞机也执行上述步骤。按照这个思路,我们的弹幕工作流程:弹幕进入播放器轨道,根据弹幕的播放速度和大小进行计算。是否有合适的曲目提供暂无通知弹幕暂无合适的曲目提供,请稍候;同时,弹幕队列中的其他弹幕依次执行步骤1。执行步骤3,播放器加载弹幕DOM,开始播放,播放完成后通知轨道更新轨道占用状态。其他弹幕也执行上述步骤。图2.3Trackavailability计算图我们已经梳理了track的基本原理,当然还有很多细节,比如如何与调度器通信,如何与弹幕通信以及虚拟轨迹检测算法等,有兴趣的同学可以参考代码。https://github.com/bytedance/...BarrageBarrage基本实现了“飞机”的作用,我们要求它有自己的属性和方法。比如调度中心可以通过id获取其所有的基本信息,轨迹控制也可以通过弹幕查看更新。当然,弹幕还必须具备状态自动更新、移动、播放结束通知、自动销毁等功能。调度调度是搭台的化身,继承了对曲目和弹幕的控制,与玩家保持同步。它的职责是:播放器交互控制弹幕队列,控制自身的状态更新,数据格式转换动画执行,或者更直白的直接用流程图描述:弹幕开始后,先查看是否有在本地缓存数据,如果没有直接请求数据并缓存,然后进行数据读取,第一次过滤数据进入弹幕队列,同时启动定时器。弹幕队列中的数据会周期性的请求曲目,检查队列中的弹幕是否可以进入。确认注册轨道后,弹幕即可进入播放器开始动画播放。定时器每2秒重新刷新一次数据,进入弹幕队列(不同业务可自定义不同规则)。弹幕结束后,会通知调度和轨道。调度器会将弹幕实例从弹幕队列中移除,轨道也会移除弹幕实例的轨道占用。所有代码都是从西瓜播放器带解析器实现的,可以节省流量,Github
