1.选中要地面 或者 地图上的静态障碍物:树\房子\石头等
2.在U3D右边Inspector面板右上角Static旁边的倒三角 ,选中 Navigation static 勾, 表示地面导航层 ,把当前选中物体设置为导航层
3.菜单栏Window ->Navigation ,Inspector面板 右下角 Bake烘焙,生成导航路径数据
4.然后要移动的角色身上添加 NavMeshAgent组件,就可以导航移动角色
NavMeshAgent 组件面板属性
agent.updateRotation = false; //不允许NavMesh来旋转角色
agent.updatePosition = true; //允许NavMesh来移动角色agent.velocity.magnitude 这个也是速度, GetComponent
().SetFloat("Speed", agent.velocity.magnitude); speed 移动速度
Angular Speed 转角速度 ,转身速度 角速度: 最高转速(度/秒)。
Acceleration 加速度,启动时的 最大加速度。
Stopping Distance 停止距离 ,,制动距离:制动距离。到目的地的距离小于这个值,代理减速。
Auto Traverse OffMesh Link 自动遍历OffMesh链接:自动移动并关闭OffMeshLinks
Auto Repath 自动重新寻路:如果现有的部分已失效,获得新的路径。
Height 高度:代理的高度(用于调试图形)。
Base offset 基本偏移:碰撞几何体相对于实际几何体垂直的偏移。
Obstacle Avoidance Type 障碍躲避类型 :躲避的质量水平。
NavMesh Walkable 导航网格行走:指定代理可以遍历的导航网格层类型。这个参数很有用,在接下来的实例中可以用到。
1.启用组件,即使角色在站立状态,也会轻微为角色添加移动,非常小的,但是会影响刚体的速度的属性.最好开始移动时 启用NavMeshAgent,移动结束关闭NavMeshAgent.
2. 使用了NavMeshAgent就不能用 transform.position = newPos;因为上面说了NavMeshAgent不停的为角色坐标赋值,用 WarpPoint(newPos)代替或者移动赋值前先NavMeshAgent.enabled = false。
3.在使用Rigidbody.AddForce施加外力时,首先关闭NavMeshAgent,重置刚体速度Rigidbody.velocity = Vector3.zero,然后在下一帧内对刚体加力,不能在同一帧进行!!!
remainingDistance //寻路剩余距离,角色和目标点的距离,(有时候为0,需要与Vector3.Distance()效验)
stoppingDistance //停止距离
SetDestination(Point);//设置要移动的目标点
destination //设置要移动的目标点
Stop(); //停止移动,寻路停止
Resume //Stop之后用Resume来恢复
path.corners;//储存路径,路径坐标点数组
ResetPath(); //重置路径
pathStatus //路径状况 ,当前路况的状态(完整,局部或者无效)。
PathComplete 在目的地的路径终止。The path terminates at the destination.
PathPartial 路径中不能到达目的地。The path cannot reach the destination.
PathInvalid 路径无效。The path is invalid.
velocity.magnitude //移动速度
//移动到B角色面前,用角色和B角色的包围盒的最近点,这样就不用修改 stoppingDistance停止距离
agent.stoppingDistance = 敌人包围盒半径的长度;
agent.destination = target.collider.ClosestPointOnBounds(transform.position);
///
/// 是否在移动中
///
///
public bool IsMoving
{
get
{
if (agent != null && agent.enabled)
{
remainingDistance = Vector3.Distance(Transform.position, agent.destination);
return agent.pathPending || remainingDistance > agent.stoppingDistance || agent.velocity != Vector3.zero;
}
return false;
}
}
/// 是否移动结束
bool EventMoveEnd() {
return state == "MOVING" && !IsMoving();
}
///
/// 绘制移动路线
///
void OnDrawGizmos()
{
var agent = GetComponent();
var path = agent.path;
Color c = Color.white;
switch (path.status)
{
case UnityEngine.AI.NavMeshPathStatus.PathComplete: c = Color.white; break;
case UnityEngine.AI.NavMeshPathStatus.PathInvalid: c = Color.red; break;
case UnityEngine.AI.NavMeshPathStatus.PathPartial: c = Color.yellow; break;
}
for (int i = 1; i < path.corners.Length; ++i)
Debug.DrawLine(path.corners[i-1], path.corners[i], c);
}
状态切换
//取消移动
agent.ResetPath();
return "IDLE";
//角色死亡
agent.ResetPath();
//移动到点
agent.stoppingDistance = 0.1f;
agent.destination = pos;
return "MOVING";
// 移动到敌人包围盒前
agent.stoppingDistance = target.agent.radius;
agent.destination = target.collider.ClosestPointOnBounds(transform.position);
return "MOVING";
using System;
using UnityEngine;
using UnityEngine.AI;
using Debug = UnityEngine.Debug;
public class MoveNavMeshAgent : MonoBehaviour
{
public NavMeshAgent agent;
[SerializeField]
bool _isMoveing = false;
[SerializeField]
float remainingDistance;
[SerializeField]
Vector3 curr_destination;
[SerializeField]
Vector3 last_destination;
private Transform Transform;
void Awake()
{
agent = gameObject.GetComponent();
if(!agent)Debug.LogError(gameObject.name + " no NavMeshAgent compent");
Transform = gameObject.transform;
agent.updateRotation = true; //允许NavMesh来旋转角色
agent.updatePosition = true; //允许NavMesh来移动角色
agent.enabled = false;
}
///
///使用了NavMeshAgent就不能用 transform.position = newPos;用 WarpPoint(newPos)代替或者移动赋值前先NavMeshAgent.enabled = false
///
///
public void WarpPoint(Vector3 destination)
{
if (agent.enabled == false)
{
agent.enabled = true;
}
agent.Warp(destination);
agent.enabled = false;
}
///
/// 是否在移动中
///
///
public bool IsMoving
{
get
{
if (agent != null && agent.enabled)
{
remainingDistance = Vector3.Distance(Transform.position, agent.destination);
_isMoveing = agent.pathPending || remainingDistance > agent.stoppingDistance || agent.velocity != Vector3.zero;
}
else
{
_isMoveing = false;
}
return _isMoveing;
}
}
///
/// 是否移动结束
///
///
public bool IsMoveEnd
{
get
{
return !IsMoving;
}
}
//停止移动
public void StopMove()
{
if (agent.enabled == true) //停止NavMeshAgent ,停止移动
{
agent.ResetPath();
agent.Stop();
agent.enabled = false;
}
}
///
/// 移动到点
///
public void MovePoint(Vector3 destination, float stoppingDistance = 0.17f)
{
curr_destination = destination;
if (agent.enabled && curr_destination == last_destination && IsMoving && Math.Round(stoppingDistance, 2) == Math.Round(agent.stoppingDistance, 2))//与上一次目的地相同,就跳过
{
return;
}
if (agent.enabled == false)
{
agent.enabled = true;
}
agent.stoppingDistance = stoppingDistance;
agent.destination = destination;
last_destination = curr_destination;
}
///
/// 移动到距离敌人包围盒最近的点,如果是远程英雄的话 stoppingDistance 就是攻击距离,
///
///
///
public void MoveToEnemy(Collider enemyCollider, float stoppingDistance = 0.17f)
{
Vector3 destination = enemyCollider.ClosestPointOnBounds(Transform.position);
MovePoint(destination, stoppingDistance);
}
///
/// 绘制移动路线
///
void OnDrawGizmos()
{
if (agent != null && agent.enabled == true)
{
var path = agent.path;
// color depends on status
Color c = Color.white;
switch (path.status)
{
case UnityEngine.AI.NavMeshPathStatus.PathComplete:
c = Color.white;
break;
case UnityEngine.AI.NavMeshPathStatus.PathInvalid:
c = Color.red;
break;
case UnityEngine.AI.NavMeshPathStatus.PathPartial:
c = Color.yellow;
break;
}
// draw the path
for (int i = 1; i < path.corners.Length; ++i)
Debug.DrawLine(path.corners[i - 1], path.corners[i], c);
}
}
public void FixedUpdate()
{
#if UNITY_EDITOR
var ShowState_Debug = IsMoving;
#endif
}
}