处理条件弹幕:LNDanmakuTrackGroup

601 阅读3分钟

这个文章的前置文章是:LNDanmakuMaster

轨道组的由来

假设产品经理提出这样的需求:所有App钻石会员用户发的弹幕只能出现在顶部前三排,黄金会员用户第4到6排、白银用户第7到9排;如果我们仍然采用一个Player/Dispatcher策略,弹幕的播放条件可能会互相影响:假设白银轨道特别繁忙,一条钻石轨道的弹幕此时插入到队尾,虽然钻石轨道当前十分空闲,但这条钻石弹幕不得不等所有队列中的白银弹幕出队列之后才能播放,说句实话这对氪金大佬十分不友好。

轨道组就是为这种有播放条件弹幕的场景设计,形成:播放器 -> 多个轨道组 -> 多个轨道的结构,用户可以挑选任意的轨道放入一个带有某种含义的轨道组中;在插入弹幕时不是将弹幕插入播放器,而是插入轨道组中;这样这条弹幕出现的位置就只可能是这个轨道组所包含的那些轨道。

所以,针对上面这种场景,我们只要创建三个轨道组,diamondTrackGroup、goldTrackGroup、silverTrackGroup, 并将对应的9条轨道分别放入三个轨道组,在分发弹幕时根据弹幕特性,分别放入不同的轨道组,这样就实现了“条件分发”。这种条件分发不会发生不同种类弹幕之间的相互阻塞,因为每个轨道组的Dispatcher中存储的弹幕都是同类弹幕。

轨道组的实现

轨道组包含了一个Dispatcher和一组TrackController。在这个TrackGroup小范围内的分发策略是由这个Dispatcher决定的,因此,分发策略甚至可以与Player整体策略不一致,以下是TrackGroup的属性定义:

@interface LNDanmakuTrackGroup : NSObject
@property (nonatomic, strong, readonly) LNDanmakuAbstractDispatcher *dispatcher;
@property (nonatomic, copy, readonly) NSArray<LNDanmakuAbstractTrackController *> *currentTrackControllers;
- (void)addTrack:(LNDanmakuAbstractTrackController *)trackController;
- (void)removeTrack:(LNDanmakuAbstractTrackController *)trackController;
- (void)clear;
@end

一个TrackGroup的工作方式与Player是一致的,但是它自身不含Clock驱动,依赖Player的驱动工作;在Player每次收到Clock回调后都会先更新自己的trackController和dispatcher,最后检查一下轨道组是否也需要同样的操作:

- (void)danmakuClockUpdateTimeInterval:(NSTimeInterval)time
{
 /**省略**/
 [self trackGroupUpdateTimeInterval:time]; 
}

遍历轨道组的列表,先驱动TrackController更新已有弹幕,再检查Dispatcher是否有机会分发新的弹幕:

- (void)trackGroupUpdateTimeInterval:(NSTimeInterval)time
{
    for (LNDanmakuTrackGroup *trackGroup in self.trackGroupMArr) {
        [trackGroup.dispatcher danmakuClockUpdateTimeInterval:time];
        for (LNDanmakuAbstractTrackController *trackController in trackGroup.currentTrackControllers) {
            [trackController update:time];
        }
        [trackGroup.dispatcher dispatchNewAttributesToFreeTracks: 
        [NSArray arrayWithArray:trackGroup.currentTrackControllers]];
    }
}

(省略了一些判断的代码,展示主要逻辑)

再举个例子

Demo示例中这样展示轨道组:

yVluuD.gif

这个弹幕播放器中有7种颜色,26条轨道,每种颜色都对应一个轨道组,每个轨道组中有4条轨道,两个轨道组间相交2条轨道:

红 = (0、1、2、3)

橙 = (2、3、4、5)

黄 = (4、5、6、7 ) 以此类推

分发时会随机选取一种颜色生成弹幕,根据这个弹幕的颜色将他放入不同的轨道组中,就形成了上面的效果。这个例子也为了说明不同的轨道组之间也是可以共用轨道的,红和橙两个轨道组之间共用了2、3轨道,因此,这两个轨道上既可能出现红色弹幕也可能出现橙色弹幕,这样可以展现出一种融在一起的效果。

轨道组的常见用途

  1. 送大型礼物的弹幕通常在屏幕顶端出现,一般不会出现在中央。

  2. 左下角飘的聊天室信息也可以放在一个轨道组里。

  3. 带图片的弹幕通常只能在特殊轨道上播放,缩放、旋转等,这种轨道通常要与普通横向的轨道区分开。

  4. 剧情解说类型的弹幕作者通常会刻意发在中间一列的那种轨道上(在看一些世界观比较大的番剧时通常会有热心网友发弹幕解说或jutou)。

  5. 等等。