BarrageFloatSprite.m 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 "BarrageFloatSprite.h"
  25. static NSUInteger const STRIP_NUM = 80; // 总共的网格条数
  26. @interface BarrageFloatSprite()
  27. {
  28. NSTimeInterval _leftActiveTime;
  29. }
  30. @end
  31. @implementation BarrageFloatSprite
  32. - (instancetype)init
  33. {
  34. if (self = [super init]) {
  35. _direction = BarrageFloatDirectionT2B;
  36. _trackNumber = 40;
  37. _fadeInTime = 0.0f;
  38. _fadeOutTime = 0.0f;
  39. _side = BarrageFloatSideCenter;
  40. _avoidCollision = NO;
  41. self.duration = 1.0f;
  42. }
  43. return self;
  44. }
  45. - (void)setDuration:(NSTimeInterval)duration
  46. {
  47. _duration = duration;
  48. _leftActiveTime = _duration;
  49. }
  50. - (void)updateWithTime:(NSTimeInterval)time
  51. {
  52. [super updateWithTime:time];
  53. _leftActiveTime = self.duration - (time - self.timestamp);
  54. NSTimeInterval existingTime = time - self.timestamp;
  55. if (_fadeOutTime > 0 && _leftActiveTime < _fadeOutTime) {
  56. self.view.alpha = _leftActiveTime/_fadeOutTime;
  57. }
  58. if (_fadeInTime > 0 && existingTime < _fadeInTime) {
  59. self.view.alpha = existingTime/_fadeOutTime;
  60. }
  61. }
  62. - (NSTimeInterval)estimateActiveTime
  63. {
  64. return _leftActiveTime;
  65. }
  66. - (BOOL)validWithTime:(NSTimeInterval)time
  67. {
  68. return [self estimateActiveTime] > 0;
  69. }
  70. - (CGPoint)originInBounds:(CGRect)rect withSprites:(NSArray *)sprites
  71. {
  72. // 获取同方向精灵
  73. NSMutableArray * synclasticSprites = [[NSMutableArray alloc]initWithCapacity:sprites.count];
  74. for (BarrageFloatSprite * sprite in sprites) {
  75. if (sprite.direction == _direction && sprite.side == self.side) {
  76. [synclasticSprites addObject:sprite];
  77. }
  78. }
  79. BOOL down = self.direction == BarrageFloatDirectionT2B; // 是否是朝下方向
  80. static BOOL const AVAERAGE_STRATEGY = NO; // YES:条纹平均精灵策略; NO:最快时间策略(体验会好一些)
  81. NSTimeInterval stripMaxActiveTimes[STRIP_NUM]={0}; // 每一条网格 已有精灵中最后退出屏幕的时间
  82. NSUInteger stripSpriteNumbers[STRIP_NUM]={0}; // 每一条网格 包含精灵的数目
  83. NSUInteger stripNum = MIN(STRIP_NUM, MAX(self.trackNumber, 1)); // between (1,STRIP_NUM)
  84. CGFloat stripHeight = rect.size.height/stripNum; // 水平条高度
  85. NSUInteger overlandStripNum = (NSUInteger)ceil((double)self.size.height/stripHeight); // 横跨网格条数目
  86. NSUInteger availableFrom = 0;
  87. NSUInteger leastActiveTimeStrip = 0; // 最小时间的行
  88. NSUInteger leastActiveSpriteStrip = 0; // 最小网格精灵的行
  89. BOOL hasBestTrack = !self.avoidCollision;
  90. for (NSUInteger i = 0; i < stripNum; i++) {
  91. //寻找当前行里包含的sprites
  92. CGFloat stripFrom = down?(i * stripHeight+rect.origin.y):(rect.origin.y+rect.size.height - i * stripHeight);
  93. CGFloat stripTo = down?(stripFrom + stripHeight):(stripFrom-stripHeight);
  94. for (BarrageFloatSprite * sprite in synclasticSprites) {
  95. CGFloat spriteFrom = down?sprite.origin.y:(sprite.origin.y+sprite.size.height);
  96. CGFloat spriteTo = down?(sprite.origin.y + sprite.size.height):sprite.origin.y;
  97. if (fabs(spriteTo-spriteFrom)+fabs(stripTo-stripFrom)>MAX(fabs(stripTo-spriteFrom), fabs(spriteTo-stripFrom))) { // 在条条里
  98. stripSpriteNumbers[i]++;
  99. NSTimeInterval activeTime = [sprite estimateActiveTime];
  100. if (activeTime > stripMaxActiveTimes[i]){
  101. stripMaxActiveTimes[i] = activeTime;
  102. }
  103. }
  104. }
  105. if (stripMaxActiveTimes[i] > 0) {
  106. availableFrom = i+1;
  107. }
  108. else if (i - availableFrom >= overlandStripNum - 1){
  109. hasBestTrack |= YES;
  110. break; // eureka!
  111. }
  112. if (i <= stripNum - overlandStripNum) {
  113. if (stripMaxActiveTimes[i] < stripMaxActiveTimes[leastActiveTimeStrip]) {
  114. leastActiveTimeStrip = i;
  115. }
  116. if (stripSpriteNumbers[i] < stripSpriteNumbers[leastActiveSpriteStrip]) {
  117. leastActiveSpriteStrip = i;
  118. }
  119. }
  120. }
  121. if (availableFrom > stripNum - overlandStripNum) { // 那就是没有找到喽
  122. availableFrom = AVAERAGE_STRATEGY?leastActiveSpriteStrip:leastActiveTimeStrip; // 使用最小个数 or 使用最短时间
  123. }
  124. CGPoint origin = CGPointZero;
  125. origin.x = (rect.origin.x+rect.size.width-self.size.width)/2;
  126. if (self.side == BarrageFloatSideRight) {
  127. origin.x = rect.origin.x+rect.size.width-self.size.width;
  128. }
  129. else if (self.side == BarrageFloatSideLeft)
  130. {
  131. origin.x = rect.origin.x;
  132. }
  133. origin.y = down?(stripHeight * availableFrom+rect.origin.y):(rect.origin.y+rect.size.height-stripHeight * availableFrom - self.size.height);
  134. if (!hasBestTrack) {
  135. origin.y = -self.size.height+rect.origin.y;
  136. _duration = 0;
  137. }
  138. return origin;
  139. }
  140. @end