适用于Unity3D的简单敌人AI系统

在这篇文章中,我将解释我如何为我的技术学院最终项目的敌人开发了一个简单的AI系统。 这个想法是一个简单的脚本,可以使敌人在现场随机行走,追赶和攻击玩家。

我开发的IA脚本基于多种游戏,尤其是在隐形游戏中。 敌人在游戏开始时会选择一个随机目的地,并在靠近选定的随机目的地时朝这个方向行走,并选择另一个随机目的地,并重新开始所有过程。 如果在他走向某个点时看到玩家,则他开始追逐玩家,如果到达玩家,他将发起攻击攻击他。

对于本示例,我将使用Unity 5游戏引擎,但您可以轻松进行更改并在其他引擎(例如Unreal)中使用。

在本文或编程逻辑中,我不会解释Unity的基本功能,如果您有任何疑问,请阅读参考链接,或在此处或在我的Twitter上提问。

在此示例中,我使用3D块构建了一个简单的迷宫,并将敌人(蓝色球形)放置在右上角,而我们的玩家放置在左下角(红色球形)。
我们的播放器是一个简单的FPSController(您可以在Unity Standard Assets上找到此脚本),在此处了解更多信息。

对于我们的敌人在场景中行走,最简单的方法是在场景中创建导航网格,并在我们的敌人(3D球体)的组件上添加Nav Mesh Agent。

“导航系统允许您使用从场景几何体自动创建的导航网格来创建可以在游戏世界中智能移动的角色。”

注意您的导航网格,它必须绕过所有墙壁,否则您的敌人将无法正常工作。

这个简单的步骤将使接下来的事情变得容易。

首先,我们需要使用Random.range函数声明和定义随机目标,并获取navMeshAgent组件。 之后,我们的代码如下所示:

  public int currentRandomPoint;
 私有 NavMeshAgent navMesh;  无效的开始(){
   currentRandomPoint = Random.Range(0,randomPoints.Length);
   navMesh = transform.GetComponent ();
 } 

如果您将使用animimator组件对敌人使用动画,则也应声明并在void start上使用动画,如下所示:

  受保护的 Animator动画师; 动画师= GetComponent (); 

在void更新中,我们要做的第一件事是计算玩家距离和随机点距离,为此,我们使用Vector3。

  playerDist = Vector3.Distance(Player.transform.position,transform.position);
 randomPointDist = Vector3.Distance(randomPoints [currentRandomPoint]。
变换位置,变换位置) 

并声明一个RaycastHit,此raycasthit将确保我们的敌人看不到墙后的玩家。

  RaycastHit热门歌曲; 

您可以在此处阅读有关Physics.Raycast的内容

 if (Physics.Raycast(transform.position,direction, out hit,1000)&& playerDist <ceptionDistance){ if (hit.collider.gameObject.CompareTag(“ Player”)){seeingPlayer = true ;  } else {seeingPlayer = false ; 在我们的玩家距离大于感知距离的同时行走。  如果 (playerDist>感知距离)walk(); 

我们的步行方法基本上是设置navMesh的加速度,速度和目的地,如下所示:

  虚空漫步(){
   如果 (追赶==  ){
     navMesh.acceleration = 1;
     navMesh.speed = walkVelocity;
     navMesh.destination = randomPoints [currentRandomPoint] .position;
   } else if (追赶== true ){
     chaseTime = true ;
   }
 } 

现在,借助RaycastHit,玩家距离和随机点距离,我们的脚本正在执行以下操作:

橙色虚线是我们计算玩家距离的脚本,蓝色虚线是随机点距离,绿色箭头是我们的RaycastHit。

这里是我们敌人的其他三种行为:

  无效的外观(){
   navMesh.speed = 0;
   transform.LookAt(Player);
 }
 无效追逐(){
   navMesh.acceleration = 5;
   navMesh.speed = chaseVelocity;
   navMesh.destination = Player.position;
 }
 无效攻击(){
   navMesh.acceleration = 0;
   navMesh.speed = 0;
  进攻=  ;
 } 

如果您正在使用动画师和动画,则可以在此处调用动画师变量,例如以下示例:

  animator.SetFloat(“ Speed”,0.5f); 

下一步是进行大量检查以攻击,追逐,停止追逐以及所有这些东西,我不会详细介绍,但是如果您有疑问,可以按照我上面所述与我联系。

以下是接下来的检查:

  if (playerDist  chaseDistance){
   如果 (seeingPlayer == true )
    看();
   其他
    步行();
   } if (playerDist  AttackDistance){
     如果 (seeingPlayer == true ){
      追();
      追逐=  ;
     } 其他 {
      步行();
     }
   } 如果 (playerDist <= AttackDistance && seeingPlayer == true )
    攻击();  如果 (randomPointDist <= 8){
     currentRandomPoint = Random.Range(0,randomPoints.Length);
    步行();
   如果 (chaseTime == true )
     chaseStopwatch + = Time.deltaTime;  if (chaseStopwatch> = 5 && seeingPlayer == false ){
     chaseTime = false ;
     chaseStopwatch = 0;
    追赶=  ;
   } if (攻击== true )
     AttackingStopwatch + = Time.deltaTime; 

并进行攻击检查:

  if (attackingStopwatch> = AttackTime && playerDist <= AttackDistance){
  进攻=  ;
   AttackingStopwatch = 0;
      
   if (attackingStopwatch> = AttackTime && playerDist> AttackDistance){
    进攻=  ;
     AttackingStopwatch = 0;
   }
 } 

如果要对播放器造成损坏,则应添加以下内容:

  playerLife = playerLife-敌人伤害;  如果 (playerLife <= 5){
   Application.LoadLevel(GameOverSceneName);
 } 否则, 如果 (attackingStopwatch> = AttackTime && playerDist> AttackDistance){
  进攻=  ;
   AttackingStopwatch = 0;
 } 

我真的建议您将playerLife作为播放器脚本的变量。

最后,如果您想让您的玩家可以攻击敌人,则可以向您的敌人添加僵尸组件,然后执行以下操作:

  void OnCollisionEnter(Collision col){
   如果 (col.transform.tag ==“子弹”){
    敌人的生命-= 10;
     如果 (enemyLife <= 0){
      销毁(gameObject);
     }
   }
 } 

现在我们完成了简单的人工智能脚本,您可以将其用于您的简单游戏,学习和改进,接下来的几个月中,我将发布第二部分,说明如何改进此脚本,增加视野,声音等。

您可以在我的github上查看完整的脚本/项目,对于项目/代码的质量感到抱歉,当我撰写本文时我才16岁。

https://github.com/OtavioHenrique/simpleAI

并在我的Twitter或Linkedin上问我

谢谢大家,很快再见。