LNDanmakuMaster is a lightweight bullet screen player. It can play the bullet screen by creating player -> Creating track -> Adding bullet screen, providing rich track styles and supporting custom track. There is no requirement for the View Layer of the incoming barrage (arbitrary View/Layer); • Multiple (currently 3) barrage distribution strategies [Fixed] Support for using track groups to play special rounds Provides ammunition – screen seek strategy corresponding to distribution strategy.

Making links:LNDanmakuMaster

  • You can download the link directly and run the rich Demo above, use the Demo code to create your own danmaku player, or use Cocoapods👇

Cocoapods

pod 'LNDanmakuMaster'
Copy the code

subdocument

  • Start with a barrage: LNDanmakuAttributes
  • The heart of the animation: LNDanmakuTrackController
  • Barrage staging and distribution: LNDanmakuDispatcher
  • Barrage reuse: LNDanmakuPool
  • Barrage container and gesture: LNDanmakuContainerView
  • Conditional barrage: LNDanmakuTrackGroup
  • Bullet screen encapsulation component: LNDanmakuPlayer

Letter Address:IOS bullet screen component LNDanmakuMaster

Barrage mechanism

  1. Driving mechanism

The refresh rate of video players is usually 29frame/s. Danmaku players will feel sluggish if they use the same refresh frequency. Therefore, danmaku players usually use their own refresh drivers, either UIView animation or CADisplayLink. CADisplaylink supports more detail and progress control, so we chose CADisplaylink here. LNDanmakuClock is a driver that encapsulates CADisplayLink and adds pause and destroy controls. The output of this clock is a small amount of time from the last DisplayLink callback to this one.

  1. Progress control mechanism

LNDanmakuMaster uses time to define progress, which is one of the main differences between LNDanmakuMaster and other bullet screen frameworks. All of our progress control, chase control and busyness control are calculated using time. Advantages of using time variables instead of spatial variables include:

  • If your track path is not straight: if you want a barrage to play in both horizontal and circular tracks, give both angular and linear velocities, and if you use time units, just give the total running time.
  • If you first control the distance between two cartridges on a curved track, the space distance needs to calculate the length of the curve, and the time distance works just like a straight line.
  • When making some judgments, if space conditions are used to make judgments, it is necessary to carry out a lot of speed and time related multiplication and division operations, and the use of time may only need addition and subtraction. Although I do not know whether it has specific advantages, it intuitively feels that multiplication and division is not as fast as addition and subtraction.
  • If it’s a barrage like station B with a column in the middle, it doesn’t need speed, just the time displayed.

In conclusion, using the time system instead of the speed system is a good way to unify various kinds of orbit schedule control.

  1. The refresh mechanism

According to the output of the Clock, we can get a stable callback to know just how long after a period of time, then the barrage of refresh process becomes: just will be deducted from the barrage of remaining survival time after time, and according to the time remaining after deducting the percentage of the total time to refresh the barrage of location, size and other information. After the introduction of the above three main mechanisms, we have all the main logic to implement a barrage framework, the rest is some module subdivision and detail carving.

The module division of labor

LNDanmakuMaster divides the whole bullet-screen framework into the following parts (Abstract means to support rewriting customization) :

The name of the module The name of the class note
player LNDanmakuPlayer The player is equivalent to the integration of other components of the whole bullet-screen framework, providing external call methods and timing proxies
The dispenser LNDanmakuAbstractDispatcher The Dispatcher is like the manager of the track, according to the state of the track set to decide where is the best place to put bullets
Track controller LNDanmakuAbstractTrackController The Track controller is similar to a worker who regularly maintains his barrage using the Track tool and reports his (busy/idle) status to the Dispatcher
orbital LNDanmakuAbstractTrack The responsibility of Track completely conforms to the definition of Track. It does not maintain barrage, but only maintains the mapping between the position, size, affine transformation and time progress of any barrage on this Track, like a function of spatial information and time information
style LNDanmakuAbstractAttributes Style is the carrier of a barrage, including all the information of a barrage, such as: survival time, location, business model carried, View/Layer used in display, etc. Yes, that’s right, very similar to CollectionViewAttributes, with added timestamp information based on player features

Additional components

The name of the module The name of the class note
Orbital group LNDanmakuTrackGroup This component is used to do special barrage play, is a smaller unit similar to Player (but without its own driver), contains a Dispatcher and several trackControllers

The significance of this component: some bullet screens have certain requirements on the track, or the track has certain requirements on its own bullet screen. For example, the gift track can only appear at the top of the screen, not in the center, to avoid affecting the user’s viewing of the video. Or circular orbits can’t be used for longer text, so it doesn’t look so round, etc. Once you consider the problem from two sides, you will fall into: Choose barrage/barrage choose orbits, but actually exists for the two cases is, these two problems finally unified use rail group, the user to specify a grouping of orbit, and Player, I can step over directly to the track group barrage, then the barrage group contains only may appear in the orbital orbit; This feature is shown in a rainbow-style track in the Demo, where I throw seven coloured cartridges into seven groups of tracks (each group has three tracks, and the two adjacent groups share the overlapping track in the middle) so that they have a rainbow effect.

Use the sample

Having covered all the important components of the framework, here is an example of how to build a simple danmaku player:

  1. Lazy loading of a danmakuPlayer:

This is the minimum that needs to be done, and it will work without any configuration

- (LNDanmakuPlayer *)danmakuPlayer { if (! _danmakuPlayer) { _danmakuPlayer = [[LNDanmakuPlayer alloc] init]; } return _danmakuPlayer; }Copy the code
  1. Add the player container View to the screen:
    [self.view addSubview:self.danmakuPlayer.containerView];
Copy the code
  1. Add some tracks to this Player:

Player support for customization is mainly in the custom track and the style of the bullet screen, so you add all the tracks by hand, and you can do that in init/viewDidLoad or whatever, or you can add it while the Player is lazily loading

- (void)addTrack for (int i = 0; i < 20; i++) { LNDanmakuHorizontalMoveTrackController *horizontalTrackController = [[LNDanmakuHorizontalMoveTrackController alloc] init]; horizontalTrackController.horizontalTrack.startPosition = CGPointMake(0, 44.f + 30.f * i); horizontalTrackController.horizontalTrack.width = self.view.frame.size.width; horizontalTrackController.spaceTimeInterval = 0.f; [self.danmakuPlayer addTrack:horizontalTrackController]; }}Copy the code
  1. Get the player moving!

Now the player can interface with any barrage from outside and play it on the screen

- (void)startPlay {
    [self.danmakuPlayer start];
}
Copy the code
  1. Let’s try putting a simple barrage on it:
- (void)addRandomDanmaku
{
        LNDanmakuAttributes *attributes = [[LNDanmakuAttributes alloc] init];
        UIView *colorView = [[UIView alloc] init];
        colorView.backgroundColor = [UIColor redColor];
        attributes.presentView = colorView;
        attributes.trackTime =4.f;
        attributes.size = CGSizeMake(88.f, 44.f);
        [_player insertAttributes:@[attributes]];
}
Copy the code

The framework defines the division of each component in the most logical way possible to ensure that it is the most comfortable to use, and encapsulates the seemingly complex logic as much as possible: distribution, refresh, catch-up, and so on; Of course, I think a reasonable framework would be one with a very low floor and a very high ceiling, rather than a rigid set of rules (like the man who controls The Wind), so when users need to delve deeper into these logic, they can easily customize them from the outside and play with their own characteristics.

In the future, we will update some articles about the application or principle of this framework. Although there are not many superb skills in the implementation, this component will definitely develop towards fewer rules, simpler code and richer functions.

Finally, I attach some renderings in the Demo

  • Transverse track

  • Pop animation track

  • Wave orbital + orbital grouping

  • Heart-shaped orbit

QA link

Here are some additional code and policy notes:

Calculation of time dependence in orbit