- (CGPoint)originInBounds:(CGRect)rect withSprites:(NSArray *)sprites{
// 获取同方向精灵
NSMutableArray * spritesOfSameGroup = [[NSMutableArray alloc]initWithCapacity:sprites.count];
for (DCBarrageWalkSprite * sprite in sprites) {
if (sprite.direction == self.direction && sprite.sequence == self.sequence) { // 找寻同道中人
[spritesOfSameGroup addObject:sprite];
}
}
static BOOL const AVAERAGE_STRATEGY = YES; // YES:条纹平均精灵策略(体验会好一些); NO:最快时间策略
//真实的弹道数
NSUInteger trackNum = MIN(TRACK_NUM_MAX, MAX(self.trackNumber, 1)); // between (1,TRACK_NUM_MAX)
if (self.spriteHeight > 0) {
trackNum = (NSUInteger)(rect.size.height/(self.spriteHeight + self.spriteSpace));
}
NSMutableArray *spriteMaxActiveTimesPerTrack = [NSMutableArray arrayWithCapacity:trackNum];// 每一条网格 已有精灵中最后退出屏幕的时间
for (int i=0; i<trackNum; i++) {
spriteMaxActiveTimesPerTrack[i] = @(0.0f);
}
NSMutableArray *spriteMaxDistancePerTrack = [NSMutableArray arrayWithCapacity:trackNum]; // 每一条网格 已有精灵中移动了最远的距离
for (int i=0; i<trackNum; i++) {
spriteMaxDistancePerTrack[i] = @(0.0f);
}
NSMutableArray<NSDictionary<NSString *, NSNumber *> *> *spriteNumbersPerTrack = [NSMutableArray arrayWithCapacity:trackNum];// 每一条网格 包含精灵的数目
for (int i=0; i<trackNum; i++) {
spriteNumbersPerTrack[i] = @{@"index":@(i), @"number": @(0)};
}
CGFloat spriteHeight = 0; // 水平条高度
if (self.spriteHeight > 0) {
spriteHeight = self.spriteHeight;
} else {
spriteHeight = rect.size.height/trackNum;
}
BOOL isLandScape = self.direction == BarrageWalkDirectionL2R || self.direction == BarrageWalkDirectionR2L; // 方向, YES代表水平弹幕
/// 计算数据结构,便于应用算法
NSUInteger overlandStripNum = 1; // 横跨网格条数目
if (isLandScape) { // 水平
if (self.spriteHeight == 0) {
overlandStripNum = (NSUInteger)ceil((double)self.size.height/spriteHeight);
}
}
/// 当前精灵需要的时间,左边碰到边界, 不是真实的活跃时间
NSTimeInterval maxActiveTime = isLandScape?rect.size.width/self.speed:rect.size.height/self.speed;
__block NSUInteger leastActiveTimeTrackIndex = 0; // 最小时间的行
NSUInteger leastActiveSpriteStrip = 0; // 最小网格的行
for (DCBarrageWalkSprite * sprite in spritesOfSameGroup) {
CGFloat spriteY = sprite.origin.y+5;//偏移5方便计算track
//所在弹道
NSUInteger spriteOfTrackIndex = (NSUInteger)(spriteY/(self.spriteHeight + self.spriteSpace));
spriteNumbersPerTrack[spriteOfTrackIndex] = @{@"index":@(spriteOfTrackIndex), @"number":@([spriteNumbersPerTrack[spriteOfTrackIndex][@"number"] integerValue] + 1)};
NSTimeInterval activeTime = [sprite estimateActiveTime];
if (activeTime > [spriteMaxActiveTimesPerTrack[spriteOfTrackIndex] doubleValue]){ // 获取最慢的那个
spriteMaxActiveTimesPerTrack[spriteOfTrackIndex] = @(activeTime);
}
CGFloat distance = isLandScape?fabs(sprite.position.x-sprite.origin.x):fabs(sprite.position.y-sprite.origin.y);
if (distance > [spriteMaxDistancePerTrack[spriteOfTrackIndex] floatValue]) {
spriteMaxDistancePerTrack[spriteOfTrackIndex] = @(distance);
}
}
NSInteger availableTrackIndex = -1;
//先找空弹道
if (self.sequence == DCBarrageWalkSequenceAsc) {
for(int i=0; i<trackNum; i++) {
if ([spriteNumbersPerTrack[i][@"number"] integerValue] == 0) {
availableTrackIndex = i;
break;
}
}
} else if (self.sequence == DCBarrageWalkSequenceDesc) {
for(int i=trackNum-1; i>=0; i--) {
if ([spriteNumbersPerTrack[i][@"number"] integerValue] == 0) {
availableTrackIndex = i;
break;
}
}
} else { //乱序
[spriteNumbersPerTrack unstableShuffle];
for(int i=0; i<trackNum; i++) {
if ([spriteNumbersPerTrack[i][@"number"] integerValue] == 0) {
availableTrackIndex = [spriteNumbersPerTrack[i][@"index"] integerValue];
break;
}
}
}
if (availableTrackIndex > -1) { //找到了空弹道
} else {//如果没有空弹道的话,取spriteMaxDistancePerTrack最大的或者spriteMaxActiveTimesPerTrack时间最短的
__block NSTimeInterval leastActiveTime = 0;
[spriteMaxActiveTimesPerTrack enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (leastActiveTime == 0) {
leastActiveTime = [obj floatValue];
leastActiveTimeTrackIndex = idx;
} else {
if ([obj floatValue] < leastActiveTime) {
leastActiveTime = [obj floatValue];
leastActiveTimeTrackIndex = idx;
}
}
}];
availableTrackIndex = leastActiveTimeTrackIndex;
}
CGPoint origin = CGPointZero;
_destination.y = origin.y = (spriteHeight + self.spriteSpace)*availableTrackIndex;
origin.x = (self.direction == DCBarrageWalkDirectionL2R)?rect.origin.x - self.size.width:rect.origin.x + rect.size.width;
_destination.x = (self.direction == DCBarrageWalkDirectionL2R)?rect.origin.x + rect.size.width:rect.origin.x - self.size.width;
return origin;
}