1. NavMesh Surface
- 得先添加Navmesh的组件,应该是在包管理器导入。
- 创建一个空物体,添加脚本Nav Mesh Surface。
- Bake即可获得区域。
- 设置如下图:
2. 在目标上挂上NavMeshAgent
3. 设置路径
- 设置了三个点当做范围,目标会依次到达这三个点。
- 都是空物体。
4. PatrolPath.cs
- 可以把enemy的List改成gameObject。
using System.Collections.Generic;
using UnityEngine;
namespace Unity.FPS.AI
{
public class PatrolPath : MonoBehaviour
{
[Tooltip("Enemies that will be assigned to this path on Start")]
public List<EnemyController> EnemiesToAssign = new List<EnemyController>();
[Tooltip("The Nodes making up the path")]
public List<Transform> PathNodes = new List<Transform>();
void Start()
{
foreach (var enemy in EnemiesToAssign)
{
enemy.PatrolPath = this;
}
}
public float GetDistanceToNode(Vector3 origin, int destinationNodeIndex)
{
if (destinationNodeIndex < 0 || destinationNodeIndex >= PathNodes.Count ||
PathNodes[destinationNodeIndex] == null)
{
return -1f;
}
return (PathNodes[destinationNodeIndex].position - origin).magnitude;
}
public Vector3 GetPositionOfPathNode(int nodeIndex)
{
if (nodeIndex < 0 || nodeIndex >= PathNodes.Count || PathNodes[nodeIndex] == null)
{
return Vector3.zero;
}
return PathNodes[nodeIndex].position;
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.cyan;
for (int i = 0; i < PathNodes.Count; i++)
{
int nextIndex = i + 1;
if (nextIndex >= PathNodes.Count)
{
nextIndex -= PathNodes.Count;
}
Gizmos.DrawLine(PathNodes[i].position, PathNodes[nextIndex].position);
Gizmos.DrawSphere(PathNodes[i].position, 0.1f);
}
}
}
}
5. EnemyController的脚本设置
- 利用PatrolPath函数,设置一个Patrol变量:
public PatrolPath PatrolPath {
get; set; }
public NavMeshAgent NavMeshAgent {
get; private set; }
public DetectionModule DetectionModule {
get; private set; }
int m_PathDestinationNodeIndex;
//获取组件模块
NavMeshAgent = GetComponent<NavMeshAgent>();
- 设置导航模式:
var navigationModules = GetComponentsInChildren<NavigationModule>();
DebugUtility.HandleWarningIfDuplicateObjects<DetectionModule, EnemyController>(detectionModules.Length,
this, gameObject);
// Override navmesh agent data
if (navigationModules.Length > 0)
{
m_NavigationModule = navigationModules[0];
NavMeshAgent.speed = m_NavigationModule.MoveSpeed;
NavMeshAgent.angularSpeed = m_NavigationModule.AngularSpeed;
NavMeshAgent.acceleration = m_NavigationModule.Acceleration;
}
- 先设置bool值判断目标点位置是否为0,然后进行目标点的更新。
bool IsPathValid()
{
return PatrolPath && PatrolPath.PathNodes.Count > 0;
}
public void ResetPathDestination()
{
m_PathDestinationNodeIndex = 0;
}
public void SetPathDestinationToClosestNode()
{
if (IsPathValid())
{
int closestPathNodeIndex = 0;
for (int i = 0; i < PatrolPath.PathNodes.Count; i++)
{
float distanceToPathNode = PatrolPath.GetDistanceToNode(transform.position, i);
if (distanceToPathNode < PatrolPath.GetDistanceToNode(transform.position, closestPathNodeIndex))
{
closestPathNodeIndex = i;
}
}
m_PathDestinationNodeIndex = closestPathNodeIndex;
}
else
{
m_PathDestinationNodeIndex = 0;
}
}
public Vector3 GetDestinationOnPath()
{
if (IsPathValid())
{
return PatrolPath.GetPositionOfPathNode(m_PathDestinationNodeIndex);
}
else
{
return transform.position;
}
}
public void SetNavDestination(Vector3 destination)
{
if (NavMeshAgent)
{
NavMeshAgent.SetDestination(destination);
}
}
public void UpdatePathDestination(bool inverseOrder = false)
{
if (IsPathValid())
{
// Check if reached the path destination
if ((transform.position - GetDestinationOnPath()).magnitude <= PathReachingRadius)
{
// increment path destination index
m_PathDestinationNodeIndex =
inverseOrder ? (m_PathDestinationNodeIndex - 1) : (m_PathDestinationNodeIndex + 1);
if (m_PathDestinationNodeIndex < 0)
{
m_PathDestinationNodeIndex += PatrolPath.PathNodes.Count;
}
if (m_PathDestinationNodeIndex >= PatrolPath.PathNodes.Count)
{
m_PathDestinationNodeIndex -= PatrolPath.PathNodes.Count;
}
}
}
}
6. Agent移动速度设置:
using UnityEngine;
namespace Unity.FPS.AI
{
// Component used to override values on start from the NavmeshAgent component in order to change
// how the agent is moving
public class NavigationModule : MonoBehaviour
{
[Header("Parameters")] [Tooltip("The maximum speed at which the enemy is moving (in world units per second).")]
public float MoveSpeed = 0f;
[Tooltip("The maximum speed at which the enemy is rotating (degrees per second).")]
public float AngularSpeed = 0f;
[Tooltip("The acceleration to reach the maximum speed (in world units per second squared).")]