Airplay 教程: 一个 Apple TV 多人竞答游戏(4)

现在,客户端需要根据服务器发来的命令进行动作。

在方法 receiveData:fromPeer:inSession:context:末尾加入代码:

  if ([commandReceived hasPrefix:kCommandQuestion] && !self.isServer)   {

     NSString *answersString = [commandReceived substringFromIndex:kCommandQuestion.length];

     [self.scene startQuestionWithAnswerCount:[answersString integerValue]];  

}

假设永远不会出现9个以上的答案,则最后一个字符就是答案的数目。answersString保存这个字符,你可以将它转换成数字,然后向 startQuestionWithAnswerCount:方法传递这个数值,这样屏幕会显示相同数目的答案按钮。

编译运行项目,先在模拟器上运行,再在真机上运行。当“Start Game”按钮出现时,轻触该按钮。你将看到如下界面:

Airplay 教程: 一个 Apple TV 多人竞答游戏(4)

在真机上,显示了和模拟器一样的内容。根据试题的内容,可能显示的按钮数目也会不同。在模拟器或真机上点击某个按钮,屏幕将显示为如下界面:

Airplay 教程: 一个 Apple TV 多人竞答游戏(4)

除此之外,程序不会有其他反应。因为当你点击选项按钮后, ATMyScene中的逻辑只包含了删除按钮并调用ATViewController方法——但实际上这个方法还是空实现。

打开 ATViewController.m,找到sendAnswer: 方法,加入以下代码:

  [self sendToAllPeers:[kCommandAnswer stringByAppendingString:     [NSString stringWithFormat:@"%ld", (long)answer]]];

代码很简单,发送 “answer”命令及用户选定的答案(索引)。

服务器通过 receiveData:fromPeer:inSession:context:来接收信息。

在这个方法末尾加入:

  if ([commandReceived hasPrefix:kCommandAnswer] && self.isServer)

   {

    NSString *answerString = [commandReceived substringFromIndex:kCommandAnswer.length];

     NSInteger answer = [answerString integerValue];

     if (answer == self.currentQuestionAnswer && self.currentQuestionAnswer >= 0)     {

       self.currentQuestionAnswer = -1;

       NSInteger points = 1 + [self.peersToPoints[peer] integerValue];

       if (points > self.maxPoints)       {

         self.maxPoints = points;

       }

       self.peersToPoints[peer] = @(points);

       [self endQuestion:peer];

     }

     else if (++self.currentQuestionAnswersReceived == self.peersToNames.count)     {

       [self endQuestion:nil];

     }

   }

先判断收到的信息是否是 “answer”命令。如果是并且答案与正确答案系统,将currentQuestionAnswer重置为-1以便下次出题。然后为玩家加分,同时更新当前的最高分记录。最后,调用 endQuestion 方法。

如果答案不正确,并且已经收到的答案与玩家数目一致,则当前提问结束,以nil 为参数调用 endQuestion 方法。

接下来实现 endQuestion:方法。

在 receiveData:fromPeer:inSession:context:方法下面添加方法:

- (void)endQuestion:(NSString *)winnerPeerID {

   [self sendToAllPeers:kCommandEndQuestion];

     NSMutableDictionary *namesToPoints = [[NSMutableDictionary alloc] initWithCapacity:self.peersToNames.count];

   for (NSString *peerID in self.peersToNames)   {

     namesToPoints[self.peersToNames[peerID]] = self.peersToPoints[peerID];

   }

   [self.mirroredScene endQuestionWithPoints:namesToPoints                                      winner:winnerPeerID ? self.peersToNames[winnerPeerID] : nil];

   [self.scene endQuestion];

     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 4 * NSEC_PER_SEC);

   dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

     [self startQuestion];

   });

}

这个方法先发送消息给客户端,让其结束当前提问;这个待会再讲。然后,创建一个dictionary,用于存储每个玩家和对应的得分并发送给第二显示器,以便显示那个玩家答对题以及当前得分情况。

最后,延迟4秒钟后运行语句块,调用 startQuestion 开下次出题。

客户端需要对 end question 命令进行处理。

在 receiveData:fromPeer:inSession:context:方法末尾加入代码:

  if ([commandReceived isEqualToString:kCommandEndQuestion] && !self.isServer)   {

     [self.scene endQuestion];

   }

客户端一旦收到该命令,就会调用 endQuestion 方法,该方法结束本轮提问并隐藏答案按钮。

编译运行程序,先模拟器,后真机。开始游戏,随便回答一些问题。如果答案不正确,你需要等真机和模拟器都答题之后才能开始下一题。

现在看可以看到类似如下的屏幕:

Airplay 教程: 一个 Apple TV 多人竞答游戏(4)

如果模拟器长时间运行,你可能会遇到程序崩溃的情况。这是因为代码并没有处理试题已经问完(即游戏结束)的情况。这是最后一块工作了!

在 startQuestion 方法头部加入以下代码:

 

  if (self.questions.count == 0)   {

     NSMutableString *winner = [[NSMutableString alloc] init];

     for (NSString *peerID in self.peersToPoints)     {

       NSInteger points = [self.peersToPoints[peerID] integerValue];

       if (points == self.maxPoints)       {

         if (winner.length) {

           [winner appendFormat:@", %@", self.peersToNames[peerID]];

         } else {

           [winner appendString:self.peersToNames[peerID]];

         }

       }

     }

     [self.mirroredScene setGameOver:winner];

     return;  

}

如果你答案是有题目,该方法会生成赢家的名字(一个或多个赢家)——然后显示在第二显示器上。

编译运行程序,当你玩完整个游戏,你会看到如下界面:

Airplay 教程: 一个 Apple TV 多人竞答游戏(4)

怎么样,你的 CS 测试是否及格?

接下来做什么?

恭喜你——你刚才用 Game Kit 编写了一个使用了外接显示器的多玩家的客户端/服务端游戏!最终完成的项目在此处下载

现在,你已经具备了使用 GameKit 编写客户/服务器游戏的基础,也知道如何使用扩展屏幕,对于某些游戏来说,这样的好处是不言而喻的。你可以用第二屏幕作为游戏视图,而将设备作为控制终端,或者在设备上显示一些附加信息,就好比HUD(平视显示器)一样。

GameKit 的 P2P 通信为多玩家游戏或 app 打开了一扇大门,你可以看到,通过利用苹果提供的APIs 实现多人控制是如何的用容易。但在 iOS7 中,GKSession 已被 Multipeer Connectivity 框架替代。这两个框架很像,你的GKSession 知识将很平滑地过度到新的 MCSession 及其相关的类上。

希望你喜欢本教程。用 AirPlay 和 GameKit p2p 开发出你想要的东西吧!

如果你有任何问题和建议,请在下面给我留言。


Airplay 教程: 一个 Apple TV 多人竞答游戏(4),布布扣,bubuko.com

Airplay 教程: 一个 Apple TV 多人竞答游戏(4)

上一篇:解决安卓TextView异常换行,参差不齐等问题


下一篇:Airplay 教程: 一个 Apple TV 多人竞答游戏(3)