1NavMesh
2NavMesh Agent
3NavMesh Obstacle
4NavMesh Surface
5NavMesh Modifier
6NavMesh Modifier Volume
7NavMesh Link
8Off Mesh Link
9抛物线跳跃脚本
10巡逻脚本
11在使用AI时可能会遇到的问题
【1】NavMesh
Agent Radius:半径数值越小,生成网格面积越大。一般与Agent的数值一致。
Agent Height:烘焙的高度,通常是角色所要通过的高度。一般与Agent的数值一致。
Max Slope:最大斜坡角度。角度越大,代理越能爬坡 ,超过这个坡度寻路者则无法通过。
Step Height:台阶步高。步高越大,导航代理迈过台阶的能力越强(可达到或代替跳跃效果)。
Drop Height:跳落高度。(只能往下跳,往返需要添加Link组件)。
Jump Distance:代理跳跃距离。 表示Agent的跳跃距离的极限。
Manual Voxel Size 导航烘焙的像素效果(提高地图的质量同时降低性能)。
Min Regon Area:网格面枳小于该值的地方,将不生成导肮网格。
Height Mesh:勾选后,将会保存高度信息。占用更多的内存和烘焙时间。(DropHeight数值越高,Agent从上往下所能跳跃的地方的标记越多,需要在视图中勾选显示Height Mesh。)
注意事项:
烘焙的Radius和NavMeshAgent的Radius的区别:
第一阶段只考虑烘培NavMesh并寻找一条可行的路径,而第二阶段Agent就已经在前往目的地的路上了,它会考虑其他agent和obstacle,并尽量避开他们。
烘培时候的Radius就对应第一阶段的生成NavMesh,而Agent上的Radius只在第二阶段使用。就比如说,有一条小径,你有一只大怪是通过不了该路径的,但烘培时候的Radius设置的比较小,虽然Agent的Radius可能设置的很大,但这只大怪还是会使用该小径通过。
Navgation Areas and Costs:这个暂时搞不明白,深入时再了解
【2】NavMesh Agent
Base Offset
碰撞模型和实体模型之间的垂直偏移量。
Speed
物体的速度。
Acceleration
物体的加速度。
Angular Speed
物体的角速度。
Stopping Distance
离目标距离还有多远时停止(一般都会设置一些,因为设置0距离物体可能永远无法到达目的地)。
Auto Braking:自动刹车。
Auto Repath
在行进某些原因中断后是否重新开始寻路。
Radius
物体的半径。
Height
物体的高度。
Quality:物体的质量。
Priority:物体的优先级。
Auto Traverse Off Mesh Link
是否采用默认方式度过链接路径。
Auto Repath:自动复制路径。
Auto Mask:agent会在哪些烘培的区域中寻找路径,能通过的Mask层,这个可以配合Navigation组件中Areas(设置层的)使用。
【3】NavMesh Obstacle
carve:雕刻(Agent就能够识别该物体为障碍物自动更换路线)。
Move Threshold:该参数代表该障碍物的移动的极限距离超过这个参数时,才会重新雕刻这个障碍物(增大此值,障碍物移动没有超过这个距离,就不会重新雕刻导航网格)。
Time To Startionary:障碍物静止不动多少时间后会重新雕刻导航网格。(当障碍物移动的时间不会进行雕刻)。
Carve Only Startionary: 勾选此参数时,只有在障碍物静止时才会对它导航网格进行雕刻。
【4】NavMesh Surface
进阶的NavMesh组件,优势:自定义烘焙单个物体减少性能消耗,无需对整个场景烘焙,可以在动态场景中进行即时烘焙BuildNavMesh();可以在运行时动态的修改NavMesh;支持垂直面烘焙。
Agent Type 导航代理类型(不同宽高、移动旋转速度、爬坡角度),在Navigation窗口设置。
Collect Objects从哪些物体上烘培导航场景。All:场景中有所物体都会拿来烘培 Children:只有自己及其子层级的物体才会加入烘培 Volume指定区域内才会烘培
Include Layers包含哪些的层级。
Use Geometry使用哪种网格来烘培场景。Render Meshs:有MeshRenderer组件的。Physics Colliders:有物理Collider组件的。
Default Area: 默认生成区域类型。
Override Voxel Size: 覆盖默认的Voxel Size,体素尺寸,用来调整精度,场景比较精密的可以把该值调小,值越小精度越高,精度越高,bake越慢,该值与Tile Size共同影响bake的效果。
Override Tile Size: 覆盖默认的Tile Size,块大小,默认是256voxel作为一块,为了让bake有较多平行与增加内存效率才有了此设置,在障碍物多的时候,可以将块减小以提升运行效率。或者打算实时bake的时候,可以用更小的Tile Size来降低内存消耗。
注意事项:复制带有Surface的物体,需要重新烘焙。
【5】NavMesh Modifier
用来被NavMeshSurface组件bake的物体进行微调,组件的作用可用于实时bake,且不需要static,效果包括其下的所有子物体。
Ignore From Build : 烘培时是否无视它。
Override Area : 重写该区域(是否可以走,是否要跳过)。
Affected Agents :排除此物体对某一类agent的影响。
【6】NavMesh Modifier Volume
功能同NavMesh Modifier,只能作用于特定粉色方框内。
【7】NavMesh Link
Agent Type: 哪种Agent才可以使用这个NavMesh Link
Swap:起点和终点位置倒置
Align Transform: 将此物体的Transform中心放在起点和终点的中心
Width :宽度如果为0则通过两个点连接,如果大于0通过两条线连接。
Cost Modifier 非负值时,通过这个链接的代价是Cost Modifier乘以终点的距离。
Bidirectional: 勾上时线的方向为双向,没勾时只能start-to-end单向。
Area Type: 区域类型
【8】Off Mesh Link
可以在两个独立的加载NavMesh Surface的地形中导航。
使用方法:将起点和重点加载到Start和End上,Agent就可以导航。
【9】抛物线跳跃脚本
private IEnumerator Start() { NavMeshAgent agent = GetComponent<NavMeshAgent>(); agent.autoTraverseOffMeshLink = false; while (true) { if (agent.isOnOffMeshLink) { yield return StartCoroutine(Parabola(agent, 2f, 0.5f)); agent.CompleteOffMeshLink(); } yield return null; } } IEnumerator Parabola(NavMeshAgent agent,float height,float duration) { OffMeshLinkData data = agent.currentOffMeshLinkData; Vector3 startPos = agent.transform.position; Vector3 endPos = data.endPos; float time = 0f; while (time <1f) { float yoffset = height * (time - time * time); agent.transform.position = Vector3.Lerp(startPos, endPos, time) + yoffset * Vector3.up; time += Time.deltaTime / duration; yield return null; } }
【10】巡逻脚本
//协程的参考博客分析https://www.cnblogs.com/fly-100/p/3910515.html private NavMeshAgent agent; private Animator anim; public Transform target; Vector3 lastKnowPosition; public Transform eye; bool patrolling; public Transform[] patrolTarget; private int destPoint; private bool arrived; // Use this for initialization void Start () { agent = GetComponent<NavMeshAgent>(); anim = GetComponent<Animator>(); lastKnowPosition = transform.position; } bool CanSeeTarget() { // bool canSee = false; Ray ray = new Ray(eye.position, target.transform.position - eye.position);//获取一个射线,从眼睛的位置射出,射向目标位置 RaycastHit hit; if (Physics.Raycast(ray,out hit)) { Debug.Log(hit.transform+"----"+target); Debug.Log(hit.transform.position + "----" + target.position); if (hit.transform != target) { canSee = false; } else { canSee = true; lastKnowPosition = target.transform.position; } Debug.Log(2); } return canSee; } // Update is called once per frame void Update () { if (agent.pathPending)//调用setDestination 后,会有一个计算路径的时间,计算过程中pathPending为true. 在这个过程中remainingDistance一直为0. { return; } if (patrolling) { if (agent.remainingDistance < agent.stoppingDistance)//剩余距离<停止距离,一定要和pathpengding连用,因为计算remainDistance需要时间,否则数值不会变化。 { if (!arrived) { arrived = true; StartCoroutine("GoToNextPoint"); } } else { arrived = false; } } if (CanSeeTarget()) { agent.SetDestination(target.transform.position); patrolling = false; if (agent.remainingDistance<agent.stoppingDistance) {anim.SetBool("Attack",true); } else { anim.SetBool("Attack", false); } } else { anim.SetBool("Attack", false); if (!patrolling) { agent.SetDestination(lastKnowPosition);//如果没有开始巡逻,就会自动寻路到上次保存的位置点 if (agent.remainingDistance < agent.stoppingDistance)//判定到达上一个目标点停止后,自动开始固定巡逻的协程 { patrolling = true; StartCoroutine("GoToNextPoint"); } } } anim.SetFloat("Forward",agent.velocity.sqrMagnitude); } IEnumerator GoToNextPoint() { if (patrolTarget.Length==0) { yield break; } patrolling = true; yield return new WaitForSeconds(2f);//yield return的值代表何时恢复协程 arrived = false; agent.destination = patrolTarget[destPoint].position; destPoint = (destPoint + 1) % patrolTarget.Length; }
【11】在使用AI时可能会遇到的问题
1.NavMesh Agent的绿色线框是否与物体重合,此项有可能会影响寻路的准确性(在Pivot/local中,子物体和母物体的位置是相对距离,子物体Tranform归零,即可到母物体中心)。
2.Raycast这个方法投射的时候对方必须有碰撞器,否则识别不了。