分享iOS平台弹幕解决方案HJDanmakuDemo

本文详细介绍弹幕技术的实现原理,包括弹幕绘制、时间控制、碰撞检测及暂停恢复等核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

弹幕实现主要需要解决以下几个问题

1.弹幕绘制方式;
2.弹幕时间控制;
3.弹幕碰撞检测原理;
4.弹幕暂停及恢复

本文主要从以上4个方面介绍弹幕的详细实现原理。

 首先是弹幕绘制方式。弹幕流畅的前提要求每秒绘制的帧数在30帧以上,而移动设备性能千差万别,当同一时刻需要绘制大量弹幕的时候,对于低端设备就会出现卡帧不流畅的情况,这会大大降低用户的体验。因此,在本项目中放弃采用自定义绘制帧的方式,而是采用系统动画的方式来实现弹幕文本的滚动。
[UIView animateWithDuration:danmaku.remainTime delay:0 options:UIViewAnimationOptionCurveLinear animations:^{   
 danmaku.label.frame = CGRectMake(-danmaku.size.width, danmaku.py, danmaku.size.width, danmaku.size.height);}
 completion:nil];
其次,就是弹幕时间的控制。由于采用系统动画的方式,所以不需要时刻计算每一个弹幕的显示时间以及其X坐标(假设弹幕横向滚动),我们需要做的就是在弹幕需要出现的时候创建它,然后设定弹幕存活的时间,剩余滚动动画交给系统负责,当然,弹幕剩余时间需要我们来更新。本项目中,创建了一个0.5s间隔的定时器,主要负责创建新的弹幕并更新已显示弹幕的剩余时间,也就是说0.5s执行一次计算,如果需要,可以将刷新间隔设置成5s或者更长。
_timer = [NSTimer timerWithTimeInterval:_frameInterval target:self selector:@selector(onTimeCount) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
[_timer fire];
然后,就是弹幕碰撞检测的问题。碰撞检测主要难点在于检测横向滚动弹幕之间的碰撞,弹幕存活时间由其显示时间和存活长短决定,因此,弹幕之间是否碰撞只需检测开始和消失是否碰撞即可。
- (BOOL)checkIsWillHitWithWidth:(float)width DanmakuL:(DanmakuBaseModel *)danmakuL 
DanmakuR:(DanmakuBaseModel *)danmakuR{    
if (danmakuL.remainTime<=0) {        return NO;    }    
if (danmakuL.px+danmakuL.size.width>danmakuR.px) {        return YES;    }    
float minRemainTime = MIN(danmakuL.remainTime, danmakuR.remainTime);   
 float px1 = [danmakuL pxWithScreenWidth:width RemainTime:(danmakuL.remainTime-minRemainTime)];    
float px2 = [danmakuR pxWithScreenWidth:width RemainTime:(danmakuR.remainTime-minRemainTime)];    
if (px1+danmakuL.size.width>px2) {        return YES;    }   
 return NO;
 }
最后,弹幕的暂停及恢复。由于弹幕滚动采用系统动画,所以在解决弹幕暂停前需要先了解系统动画的实现原理,有兴趣的朋友可以参考动画解释这篇文章,在此就不做过多介绍。暂停的基本原理就是通过view的presentationLayer获取对象的当前坐标并赋给其frame,然后移除layer动画,考虑到缓冲,可以在当前坐标基础上-1
- (void)pauseRenderer{    
for (DanmakuBaseModel *danmaku in _drawArray.objectEnumerator) {        
CALayer *layer = danmaku.label.layer;        
CGRect rect = danmaku.label.frame;       
if (layer.presentationLayer) {            
rect = ((CALayer *)layer.presentationLayer).frame;            
rect.origin.x-=1;        }       
danmaku.label.frame = rect;      
 [danmaku.label.layer removeAllAnimations];    }}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值