【GAD翻译馆】VR100天教程:第12天在Unity中为敌人创造AI动作
译者:刘鸿(lewis2012,251423807) 审校:王玥亭(玥亭)
这里是虚拟现实100天的第12天。昨天,我们研究了rigs模型和Unity的mecanim系统(我应该学但在 Survival Shooter 教程中忽略了...)
今天,我们将在创建animator控制器后继续下去。
我们将创建导航组件给我们的Knight Enemy来追逐和攻击玩家。正如你可能记得的那样,Unity为我们提供了一个AI pathfinder(人工智能寻路器) ,可以让我们的游戏对象朝着一个方向移动,同时避开障碍物。
将敌人向玩家移动
设置模型
为了能够为我们的敌人创建AI动作,我们需要将Nav Mesh Agent组件添加到我们的Knight游戏对象中。我要唯一改变的设置是速度,我设置为2。
此时,我们可以删除我们的老敌人游戏对象。我们不需要它了。
接下来,我们需要为我们的敌人创建一个NavMesh系统。
单击Navigation面板旁边的导航面板。
如果没有,请点击Window > Navigation打开视图窗。
在bake标签下,只需点击bake,创建NavMesh。我不想为我们的角色创造任何特别的东西。
一旦我们完成,如果我们显示我们创建的导航,我们应该有这样的东西。
确保 环境 父游戏对象设置为静态!
创建脚本
在这一点上,我们需要做的是创建允许敌人追逐玩家的脚本。
为了做到这一点,我创建了 EnemyMovement 脚本并将其附加到我们的knight。
代码如下:
现在很简单:
1)我们得到了我们的玩家GameObject和Nav Mesh Agent组件。
2)我们设置导航器追逐我们的玩家
我们必须做的一件重要的事情是确保代码的工作原理,我们必须将 Player 标签添加到我们的角色上,以确保我们获取GameObject对象。
之后,我们可以尝试运行游戏,我们可以看到敌人会追逐我们的玩家。
使用攻击动画
现在Knight会绕着我们跑。但是我们如何让它做一个攻击动画呢?
我们需要做的第一件事是将一个胶囊碰撞器(capsule collider)组件连接到我们的knight 游戏对象上,并做出这些设置:
1)Is Trigger 选中
2)Y Center 为 1
3)Y Radius 为1.5
4)Y Height 为1
与我们在Survival Shooter教程中所做的一样,当我们的Knight接近我们时,我们将切换到一个攻击动画玩家此时也受到敌人伤害。
随着我们的新的胶囊碰撞器(capsule collider)与玩家碰撞,我们将添加逻辑到我们的animator 上并开始攻击动画。
首先,我们将创建一个名为EnemyAttack 的新脚本 ,并将其附加到Knight上。
脚本代码如下:
这与我们在Survival Shooter游戏中看到的相似。当我们的对撞机被触发时,我们会将我们的“IsNearPlayer”设置为true,以便我们启动攻击动画,当我们的玩家离开触发范围时,Knight将停止攻击。
注意:如果你遇到Knight第一次攻击玩家后就停止的问题,请检查动画片段,并确认 Loop Time被选中。我不知道如何,但我禁用了它。
检测攻击动画
添加网格碰撞器
所以现在Knight会触发攻击动画。你可能会注意到玩家没有任何反应。
我们今天不打算讲这个,但我们会写一些预留接口代码,让我们以后能够受到敌人的损害。
目前,我们有一个胶囊碰撞器(capsule collider),将允许我们检测何时敌人在攻击范围内。接下来我们需要做的是弄清楚敌人是触碰到了玩家。
为了做到这一点,我们要 在我们的敌人附上一个 网格碰撞器(Mesh Collider)。
与以前的碰撞器不同的是触发器,这个实际上将检测敌人何时与玩家碰撞。
确保我们将我们的Knight使用的身体网格( body mesh)连接到我们的 网格碰撞器(Mesh Collider)上。
我需要注意的是,由于某些原因,Knight的网格在地面之下,然而我没有遇到任何具体的问题,所以我决定忽略它。
在我们的攻击动画中添加一个事件
在我们继续编写Knight攻击玩家的代码之前,我们必须在玩家动画中添加一个事件。
具体来说,我想做到这一点,当Knight攻击时,如果他们与玩家碰撞,我们会受到伤害。
要做到这一点,我们将要做类似于 Survival Shooter教程的内容。我们将在我们的动画中添加一个事件,在我们的脚本中调用一个函数。
我们有两种做法。
我们 从模型中创建一个 Animation event on imported clips
2)我们从动画剪辑添加一个 Animation Event in the Animation tab
由于我们的Knight模型没有我们添加的动画,我们将使用第二种方式。
我们 要从Brute Warrior Mecanim包中编辑我们的Attack1 动画片段(animation clip)。在 动画(Animator) 标签中
在选择我们的 Knight Animator Controller,在Animator面板中点击Attack1 并选择Animation 选项卡打开它。
如果你的项目中尚未打开任何一个选项卡,则可以通过转到Windows并选择将其放入项目中来打开它们。
现在,我们会遇到一个问题。我们的Attack1动画是只读的,我们无法编辑它。
我们做什么?
根据这个 helpful post帖子,我们应该只是复制动画剪辑。
所以这就是我们要做的。找到Attack1并按Ctrl + D复制我们的剪辑。我要将其重命名为 Knight Attack ,我将把它移动到我的animations(根目录下创建的)文件夹中。
回到我们的Animator 选项卡中的Knight Animator Controller,我将切换Attack1状态,使用新的 Knight Attack 动画剪辑,而不是之前的动画剪辑。
接下来,我们将需要弄清楚设置触发器调用代码的关键点。
为此,我拖出Animation标签,并将其停放在窗口中的其他地方,如下所示:
在游戏hierarchy面板中选择我们的Knight对象,然后你可以注意到,在 animation选项卡中,播放按钮现在可以点击。
如果我们点击它,我们会看到我们的Knight会播放我们所在的动画片段。
切换到 Knight Attack ,按播放看我们的攻击动画。
从这里,我们需要弄清楚运行我们的脚本的关键点。
播放动画,我相信在第16帧触发我们的伤害玩家事件将是最好的时间点。
接下来,我们需要点击16帧下方的little+button right来创建一个新的事件。将该事件拖到第16帧。
从Inspector面板下, 我们可以从附加的脚本中选择一个函数。现在我们没有什么,除了OnTrigger()。
现在,我们在我们的EnemyAttack脚本中创建一个名为Attack()的空函数, 以便我们可以使用:
我所做的只是添加Attack ()函数。
现在我们有了这个代码,我们可能需要重新选择动画来显示新的函数,但是当你完成时,你应该能够看到Attack (),我们现在应该有这样的东西:
这是我所做的:
1)添加了OnCollisionExit()和OnCollisionEnter()来检测,当我们的网格碰撞器(Mesh Collider)与我们的玩家接触。
一旦这样做,我们设置一个布尔值来表示我们已经与敌人相碰撞了。
3)然后当攻击动画播放时,正好是第16帧,我们将调用Attack()。如果我们仍然与网格碰撞器(Mesh Collider)接触 ,我们的玩家将被击中。否则我们将成功地躲避敌人。
就是这样!
运行游戏,看看控制台的日志,看看Knight进入攻击区域的时候,当他碰撞到玩家的时候,当他成功击中玩家的时候。
实际上有很多方法可以实现这一点,我不知道哪种方式是正确的,但这是我想到的:
我们可以做的其他事情,但没有:
1)做到这一点,如果我们与敌人接触,无论是否进行攻击,都会受到伤害。
2)在Knight Attack 开始时创建一个动画事件, 并设置_isAttacking布尔值为true,然后在我们的Update()中,如果敌人正在攻击,并且我们与他们交互,则玩家会受到伤害,然后设置_isAttacking是假的,所以我们不会在同一个动画循环中再次击中。
结论
那就是第12天!这实际上花了比我想象的更长的时间!
最初,我以为这样就像我们在Survivor Shooter游戏中一样应用Nav Mesh Agent,但是当我开始考虑攻击动画时,事情变得越来越复杂,我花了很多时间试图弄清楚如何只有在攻击动画期间攻击伤害玩家。
明天,我要更新 PlayerShootingController ,以便能够射击我们的Knight敌人。
我们的脚本有个问题。目前,每当我们遇到一个敌人,出于某种奇怪的原因,我们将永远朝着一个方向滑动。我不知道是什么原因,但我们会在明天解决这个问题!
访问 VR挑战100天的内容表
【版权声明】
已经询问原文作者,并获取原文作者翻译许可,译文获得授权。