ai自动寻路 unity3d
2015-12-09 19:00:21 foso1994 阅读数 914
public class AITank : Unit  {

	public float moveSpeed;
	public float rotateSpeed;
	public float attackRange;
	public GameObject player;
	public float shootColdDown;

	private float timer;
	private TankWeapons tw;
	private NavMeshAgent nav;//是NavMeshAgent的组件的实例

	void Start(){
		tw = GetComponent<TankWeapons> ();
		nav = GetComponent<NavMeshAgent> ();
	}


void FixedUpdate(){

		timer += Time.fixedDeltaTime;
		
		if (player == null) {//当玩家死亡后,player==null,不再进行下一步操作,否则会报错
			return;
		}
		float dist = Vector3.Distance (player.transform.position , transform.position);//计算两个三维向量之间的距离
		if (dist > attackRange) {
			nav.SetDestination (player.transform.position);//NavMeshAgent的自动寻路函数,目标是玩家的位置
		} else {
			nav.ResetPath();//距离小于攻击范围后就停止寻路,开始攻击
			transform.LookAt (player.transform.position);
			if (timer > shootColdDown) {//shootColdTime是冷却时间
				tw.Shoot ();
				timer = 0;
			}
		}

	}

}


注:

1.NavMeshAgent是unity3D中用来自动寻路的插件,在制作电脑AI时会经常使用,具体函数请翻阅文档。

2.计算两个三维向量之间的距离:Vector3.Distance(A,B)

2014-07-14 13:29:33 YHuangHeR 阅读数 536

现在的大部分mmo游戏都有了自动寻路功能。点击场景上的一个位置,角色就会自动寻路过去。中间可能会有很多的障碍物,角色会自动绕过障碍物,最终达到终点。使用Unity来开发手游,自动寻路可以有很多种实现方式。第一种比较传统的是使用A星寻路,它是一种比较传统的人工智能算法,在游戏开发中比较常用到。大部分的页游和端游都用到这种技术。在Unity游戏也可以用这种技术,Asset Store上面已经有相关的组件了,感兴趣的同学可以自己去了解。我在后面有机会再来详细介绍了。今天我们来学习Unity官方内置的寻路插件-Navmesh。由于内容比较多,我们将分几次来系统学习。今天先通过学习一个最简单的例子来入门。

(转载请注明原文地址http://blog.csdn.net/janeky/article/details/17457533

  • 实例
我们要实现一个功能:点击场景中的一个位置,角色可以自动寻路过去。角色会绕过各种复杂的障碍,找到一条理论上”最短路径“。
  • 步骤
1.创建地形
2.添加角色
3.创建多个障碍物,尽量摆的复杂一点,来检查Navmesh的可用性和效率。
4.选中地形,在Navigation窗口中,设置Navigation Static

5.依次选中障碍物,在avigation窗口中,设置Navigation Static
7.Navigation窗口中,选择Bake(烘焙)界面,点击Bake按钮,进程场景烘焙,就可以烘焙出寻路网格了
8.为角色添加NavMeshAgent组件。Component->Navigation->Nav Mesh Agent
9.为角色新增一个脚本PlayerController.cs,实现点击目标,自动寻路功能
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. //Author:ken@iamcoding.com  
  5. public class PlayerController : MonoBehaviour  
  6. {  
  7.     private NavMeshAgent agent;  
  8.   
  9.   
  10.     void Start()  
  11.     {  
  12.         //获取组件  
  13.         agent = GetComponent<NavMeshAgent>();  
  14.     }  
  15.   
  16.   
  17.     void Update()  
  18.     {  
  19.         //鼠标左键点击  
  20.         if (Input.GetMouseButtonDown(0))  
  21.         {  
  22.             //摄像机到点击位置的的射线  
  23.             Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);  
  24.             RaycastHit hit;  
  25.             if (Physics.Raycast(ray, out hit))  
  26.             {  
  27.                 //判断点击的是否地形  
  28.                 if (!hit.collider.name.Equals("Terrain"))  
  29.                 {  
  30.                     return;  
  31.                 }  
  32.                 //点击位置坐标  
  33.                 Vector3 point = hit.point;  
  34.                 //转向  
  35.                 transform.LookAt(new Vector3(point.x, transform.position.y, point.z));  
  36.                 //设置寻路的目标点  
  37.                 agent.SetDestination(point);  
  38.             }  
  39.         }  
  40.   
  41.   
  42.         //播放动画,判断是否到达了目的地,播放空闲或者跑步动画  
  43.         if (agent.remainingDistance == 0)  
  44.         {  
  45.             animation.Play("idle");  
  46.         }  
  47.         else  
  48.         {  
  49.             animation.Play("run");  
  50.         }  
  51.           
  52.     }  
  53. }  
完成了,可以看看效果:


  • 相关知识
1.角色身上的Nav Mesh Agent 组件

Radius 半径: 代理的半径(仅用于寻路目的,可以跟实际对象的半径大小不一样,一般比实际对象的半径大)。
Speed 速度: 代理可以周游世界,走向它的目的地的最大移动速度。
Acceleration 加速度: 最大加速度。
Angular Speed 角速度: 最高转速(度/秒)。
Stopping distance 制动距离:制动距离。到目的地的距离小于这个值,代理减速。
Auto Traverse OffMesh Link 自动遍历OffMesh链接:自动移动并关闭OffMeshLinks
Auto Repath 自动重新寻路:如果现有的部分已失效,获得新的路径。
Height 高度:代理的高度(用于调试图形)。
Base offset 基本偏移:碰撞几何体相对于实际几何体垂直的偏移。
Obstacle Avoidance Type 障碍躲避类型 :躲避的质量水平。
NavMesh Walkable 导航网格行走:指定代理可以遍历的导航网格层类型。这个参数很有用,在接下来的实例中可以用到

2.障碍物一定要有Mesh Render,用于烘焙寻路网格。
  • 总结
这个实例可以很简单的让我们学会如何最基本的使用自动寻路组件Nav。但是,这个组件还提供了更加强大的功能,比如,起始点和目标点中间出现阻断了,
怎么办?在下面的文章中,我们将会继续探寻其他强大的功能。

  • 源码

http://pan.baidu.com/s/1hqC6v4o

  • 参考资料

1.http://www.xuanyusong.com/

2.http://liweizhaolili.blog.163.com/

3.http://game.ceeger.com/Components/class-NavMeshAgent.html

2017-05-17 17:24:11 yongh701 阅读数 5680

毕竟游戏里面,不能所有物体都要求它按照一条定向的路径移动的,需要给玩家一个操作空间,让玩家点哪,这东西自然而然地去哪里。因此自《【iTween】指定路径位移》(点击打开链接)之后,自动寻路的需求应运而生。不过,Unity3D自带的功能,就能完成这个看起来高大上的功能。下面举一个例子说明这个问题。

如下图,摆了4个cube当作墙,然后摆一个球,当作游戏的主角,鼠标点哪走哪,但关键是不会出现穿墙的情况。


具体做法如下:

一、场景布置

1、如下图所示,没什么好说的。


2、之后先将这个场景保存为Navmesh,然后如下图打开自动寻路设置界面。


如下图所示,在Navigation界面,对所有代表墙的Cube和地板Plane都勾上Navigation Static。表示这些都是寻路的阻碍物。

都设置好再点击Bake。烘培之后就会出现如下图的淡蓝色的,可移动的区域。这是Unity3D自己能计算出来的。


3、给球加上Nav Mesh Agent这个组件,表示它是一个被导航体。里面的半径、速度等,Unity3D给你上这个组件的时候,基本会给你计算好的,如果你是自己导入的3D模型估计需要将半径改到和你的3D模型基本匹配的程度。


4、之后再给Plane上一个plane标签,用于碰撞检测。因为Unity3D中,鼠标点击Plane,需要是在鼠标点击的屏幕像素点,发出一条直线和Unity3D世界中物体碰撞,才能找到准确的点击的。这在《【Unity3D】判断是否鼠标点击物体与血条制作》(点击打开链接)已经说了,这里不再赘述了。毕竟这个plane注定要会被我们一会儿疯狂点击的。


二、脚本设置

给球sphere赋予如下的Navigation.cs:

using UnityEngine;
using System.Collections;

public class Navigation : MonoBehaviour
{
    private NavMeshAgent navMeshAgent;
    void Start()
    {
        navMeshAgent = gameObject.GetComponent<NavMeshAgent>();//初始化navMeshAgent
    }
    void Update()
    {
        if (Input.GetMouseButtonDown(0))//鼠标左键点下  
        {
            Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);//住摄像机向鼠标位置发射射线 
            RaycastHit mHit;
            if (Physics.Raycast(mRay, out mHit))//射线检验 
            {
                if (mHit.collider.gameObject.tag == "plane")
                {
                    navMeshAgent.SetDestination(mHit.point);//mHit.point就是射线和plane的相交点,实为碰撞点
                }
            }
        }
    }
}
则能够享受NavMeshAgent带来的Unity3D自动寻路的欢乐~(*^_^*)

2013-06-14 17:52:34 mashuailove 阅读数 2428
   接着我的 上一篇自动寻路文章,这一次我们就来学习一下与自动寻路有关的组件吧。Unity中与自动寻路相关的组件主要有两个:NavMeshAgent (  又称导航网格代理 ),Off Mesh Link( 分离网格链接 )。这两个组件的作用与使用范围是不同的,我们唯一可以确定的是我们必须烘焙地形,产生NavMesh(导航网格)。因为导航网格决定我们的角色(带有导航网格代理的角色)活动的范围。NavMeshAgent组件需要附着寻路的角色身上,比如怪物,而OffMeshLink这个组件主要是用来构造寻路角色的寻路路径的某个部分,比如我们有时需要怪物在寻路过程中从一个固定的地方移动到另一个固定的地方,这将会在我下面的例子中清楚的看到。好了,甭废话了,让我们开始吧!
        首先,我们先来了解一下NavMeshAgent组件,这个组件是unity3d提供的寻路系统的核心组件。官方是这样解释的:The NavMeshAgent component is connection with pathfinding,and is the place to put information about how this agent navigates the NavMesh 。意思大致是这样的:NavMeshAgent组件是关于寻路的,它是一个用来存放代理周游导航网格的路径信息的平台。那么代理又是什么呢?原来,角色的移动是要依靠代理来做的,每一个附着这个组件在寻路的过程中都是利用代理进行的,这也就是这个组件为什么叫导航网格代理的原因。每一个你需要让它具有自动寻路功能的角色必须要附着这个组件,除非你利用其它的寻路算法,但那样做实在是太复杂了,因为考虑的情况太多了,然而Unity为我们提供了这样一个组件,我们为啥不用呢?我们先来举一个例子吧,这样学起来也好理解一些。
        我接着我上一篇文章中的工程,新建了一个Scene,给了它一个名字:TestNavgation2。然后这个场景里面也需要一个地面,我还是用Cube来做。这次我先向这个平面上建一个Spere,重命名为Hero,并且给它加上一个NavMeshAgent组件,方法:Unity菜单,Component->Navgation->NavMeshAgent。给Hero上个颜色就像下面截图一样:



选中Hero,在Inspector下,我们可以看到NavMeshAgent组件的各个属性:



这几个属性我简单的解释一下:
Radius:导航代理的半径,我们可以适当的调节一下这个值

Speed :这个属性代表这个导航网格代理寻路时可以达到的最大速率

Acceleration :加速度,表示代理的速度从0加速到Speed时的最大的加速度

Angular Speed :最高的角速度

Stopping distance : 制动距离,当代理据目的地的距离小于这个值时开始减速

Auto Traverse OffMesh Link :自动移动并关闭OffMeshLinks,这个选项对于我们利用程序来操纵后面我要介绍的OffMeshLink很关键,

Auto Repath   自动重新寻路,如果发现现有路径已失效,那么它将获得新的路径,这个选项我们一般将其勾选上

Height  : 导航代理的高度。

Base Offset : 基本偏移,我们可以通过调整这个变量来调整代理自身的包围盒

Obstacle Avoidace Type  : 代理躲避的水平,一般我们选默认的High Quality就行了

NavMesh Walkable :导航网格代理可以通过的网格层类型
好了这些属性我们基本上知道了一点,但要真正理解它,我们还有很长的路要走。我们到头来是要用脚本来控制寻路的,也就是说我们必须掌握NavMeshAgent这个类,还是老办法,看文档吧,记住,文档我们必须看,这是我们学习新东西必须做的,那些出视频,出书的没一个不是从看文档开始的。
        我们看NavMeshAgent这个类,Unity菜单:help->Scripting Reference 。我们找到这个类,发现里面的变量和方法还不少呢。这次我不可能将其全部讲解到 , 因为有些我自己都没用过,所以我只讲解我们常用的:
NavMeshAgent(导航网格代理组件所对应的类)
假使我们的主角身上添加了一个导航网格组件,我们一般在脚本中这样定义NavMeshAgent类型的成员变量:
private NavMeshAgent nma ;
并在Start或Awake函数中实例化它:
nma = gameObject.GetComponent<NavMeshAgent>();
重要变量:
1.destination
我们可以这样对导航网格代理设置目的地:
nma.destination = Vector3类型的值。相当于nma.SetDestination( Vector3类型的值 )

2.stoppingDistance
这个与Inspector面板中的Stopping Distance对应,一下再不涉及与Inspector面板中的属性对应的变量

3.velocity
导航网格代理周游时的实时速度,非常重要

4.nextPosion
顾名思义,也就是下一个位置,在Update函数中打印这个属性,你会发现打印出的结果与这个导航网格代理周游过的路径一致

5.steeringTarget(只读)
这个属性是相当重要的,它指的是导航网格代理在导航网格中周游时所经过的拐点,这对于制作寻路网游同步角色的Transform是相当重要的,因为导航网格的寻路路线是直线,我们只需将其寻路的拐点与旋转角度告诉给服务器端,有服务器端广播出去,然后再写一个执行Transform同步的脚本(是特制的)绑定在非角色玩家身上就可以了。

6.desiredVelocity(只读)
这个属性说实话我用的不多,指的是导航网格代理的期望速度,与其当前速度不是等价的。

7.remainingDistance( 只读 )
导航网格代理离目的地还剩的距离,如果其值为0,那么代理已经到达了目的地了,所以我们可一个这样判断一个导航网格代理是否到达了目的地:
if( nma.remainingDistance == 0 ){
//执行行为

}

8.isOnOffMeshLink
导航网格代理当前的位置是否位于OffMeshLink,因为这个牵扯到了另一个组件,我会在后面说的

重要方法:
1.SetDestination( Vector3 v )
设置目的地,与nma.destination = v一样的,你想怎么用都行,只是这个函数在设置目的地成功后返回***e,否则返回false,就只比调用属性多了一个返回值

2.ActivateCurrentOffMeshLink( bool activated )
返回值为空
与OffMeshLink有关,当activated为***e激活OffMeshLink,后面会讲到的

3.CompleteOffMeshLink ()
让导航网格代理完成在OffMeshLink上的周游,后面会讲的

4.Move( Vector3 v )
让导航网格代理朝向量v的世界坐标系方向平移v的长度

5.Stop()
让导航网格代理停止寻路,但此寻路状态可以靠下面一个函数恢复到寻路状态,并且目的地也与上次一样

6.Resume()
恢复寻路状态,此时角色会在上一次执行了Stop函数停下来后恢复当时的状态,目的地为上一次的目的地

这8个属性与Inspector面板上的各个属性并且和这6个函数我们一定要好熟练掌握,这关系到我们是否能熟练书写寻路脚本。还有一些函数我这里没有介绍,就留着读者自己研究研究吧。
         此刻我相信读者对这个组件已经有了相当深刻的认识了,但是还没完,我们必须做的一个步骤就是烘焙场景,生成导航网格。为什么要这样做呢?因为Unity3d自带的寻路系统的原理是事先通过烘焙将地形的信息记录起来存储在NavMesh文件上。我们烘焙一次看看,其实做法很简单 ,我们打开Navigation窗口,做法:Window>Navigation。然后选中Plane,出现下面截图:


我们可以看到Navigation Static复选框,勾选它。那它的作用是什么呢?原来,每一个GameObject都可以标记成静态的或非静态的,就想这样:



我们看到Plane的右侧有一个Static属性,展开他我们可以看到:



这里面每一种静态选项背后都包含一种技术,比如Lightmap Static,用于生成光照贴图对场景进行优化。还有Occluder Static与Occludee Static,是关于Unity3d中与遮挡剔除技术有关的。好了,言归正传,导航网格代理是在导航网格上周游的。所以我们的地面必须生成导航网格,这里的Navigation Static属性框必须勾上。这时我们看到了第二个属性框:OffMeshLink Generation,勾选上之后我们就可以不借助OffMeshLink组件来生成OffMeshLink。那么什么是OffMeshLink呢?请看下图:



看到那些个线没有?每一条线就代表一个OffMeshLink。那么此时我可以引入OffMeshLink组件了,这个组件其实就是自定义像上图那样的样条线,但每一个OffMeshLink组件只能形成一个样条线。这个样条线的作用可不一般啊,但是应用其时我们必须格外注意一些问题,不然我们即使用了这个组件也不会产生丝毫的作用的。
        那好吧,我们该做点什么了!
        如上图,我建了连个Plane,分别为Plane1,Plane2。我们一次选择这两个平面,在Navigation窗口将Navigation Static 与Off Mesh Link Generation选项给勾上,并选择Navigation Layer为Default。然后单击Bake按钮,如下:


我们还建立一个围墙,用Cube做的,我们在Navigation面板中除了勾选Navigation Static之外,还必须将其Navigation Layer下拉框中选择Not Walkable,即让我们的Hero绕过此障碍物达到目的地。Not Walkable只是导航网格层中的一个内建层,我们还可以建立我们自己的导航网格层。关于导航网格层,我会在我的下一篇文章中详细为您讲解。

我们之前说过,导航网格代理的活动空间只能是导航网格,即NavMesh。但现在看来这句话可能需要修改一下了。因为导航网格代理还可能活动在OffMeshLink上面,所以我们可以在两个平面上面建立OffMeshLink来连通两个平面。我们现在没有用Off Mesh Link组件,这样就可以生成很多的OffMeshLink。但是我们发现烘焙后的场景没有出现Off Mesh Link。到底是什么原因呢?原来,我们还得设置一些参数:


我们看到了一个选项 :Jump Distance。我们将这个值调到4,再次烘焙一次,则出现了以下场面:



然后我们新建一个Cube,命名为:DS。将其放置在上图中的白色的Cube所在的位置上,然后我写一个脚本:

using UnityEngine;
using System.Collections;

public class SetHeroDes : MonoBehaviour {
    public Transform ds;//目的Cube的Transform
    private Vector3 origin;//存储导航网格代理的初始位置
    private NavMeshAgent nma;//存储导航网格代理组件

        void Start () {
             nma =  gameObject.GetComponent<NavMeshAgent>();
    //取得导航网格代理组件
             origin = transform.position;
    //实例化origin
        }

    void OnGUI()
    {
        if(GUILayout.Button("Start***n"))
        {
            nma.SetDestination(tf.position);
        //设置导航网格代理的目的地
        }
        if (GUILayout.Button("Resume"))
        {
            transform.position = origin;
            //恢复导航网格代理的位置为初始位置
        }
    }
}

我们将这个脚本绑定到Hero上,然后将DS拖拽到指定位置:


然后我们运行一下:







我们可以清楚的发现,我们的Hero越过了重重阻壑,终于到达了目的地。可是问题此时又随之而来了:如果我们将Hero中的导航网格代理组件中的Auto Traverse Off Ms选项给去掉,它还会越过重重沟壑到达我们的目的地吗?实验证明这样做是无法成功的。官方文档对这个勾选的解释为:
Automate movement onto and off of OffMeshLinks。大致是这样的:自动移动并且将OffMeshLinks关闭。你想,OffMeshLink都关闭了,Hero还怎么过来呢?
        接下来我再来介绍OffMeshLink组件的用法了,操作非常简单:
1.新建连个空的GameObject或者你用模型也行,分别取名为StartPoint和EndPoint。为了便于识别,我用的是Sphere,给它上个绿色,并调节StartPoint的位置为Plane1上面,EndPoint的位置咋Plane2上面;


2.接着我们新建一个空的GameObject,取名为:SingleOffMeshLink,并让StartPoint与EndPoint成为其子物体,为SingleOffMeshLink加入OffMeshLink组件,做法:选中SingleOffMeshLink,然后再Unity菜单栏中:Component->Navigation->Off Mesh Link。如下图:



我们将StartPont拖拽到Start上,EndPoint拖拽到End上。最后烘焙一下场景(此时Plane1与Plane2在Navigation中的OffMeshLink Generation勾选给去掉,目的是自定义我们的OffMeshLink):



看到没,只生成了一条样条线。这就是我们自己做的OffMeshLink。我们可以编写一些简单的脚本来测试一下Hero此时是否会到达Plane2上的目的地。我想我们还会碰到一些问题的,但我觉得这些问题都不难解决,只需要花些时间尝试。那么最后留给读者一个问题,如果我们打开两个平面的OffMeshLink,那么Hero到底是从我们自定义的OffMeshLink上掠过还是从Plane自身生成的OffMeshLink上掠过?还有,如果我们将Hero身上的Auto Traverse Off Ms勾选给去掉,那么是不是犹如前一个实验一样发生越不过去的问题?这个问题如果弄清楚了,我的这篇帖子也就完成了它的使命了。好了,下次我准备重点讲解导航网格层的运用,这是重点中的重点。那么我们下次再会!
2015-07-19 13:05:07 CodeEmperor 阅读数 1352
添加新物体,命名为Player,添加组件Nav Mesh Agent.同时添加Navigation,将
需要进行自动寻路的地方进行烘焙。创建脚本Follow:
using UnityEngine;
using System.Collections;
public class Follow : MonoBehaviour
{
    public Transform target;
    private NavMeshAgent agent;
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }
    // Update is called once per frame
    void Update()
    {
        if (target != null)
        {
            agent.destination = target.position;
        }
    }
}
创建一个新物体Target,拖入脚本的变量中,可使Player自动找到Target。无论
Player如何变化,都可以找到。
新建Cube添加Nav Mesh Obstacle组件,将所有的障碍物都进行烘焙。此时Player
可绕过障碍物找到Target.
当Target突然移动时,为了让Player直接跳下来可设置Bake中的Drop Height的值
为4,Object中的选项都勾选上。

Unity3D中的自动寻路

阅读数 1643

Unity3d自动寻路基础教程

博文 来自: grf123
没有更多推荐了,返回首页