前言
今年疫情原因,学校好长时间都不开学,本来在线教育就很火,这下更是火山爆发,线上教育APP多如牛毛,成长更是惊人。
成人的教育视频依然是常规视频,没有太大变化,可是主打低龄儿童市场的视频教学,为了让小朋友感兴趣,确是玩出了很多花样,比如 斑马AI课,小火花思维等主打视频互动课,比如 洪恩识字 直接是个游戏。
视频互动课 直接颠覆了我对视频交互的认知,在看到它之前,我接触过的视频交互,也紧紧是 在视频上发个弹幕,抖音点个赞。视频互动课在我们开发者看,就是跳出视频进行一些操作,完成在回到视频。给常人或小朋友们的感觉是 我在和视频中的人物在交互。一般套路是播放一个动画,动画中的人物需要做一些事情,需要小朋友们帮助,小朋友们需要完成一些小游戏,在小游戏中学习了知识,或是播放一段音乐,让小朋友跟着唱跳。这个产品设计真的太棒了。小朋友真的粘性超高,父母也乐意,终于能消停会了,还能学习。每天看一节视频课在加上课后练习的游戏和别的互动也就20分钟至半个小时。对小朋友眼睛损伤并不大。我来看下视频互动课的录制
![](https://img.haomeiwen.com/i1830250/5e681622ac6d2777.gif)
首先看到 视频下的进度条上有4个 时间点图标,代表着 这4个事件。可见在视频开始时或之前 就已经知道了时间点的位置。而每节课的时间点是不一样的,所以我们设计进度条上的图标,是根据时间点的数据而确定位置的。
接下来 仿着视频互动课 ,自己试着实现
使用的播放器 是ZFPlayer
先创建 节点数据模型
@interface ZBGameModel : NSObject
@property (nonatomic,assign)NSInteger seconds;//游戏时间
@property (nonatomic,assign)NSInteger gameId;//游戏id
@property (nonatomic,assign)NSInteger gameType;//游戏类型 1为游戏
@end
给模型赋值对应的时间和类型
ZBGameModel *model1=[[ZBGameModel alloc]init];
model1.gameId=1001;
model1.gameType=1;
model1.seconds=100;
ZBGameModel *model2=[[ZBGameModel alloc]init];
model2.gameId=1002;
model2.gameType=1;
model2.seconds=221;
ZBGameModel *model3=[[ZBGameModel alloc]init];
model3.gameId=1003;
model3.gameType=1;
model3.seconds=303;
ZBGameModel *model4=[[ZBGameModel alloc]init];
model4.gameId=1004;
model4.gameType=2;
model4.seconds=318;
[self.timeArray addObject:model1];
[self.timeArray addObject:model2];
[self.timeArray addObject:model3];
[self.timeArray addObject:model4];
根据上图我们可以看到 对号标志 代表游戏,最后一个音乐标志代表儿歌时间。可是这个图标,我们怎么算位置坐标呢。
下面就要靠计算了,
(进度条的总长度/视频的总时间)* 对应的时间点 - 图标的宽度的一半
得到的就是 每个图标的位置了
///当播放器准备开始播放时候调用
self.player.playerReadyToPlay = ^(id<ZFPlayerMediaPlayback> _Nonnull asset, NSURL * _Nonnull assetURL) {
@strongify(self)
[self.timeArray enumerateObjectsUsingBlock:^(ZBGameModel *model, NSUInteger idx, BOOL * _Nonnull stop) {
UIImageView *icon=[[UIImageView alloc]init];
if (model.gameType==1) {
icon.image=[UIImage imageNamed:@"gift_icon_0"];
}else{
icon.image=[UIImage imageNamed:@"douyin"];
}
icon.backgroundColor=[UIColor whiteColor];
[self.controlView.landScapeControlView.slider addSubview:icon];
[icon mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@(0));
make.width.equalTo(@(14));
make.height.equalTo(@(14));
//7为宽的一半
make.left.equalTo(@(model.seconds*(self.controlView.landScapeControlView.slider.frame.size.width/self.playerManager.totalTime)-7));
}];
}];
};
![](https://img.haomeiwen.com/i1830250/692b6e7c6106a736.png)
因为只是 demo,我并没自定义 视频控制层和视频互动课一样,大家应该能看到,图标和原图基本一致
图标指示UI 层面的,那么 到了游戏图标的时间我们怎么能够进入游戏 呢
创建一个 游戏队列类 把我们刚才的 数据传进去
self.gameQueue=[[ZBGameQueue alloc]init];
self.gameQueue.delegate=self;
[self.gameQueue loadGameList:self.timeArray];
里面是这样的,把模型数据存在字典里,以节点时间为key
- (void)loadGameList:(NSArray *)gameList{
if (gameList.count<=0) {
return;
}
for (int i = 0; i < gameList.count; i ++) {
ZBGameModel *gameModel = gameList[i];
[self.cacheDict setObject:gameModel forKey:@(gameModel.seconds).stringValue];
}
}
在视频时间回调内 游戏时间 和 视频时间进行匹配,找到对应的时间点,证明可以进入游戏了
__block NSInteger tempTime;
self.player.playerPlayTimeChanged = ^(id<ZFPlayerMediaPlayback> _Nonnull asset, NSTimeInterval currentTime, NSTimeInterval duration) {
@strongify(self)
//因为此回调是0.1秒一次,所以做了此判断,
tempTime=currentTime;
if (self.currentTime!=tempTime) {
NSLog(@"tempTime:%ld",tempTime);
//游戏列队 和 视频时间对比
[self.gameQueue startQueueWithCurrentTime:tempTime];
}
self.currentTime=tempTime;
};
- (void)startQueueWithCurrentTime:(NSInteger)currentTime{
if ([self.cacheDict.allKeys containsObject:@(currentTime).stringValue]) {
ZBGameModel *gameModel =[self.cacheDict objectForKey:@(currentTime).stringValue];
if ([self.delegate respondsToSelector:@selector(gameQueueGetGameModel:)]) {
[self.delegate gameQueueGetGameModel:gameModel];
}
}
}
看到这,如果之前看过我写的 历史弹幕绑定视频时间的朋友,应该了解。逻辑都一样。
之后就是 代理触发,我们就可以进入游戏了
#pragma mark - ZBGameQueueDelegate
- (void)gameQueueGetGameModel:(ZBGameModel *)gameModel{
if (gameModel.gameType==1) { //1为游戏
[self.playerManager pause];//暂停视频
NSLog(@"进入游戏");
GameViewController *gameVC=[[GameViewController alloc]init];
gameVC.delegate=self;
UIViewController *vc=[self.controlView.landScapeControlView findeCurrentViewController];
[vc presentViewController:gameVC animated:YES completion:nil];
}else{
//其他不跳转 比如儿歌时间
}
}
游戏部分,我只是随便写了一点,三个游戏节点,都是一个。一节课 视频里3-4个游戏,加上课后练习的游戏10个 起码有了。一期有10多节课,每个年龄段的课还不一样,游戏也不一样。游戏的量这么大,感觉用原生开发不太可能。
最后在游戏结束时 给一个回调,游戏结束继续播放视频
#pragma mark - GameViewControllerDelegate
- (void)gameComplete{
[self.playerManager play];
}
经过上面的处理,服务下发的或传进来的任何时间点,任何数量的数据,我们的UI图标 和 事件都能准确的触发
我们来个看下整体效果
![](https://img.haomeiwen.com/i1830250/2dd5f900de8cfd33.gif)
最后奉上本文Demo
结尾:水平有限,代码也很烂,一直在努力学习中,大家多多包涵。如果你喜欢这个轮子,请给个star,这是对作者最大的鼓励和支持,拜谢!!!假如你有更好的想法或方案请留言!
网友评论