美文网首页人猿星球
iOS AI视频互动课的实现

iOS AI视频互动课的实现

作者: Andi | 来源:发表于2020-12-04 10:19 被阅读0次

    前言

    今年疫情原因,学校好长时间都不开学,本来在线教育就很火,这下更是火山爆发,线上教育APP多如牛毛,成长更是惊人。
    成人的教育视频依然是常规视频,没有太大变化,可是主打低龄儿童市场的视频教学,为了让小朋友感兴趣,确是玩出了很多花样,比如 斑马AI课,小火花思维等主打视频互动课,比如 洪恩识字 直接是个游戏。
    视频互动课 直接颠覆了我对视频交互的认知,在看到它之前,我接触过的视频交互,也紧紧是 在视频上发个弹幕,抖音点个赞。视频互动课在我们开发者看,就是跳出视频进行一些操作,完成在回到视频。给常人或小朋友们的感觉是 我在和视频中的人物在交互。一般套路是播放一个动画,动画中的人物需要做一些事情,需要小朋友们帮助,小朋友们需要完成一些小游戏,在小游戏中学习了知识,或是播放一段音乐,让小朋友跟着唱跳。这个产品设计真的太棒了。小朋友真的粘性超高,父母也乐意,终于能消停会了,还能学习。每天看一节视频课在加上课后练习的游戏和别的互动也就20分钟至半个小时。对小朋友眼睛损伤并不大。我来看下视频互动课的录制


    banmaGIF.gif IMG_1494.PNG

    首先看到 视频下的进度条上有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));
                }];
            }];
        };
    
    ED11C40C-9B24-4799-9C31-3197AB0F0FA8.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图标 和 事件都能准确的触发

    我们来个看下整体效果

    banma zb GIF.gif
    最后奉上本文Demo
    结尾:水平有限,代码也很烂,一直在努力学习中,大家多多包涵。如果你喜欢这个轮子,请给个star,这是对作者最大的鼓励和支持,拜谢!!!假如你有更好的想法或方案请留言!

    相关文章

      网友评论

        本文标题:iOS AI视频互动课的实现

        本文链接:https://www.haomeiwen.com/subject/mnjywktx.html