BarrageRenderer.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // Part of BarrageRenderer. Created by UnAsh.
  2. // Blog: http://blog.exbye.com
  3. // Github: https://github.com/unash/BarrageRenderer
  4. // This code is distributed under the terms and conditions of the MIT license.
  5. // Copyright (c) 2015年 UnAsh.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. #import "BarrageRenderer.h"
  25. #import "BarrageCanvas.h"
  26. #import "BarrageDispatcher.h"
  27. #import "BarrageSprite.h"
  28. #import "BarrageSpriteFactory.h"
  29. #import "BarrageClock.h"
  30. #import "BarrageDescriptor.h"
  31. NSString * const kBarrageRendererContextCanvasBounds = @"kBarrageRendererContextCanvasBounds"; // 画布大小
  32. NSString * const kBarrageRendererContextRelatedSpirts = @"kBarrageRendererContextRelatedSpirts"; // 相关精灵
  33. NSString * const kBarrageRendererContextTimestamp = @"kBarrageRendererContextTimestamp"; // 时间戳
  34. @interface BarrageRenderer()<BarrageDispatcherDelegate>
  35. {
  36. BarrageDispatcher * _dispatcher; //调度器
  37. BarrageCanvas * _canvas; // 画布
  38. BarrageClock * _clock;
  39. NSMutableDictionary * _spriteClassMap;
  40. NSMutableDictionary * _context; // 渲染器上下文
  41. NSMutableArray * _preloadedDescriptors; //预加载的弹幕
  42. NSMutableArray * _records;//记录数组
  43. NSDate * _startTime; //如果是nil,表示弹幕渲染不在运行中; 否则,表示开始的时间
  44. NSTimeInterval _pausedDuration; // 暂停持续时间
  45. NSDate * _pausedTime; // 上次暂停时间; 如果为nil, 说明当前没有暂停
  46. }
  47. @property(nonatomic,assign)NSTimeInterval time;
  48. @property(nonatomic,assign)NSTimeInterval pausedDuration; // 暂停时间
  49. @end
  50. @implementation BarrageRenderer
  51. @synthesize pausedDuration = _pausedDuration;
  52. #pragma mark - init
  53. - (instancetype)init
  54. {
  55. if (self = [super init]) {
  56. _canvas = [[BarrageCanvas alloc]init];
  57. _spriteClassMap = [[NSMutableDictionary alloc]init];
  58. _zIndex = NO;
  59. _context = [[NSMutableDictionary alloc]init];
  60. _recording = NO;
  61. _startTime = nil; // 尚未开始
  62. _pausedTime = nil;
  63. _redisplay = NO;
  64. _smoothness = 0.0f;
  65. self.pausedDuration = 0;
  66. [self initClock];
  67. }
  68. return self;
  69. }
  70. /// 初始化时钟
  71. - (void)initClock
  72. {
  73. __weak id weakSelf = self;
  74. _clock = [BarrageClock clockWithHandler:^(NSTimeInterval time){
  75. BarrageRenderer * strongSelf = weakSelf;
  76. strongSelf.time = time;
  77. [strongSelf update];
  78. }];
  79. }
  80. #pragma mark - control
  81. /// 接收弹幕,并校对时间
  82. - (void)receive:(BarrageDescriptor *)descriptor
  83. {
  84. [self receive:descriptor withCorrection:YES];
  85. }
  86. /// 接收弹幕, 并决定是否要校对时间
  87. - (void)receive:(BarrageDescriptor *)descriptor withCorrection:(BOOL)correction
  88. {
  89. dispatch_async(dispatch_get_main_queue(), ^{
  90. if (!_startTime) { // 如果没有启动,则抛弃接收弹幕
  91. return;
  92. }
  93. BarrageDescriptor * descriptorCopy = [descriptor copy];
  94. if (correction) {
  95. [self convertDelayTime:descriptorCopy];
  96. }
  97. BarrageSprite * sprite = [BarrageSpriteFactory createSpriteWithDescriptor:descriptorCopy];
  98. [_dispatcher addSprite:sprite];
  99. if (_recording) {
  100. [self recordDescriptor:descriptorCopy];
  101. }
  102. });
  103. }
  104. - (void)start
  105. {
  106. // 如果之前调整过frame,_canvas的layoutSubviews不会及时调用,于是显示时会出问题
  107. // 解决bug: https://github.com/unash/BarrageRenderer/issues/16
  108. [_canvas setNeedsLayout];
  109. if (!_startTime) { // 尚未启动,则初始化时间系统
  110. _startTime = [NSDate date];
  111. _records = [[NSMutableArray alloc]init];
  112. _dispatcher = [[BarrageDispatcher alloc]init];
  113. _dispatcher.smoothness = self.smoothness;
  114. _dispatcher.cacheDeadSprites = self.redisplay;
  115. _dispatcher.delegate = self;
  116. }
  117. else if(_pausedTime)
  118. {
  119. _pausedDuration += [[NSDate date]timeIntervalSinceDate:_pausedTime];
  120. }
  121. _pausedTime = nil;
  122. [_clock start];
  123. if (_preloadedDescriptors.count) {
  124. for (BarrageDescriptor * descriptor in _preloadedDescriptors) {
  125. [self receive:descriptor withCorrection:NO];
  126. }
  127. [_preloadedDescriptors removeAllObjects];
  128. }
  129. }
  130. - (void)pause
  131. {
  132. if (!_startTime) { // 没有运行, 则暂停无效
  133. return;
  134. }
  135. if (!_pausedTime) { // 当前没有暂停
  136. [_clock pause];
  137. _pausedTime = [NSDate date];
  138. }
  139. else
  140. {
  141. _pausedDuration += [[NSDate date]timeIntervalSinceDate:_pausedTime];
  142. _pausedTime = [NSDate date];
  143. }
  144. }
  145. - (void)stop
  146. {
  147. _startTime = nil;
  148. [_clock stop];
  149. _pausedDuration = 0.0f;
  150. [_dispatcher deactiveAllSprites];
  151. }
  152. - (void)setSpeed:(CGFloat)speed
  153. {
  154. if (speed > 0) {
  155. _clock.speed = speed;
  156. }
  157. }
  158. - (CGFloat)speed
  159. {
  160. return _clock.speed;
  161. }
  162. - (void)setRedisplay:(BOOL)redisplay
  163. {
  164. _redisplay = redisplay;
  165. if (_dispatcher) {
  166. _dispatcher.cacheDeadSprites = _redisplay;
  167. }
  168. }
  169. - (void)setSmoothness:(CGFloat)smoothness
  170. {
  171. _smoothness = smoothness;
  172. if (_dispatcher) {
  173. _dispatcher.smoothness = smoothness;
  174. }
  175. }
  176. - (NSTimeInterval)pausedDuration
  177. {
  178. return _pausedDuration + (_pausedTime?[[NSDate date]timeIntervalSinceDate:_pausedTime]:0); // 当前处于暂停当中
  179. }
  180. /// 获取当前时间
  181. - (NSTimeInterval)currentTime
  182. {
  183. NSTimeInterval currentTime = 0.0f;
  184. if (self.delegate && [self.delegate respondsToSelector:@selector(timeForBarrageRenderer:)]) {
  185. currentTime = [self.delegate timeForBarrageRenderer:self];
  186. }
  187. else
  188. {
  189. currentTime = [[NSDate date]timeIntervalSinceDate:_startTime]-self.pausedDuration;
  190. }
  191. return currentTime;
  192. }
  193. /// 转换descriptor的delay时间(相对于start), 如果delay<0, 则将delay置为0
  194. - (void)convertDelayTime:(BarrageDescriptor *)descriptor
  195. {
  196. NSTimeInterval delay = [[descriptor.params objectForKey:@"delay"]doubleValue];
  197. delay += [self currentTime];
  198. if (delay < 0) {
  199. delay = 0;
  200. }
  201. [descriptor.params setObject:@(delay) forKey:@"delay"];
  202. }
  203. - (NSInteger)spritesNumberWithName:(NSString *)spriteName
  204. {
  205. NSInteger number = 0;
  206. if (spriteName) {
  207. Class class = NSClassFromString(spriteName);
  208. if (class) {
  209. for (BarrageSprite * sprite in _dispatcher.activeSprites) {
  210. number += [sprite class] == class;
  211. }
  212. }
  213. }
  214. else
  215. {
  216. number = _dispatcher.activeSprites.count;
  217. }
  218. return number;
  219. }
  220. - (void)removePresentSpritesWithName:(NSString *)spriteName
  221. {
  222. Class class = NSClassFromString(spriteName);
  223. for (BarrageSprite * sprite in _dispatcher.activeSprites) {
  224. if (!class || [sprite class] == class) {
  225. [sprite forceInvalid];
  226. }
  227. }
  228. }
  229. - (void)removeSpriteWithIdentifier:(NSString *)identifier
  230. {
  231. for (BarrageSprite * sprite in _dispatcher.activeSprites) {
  232. if ([sprite.viewParams[@"identifier"] isEqualToString:identifier]) {
  233. [sprite forceInvalid];
  234. break;
  235. }
  236. }
  237. }
  238. #pragma mark - record
  239. /// 此方法会修改desriptor的值
  240. - (void)recordDescriptor:(BarrageDescriptor *)descriptor
  241. {
  242. __block BOOL exists = NO;
  243. [_records enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL * stop){
  244. if([((BarrageDescriptor *)obj).identifier isEqualToString:descriptor.identifier]){
  245. exists = YES;
  246. *stop = YES;
  247. }
  248. }];
  249. if(!exists){
  250. [_records addObject:descriptor];
  251. }
  252. }
  253. - (NSArray *)records
  254. {
  255. return [_records copy];
  256. }
  257. - (void)load:(NSArray *)descriptors
  258. {
  259. if (_startTime) {
  260. for (BarrageDescriptor * descriptor in descriptors) {
  261. [self receive:descriptor withCorrection:NO];
  262. }
  263. }
  264. else
  265. {
  266. if (!_preloadedDescriptors) {
  267. _preloadedDescriptors = [[NSMutableArray alloc]init];
  268. }
  269. for (BarrageDescriptor * descriptor in descriptors) {
  270. [_preloadedDescriptors addObject:[descriptor copy]];
  271. }
  272. }
  273. }
  274. #pragma mark - update
  275. /// 每个刷新周期执行一次
  276. - (void)update
  277. {
  278. [_dispatcher dispatchSprites]; // 分发精灵
  279. for (BarrageSprite * sprite in _dispatcher.activeSprites) {
  280. [sprite updateWithTime:self.time];
  281. }
  282. }
  283. #pragma mark - BarrageDispatcherDelegate
  284. - (BOOL)shouldActiveSprite:(BarrageSprite *)sprite
  285. {
  286. return !_pausedTime;
  287. }
  288. - (void)willActiveSprite:(BarrageSprite *)sprite
  289. {
  290. NSValue * value = [NSValue valueWithCGRect:_canvas.bounds];
  291. [_context setObject:value forKey:kBarrageRendererContextCanvasBounds];
  292. NSArray * itemMap = [_spriteClassMap objectForKey:NSStringFromClass([sprite class])];
  293. if (itemMap) {
  294. [_context setObject:[itemMap copy] forKey:kBarrageRendererContextRelatedSpirts];
  295. }
  296. [_context setObject:@(self.time) forKey:kBarrageRendererContextTimestamp];
  297. NSInteger index = [self viewIndexOfSprite:sprite];
  298. [sprite activeWithContext:_context];
  299. [self indexAddSprite:sprite];
  300. [_canvas insertSubview:sprite.view atIndex:index];
  301. if (self.delegate && [self.delegate respondsToSelector:@selector(barrageRenderer:spriteStage:spriteParams:)]) {
  302. [self.delegate barrageRenderer:self spriteStage:BarrageSpriteStageBegin spriteParams:sprite.viewParams];
  303. }
  304. }
  305. - (NSUInteger)viewIndexOfSprite:(BarrageSprite *)sprite
  306. {
  307. NSInteger index = _dispatcher.activeSprites.count;
  308. /// 添加根据z-index 增序排列
  309. if (self.zIndex) {
  310. NSMutableArray * preSprites = [[NSMutableArray alloc]initWithArray:_dispatcher.activeSprites];
  311. [preSprites addObject:sprite];
  312. NSArray * sortedSprites = [preSprites sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
  313. return [@(((BarrageSprite *)obj1).z_index) compare:@(((BarrageSprite *)obj2).z_index)];
  314. }];
  315. index = [sortedSprites indexOfObject:sprite];
  316. }
  317. return index;
  318. }
  319. - (void)willDeactiveSprite:(BarrageSprite *)sprite
  320. {
  321. [self indexRemoveSprite:sprite];
  322. [sprite.view removeFromSuperview];
  323. [sprite deactive];
  324. if (self.delegate && [self.delegate respondsToSelector:@selector(barrageRenderer:spriteStage:spriteParams:)]) {
  325. [self.delegate barrageRenderer:self spriteStage:BarrageSpriteStageEnd spriteParams:sprite.viewParams];
  326. }
  327. }
  328. - (NSTimeInterval)timeForBarrageDispatcher:(BarrageDispatcher *)dispatcher
  329. {
  330. if ([dispatcher isEqual:_dispatcher]) {
  331. return [self currentTime];
  332. }
  333. return 0.0f; // 错误情况
  334. }
  335. #pragma mark - indexing className-sprites
  336. /// 更新活跃精灵类型索引
  337. - (void)indexAddSprite:(BarrageSprite *)sprite
  338. {
  339. NSString * className = NSStringFromClass([sprite class]);
  340. NSMutableArray * itemMap = [_spriteClassMap objectForKey:className];
  341. if (!itemMap) {
  342. itemMap = [[NSMutableArray alloc]init];
  343. [_spriteClassMap setObject:itemMap forKey:className];
  344. }
  345. [itemMap addObject:sprite];
  346. }
  347. /// 更新活跃精灵类型索引
  348. - (void)indexRemoveSprite:(BarrageSprite *)sprite
  349. {
  350. NSString * className = NSStringFromClass([sprite class]);
  351. NSMutableArray * itemMap = [_spriteClassMap objectForKey:className];
  352. if (!itemMap) {
  353. itemMap = [[NSMutableArray alloc]init];
  354. [_spriteClassMap setObject:itemMap forKey:className];
  355. }
  356. [itemMap removeObject:sprite];
  357. }
  358. #pragma mark - attributes
  359. - (UIView *)view
  360. {
  361. return _canvas;
  362. }
  363. - (void)setCanvasMargin:(UIEdgeInsets)canvasMargin
  364. {
  365. _canvas.margin = canvasMargin;
  366. }
  367. - (void)setMasked:(BOOL)masked
  368. {
  369. _canvas.masked = masked;
  370. }
  371. @end