今天,我将讨论玩家互动,简单的游戏AI即游戏逻辑。还将探讨一下简单的碰撞检测以便检测到什么时候球碰到球拍。根据大家要求,我还会在教程最后加入一些“挑战”以改进一些更高级的创意。首先打开第一部分的代码…
用户互动
我们首先要实现的是用户互动。我们所需要做的只是将球拍的X位置移动到用户触摸的X位置。这是很简单的方法,我们还可以做得更好(我将这部分挑战放在教程的最后 )。打开iTennisViewController.m加入下面代码:
就像上一篇教程一样,我们要重载touchesMoved方法。此方法在用户在屏幕上“拖动”手指时被触发。首先,我在touchesBegan中加入“else if”语句,当游戏处于运行状态时简单地将所有事件转发到touchesMoved中。touchesMoved中前两行是检测用户触屏的位置。接着,我们根据用户触屏X位置及黄色球拍(玩家球拍)Y位置创建 一个新的CGPoint。Objective-C不允许racquet_yellow.center.x = location.x。这可能是因为CGpiont不可改变(不可编辑)。最后,将玩家球拍的中点设置到新的位置。
碰撞检测
*更新, 有读者指出有更简单的碰撞检测方法。将下列代码加入到iTennisViewController.m 的gameLoop方法中:
苹果已经提供我们一个十分方便的方法检测对象frame是否碰撞。它就是CGRectIntersectsRect。我们只是简单地提交球和球拍的frame给此方法。当球与球拍碰撞时,我们将Y速度反向。下一个if语句也是必需的,因为有时球被向反向移动的球拍“截留”住了而不会移动。因此,我们应保证球速度只当球在球拍前方时反向。(注:NSLog仅用调试)。
简单游戏AI
下面 ,我们将讨论怎样加入简单的AI,让电脑选手与我们玩iTennis。你们可能知道一个不错的AI设计牵涉了多少工作。我可以不停地介绍数学,哲学,试探法等,但我不会这么做。我只是介绍一种超级菜鸟级的游戏AI。基本上说,电脑将“观察”球并向其方向移动,希望能击打到它。
首先,我们需要定义一个常量,它决定了电脑的移动速度。 在iTennisViewController.m顶部加入如下定义:
你测试时,可以调整这个数值。它定义了电脑选手为到达球的位置能移动得多快。这个数值越大,电脑选手将越“强”。如果这个数值足够大的话,那么电脑将不可战胜。现在,在碰撞检测代码后加入以下代码:
第一个“if”语句是为了给电脑增加点难度,检查球是否处于“它”的半场。如果球不在它的半场,电脑将不会有任何动作。你可以省略这条语句,那就成了另一个有趣的游戏了。下一条“if”语句检查球中心的X与球拍中心的X是否不同。如果球在电脑球拍的右方,电脑球拍的X坐标将增大kCompMoveSpeed。如果球在电脑球拍的左方,电脑球拍的X坐标将减小kCompMoveSpeed。
现在应该很清楚kCompMoveSpeed变量是怎样影响电脑的表现了吧……
你可以按“Build and Go”来看看游戏的表现吧。你可以看到电脑会做出反应并在大部分时间内击打到球。但为了游戏更有趣,还剩下最后一部分:记分。
游戏机制:记分
我们需要一种方式来保存分数。这实际上是一种更简单的碰撞检测。我们将检查球是否碰到后墙。 首先,我们定义几个变量和方法。打开iTennisViewController.h,添加下列高亮的代码:
我们需要一个代表分数的整数,当电脑和玩家得分时,我们会把分数加上。 另外我们还需要一个“reset”函数,调用它会将球复位到屏幕的中心。我们还需要定义另一个变量。将下面各行加入到iTennisViewController.m的顶部:
这个变量的意思应该很清楚,它定义了需要获胜的分数。为了加快游戏进程,我只是将其赋值为5。下面,我们检查是电脑还是玩家得分。在AI代码后,加入下面代码:
首先我们看到两条if语句。它们只是检查球是否碰到/超过屏幕的顶部或底部。如果球超过顶部,玩家将得分。如果球超出底部,电脑将得分。如果你是编程新手的话,下面一行可能有些奇怪。我们调用reset函数,但是我们传递的表达式是什么意思?
如果你看一下reset的定义,你就会知道,它接受一个代表游戏是否结束的BOOL值。它可以为true或false。我们实际上只是传递true或false给函数。所以,当player_score_value变量小于5时,(player_score_value >= kScoreToWin)为false,而当此变量到5时,表达式为true。
我们为什么要这样做?因为这样可以节省好几行代码并降低程序复杂度 。所以我们现在不需要if(player_score_value >= kScoreToWin) ) [self reset:YES]; }else{[self reset:NO];}。明白了吗?
下面,我们定义reset函数 。在iTennisViewController.m中加入下列代码:
首先我们暂停游戏。暂停游戏使“Tap to Begin”信息显示在屏幕上。然后,我们将球定位到屏幕中心。如果被传递的参数newGame为YES/true,我们需要做几件事。首先,通过比较电脑和玩家分数,我们要检查谁是赢家。然后,更新“tapToBegin”(标签变量)通知用户谁获胜。你也可以加多另一个标签作此用,但我只是循环使用“tapToBegin”标签。最后,因为要开始新游戏,我们将玩家和电脑的分数清零。
如果newGame为NO/false,我们只需要复位tapToBegin,显示“Tap to Begin”。这只是为了更改tapToBegin中的信息,以防其还显示着像“Player/Computer wins!”(“玩家/电脑获胜!”)之类的信息。
按“Build and Go”与电脑进行一场“史诗般”的iTennis决战吧!源代码在此下载。
如约,这里有一些挑战
- 改进用户互动 – 当用户触屏时,球拍并不直接移动到触屏的位置,而是向触屏的方向移动
- 改进碰撞检测 – 当球碰到球拍时,使用一些简单的物理学原理使球拍的速度影响球的速度(和方向)
- 改进AI – 为AI增加一些随机性,使它能尽量“预测”球的运行轨迹
- 改进记分系统 – 使用网球记分 15, 30 , 等……
- 改进记分系统 – 你必须赢两分以上
请继续关注我们的教程,我将介绍游戏音频,启动画面,“关于……”以及其他部分…….









