现在很多视频网站里面都有弹幕,弹幕可以让看视频的人有一个交流和沟通,相比之前更加好玩,但是小弹怡情,大弹伤身啊,比如下面的:

    因为说话的人太多了,导致很多文字都叠在一起了,看不到。。。那么如何做一个就算很多人说话也不会重叠在一起的弹幕呢?

    不碰撞弹幕

    先来看看实现后的效果:

    不碰撞弹幕    

    上面就是一个模拟很多人说话的情况,我们可以看到,就算很多人同时发出了弹幕,也不会出现重复的情况,那这个是怎么实现的呢?

    实现思路

    这个主要是仿照我们在操场上跑步的情况:

    接力赛很多人肯定参加过,一个人跑过去再跑回来,把接力棒给下一个人。其实这种思路可以用在弹幕上,但是这里有一个问题,就是同一个赛道上最多只能有一个人,很明显,弹幕上同一行肯定不止一个,这该怎么处理?

    现在假设我们想让同一个跑道上最多有两人怎么办?我们可以修改以下接力的规则:当第一个人跑道跑道的1/2的时候,下一个人开始跑,如果跑到了终点,迅速在后面排好(不能沿着跑道返回,因为会和后面的人撞上;跑完后的排好不一定是排在原来的队里,可以随便排。)

    同理,如果想让一个跑道上有三个人的话,每次跑道1/3开始跑,依此类推。。。

    思路有了,我们看看具体运用的技术和问题。

    首先,一个东西从右边到左边,肯定是用css的animation动画,这个可以动画的延迟和运行时间。

         考虑完了一个的情况,现在比较麻烦的就是下一个元素如何才能不碰撞前一个元素?

    上面是两个元素会重合的极端情况,上面给出了如何根据第一个元素的速度算出第二个元素最大碰撞速度,得到了这个速度,就可以保证所有的东西都不碰撞了。

    一个跑道上多少个人在这里是可以设置的:

    注意,这里我做了一个处理,当占有率为20的时候,并不是1/20的时候叫下一个出来,而是只要前面一个人走了,下一个立马就跟上,是一种最大的极端情况。

    上图有一个接力失败的情况,是指当你的屏幕上可容纳赛跑者很多,但是真正的赛跑者不多的时候,例如有10个赛道,选手到1/2的时候叫下一个赛跑者上场,这样一共可以容纳20个选手,但是一共就有15个赛跑者,这样就会造成有的选手跑完叫下一个选手的时候发现没人了,这个时候就失败了,不过程序内部已经处理了,如果有一个失败了,那么当有选手跑完的时候,就会认领这个失败任务。

    占有率可以控制屏幕上弹幕的密集程度,这里是手动设置的,真实的可以根据弹幕的多少来自动设置,比如只有100个弹幕的时候,就设置的小一点,有1000个弹幕的时候,就设置的高一点,这样屏幕看起来就比较多,别人就知道有很多人留言了。

    暂停功能

    暂停弹幕一般分为两种情况,一种是暂停页面上的弹幕,一种是暂停还没有出现的弹幕,我们先来看看如何暂停和恢复页面上的弹幕:

    1. //暂停页面上的关键代码
    2. all_row_array.forEach(function(data, i) { //暂停赛道上没有满员的
    3.     for(var key in data.runner) {
    4.         var $current_runner = data.runner[key];
    5.         $current_runner.style.animationPlayState = 'paused';
    6.         $current_runner.style.webkitAnimationPlayState = 'paused';
    7.     }
    8. });
    9. for(var k1 in all_row_finish_runner_helper) {//暂停赛道上满员的
    10.     for(var k2 in all_row_finish_runner_helper[k1]) {
    11.         var $current_runner = all_row_finish_runner_helper[k1][k2];
    12.         $current_runner.style.animationPlayState = 'paused';
    13.         $current_runner.style.webkitAnimationPlayState = 'paused';
    14.     }
    15. }
    16. //恢复页面上的关键代码
    17. all_row_array.forEach(function(data, i) { //恢复赛道上没有满员的
    18.     for(var key in data.runner) {
    19.         var $current_runner = data.runner[key];
    20.         $current_runner.style.animationPlayState = 'running';
    21.         $current_runner.style.webkitAnimationPlayState = 'running';
    22.     }
    23. });
    24. for(var k1 in all_row_finish_runner_helper) { //恢复赛道上满员的
    25.     for(var k2 in all_row_finish_runner_helper[k1]) {
    26.         var $current_runner = all_row_finish_runner_helper[k1][k2];
    27.         $current_runner.style.animationPlayState = 'running';
    28.         $current_runner.style.webkitAnimationPlayState = 'running';
    29.     }
    30. }

    我们把进入赛道的每一个runner保存起来,当暂停的时候,就是用animation-play-state:paused来暂停,但是如果赛道上runner个数满了的话(比如一个赛道上一共可以容量2个人,现在已经有了2人),在程序内部计算的时候,会把赛道删除,因此需要对满员的赛道特殊处理一下,暂停它们的animation。恢复的时候和暂停是相反的动作,只要将 animation-play-state设置为running就好了。

    还有一个比较复杂的是暂停没有出现的弹幕。其实没有出现的弹幕,是因为有一个延时(delay),这个是用setTimeout控制的,因此,我们的构想就是将所有的延时方法保存起来,当暂停又播放的时候,我们更新延时的时间,具体如下图:

    上图描述了一个最简单的暂停恢复的情况,然而实际情况会更复杂,比如一个弹幕延时10秒出现,但是中间可能多次暂停恢复,为了方便处理,我们统一只是计算最新的延时时间,比如第2秒你停了,那么我先将之间的10秒定时清除,然后更新新的延时时间为8秒,不管你暂停多久,等你再开始的时候,我就新建一个8秒的定时,那假设又过了3秒,你暂停了,那么我就清除那个8秒的定时,待你恢复的时候,我再新开一个5秒的延时。。。以此类推,不管你中间停多少次,我都可以准确的计算到最新的延时。

    上图是设置初使延时的地方,那些你看不到的弹幕,都是在这里设置延时的,相当于之前的10秒。这里会把当前时间,总延时时间和回调方法保存起来。

    这里就是你按暂停后,会更新当前时间和新的延时时间,这个新的延时时间=原来的延时时间-(按下暂停的当前时间-之前的当前时间),同时会把之前的定时给清除(clearTimeout)。

    这里就是你恢复暂停进行的操作,同样,我们更新了当前时间,这里我们会新建一个新的定时(setTimeout),延时则采用上一步的延时。

    注意:暂停功能在ios浏览器上存在问题,主要是因为ios浏览器对animation-play-state:paused支持的有问题,因此暂停功能最好在pc设备上用。

    DEMO下载

    点击下载[0积分]一共下载0
    回到顶部
    我要评论

    所有评论

      相关文章