我正在使用Unity 5中的AI脚本,该脚本主要由协同程序构建,以便在我的游戏中移动AI对象。它实际上工作得很好,并且这种方式与帧无关。我试图避免使类的Update
函数混乱。
然而,我正在尝试创建一个名为wander的函数,其中AI挂起并在航点区域中随机选择几个Vector3
并前往其中的每一个。在此之后,AI应该转到下一个航路点并基本上做同样的事情到无穷大。碰撞检测和所有类型适用于后续部件。我想首先修复导航部分。
void Start(){
agent = GetComponent<NavMeshAgent> ();
collisionRange = GetComponent<CapsuleCollider> ();
collisionRange.radius = detectionRadius;
if (waypoints.Length > 0) {
StartCoroutine (patrol ());
} else {
StartCoroutine (idle (idleTime));
}
}
IEnumerator patrol(){
agent.SetDestination(waypoints[waypointIndex].position);
Debug.Log ("Patrol started, moving to " + agent.destination);
while (agent.pathPending) {
Debug.Log ("not having path");
yield return null;
}
Debug.Log ("I have a path, distance is " + agent.remainingDistance);
while (float.Epsilon < agent.remainingDistance) {
//Debug.Log ("Moving...");
yield return null;
}
StartCoroutine (nextWaypoint ());
}
IEnumerator idle(int time){
Debug.Log ("Idleing for "+ time + " seconds");
agent.Stop ();
yield return new WaitForSeconds(time);
if(waypoints.Length > 2){
agent.Resume ();
StartCoroutine(patrol());
}
}
IEnumerator wander(){
agent.Stop ();
Debug.Log ("Going to look around here for a while.");
Vector3[] points = new Vector3[wanderPoints];
for (int i = 0; i < wanderPoints; i++) {
agent.Stop ();
Vector3 point = Random.insideUnitSphere * wanderRadius;
point.y = transform.position.y;
points [i] = point;
}
agent.ResetPath ();
agent.SetDestination(points[0]);
agent.Resume ();
Debug.Log ("point: " + points [0]);
Debug.Log ("Destination: " + agent.destination);
while (float.Epsilon < agent.remainingDistance) {
Debug.Log ("Moving...");
yield return null;
}
//StartCoroutine(patrol());
yield return null;
}
IEnumerator nextWaypoint(){
Debug.Log ("Arrived at my waypoint at " + transform.position);
if (waypointIndex < waypoints.Length -1) {
waypointIndex +=1;
} else {
waypointIndex = 0;
}
StartCoroutine(wander ());
yield return null;
}
如果我将wander
函数与idle
中的nextWaypoint
函数交换,一切都按预期工作,但这一位将永远不会有效:
agent.ResetPath ();
agent.SetDestination(points[0]);
agent.Resume ();
Debug.Log ("point: " + points [0]);
Debug.Log ("Destination: " + agent.destination);
这是一些测试代码(手动设置只有1个位置point[0]
,但它永远不会到达目的地。SetDestination
永远不会更新到我想要设置它们的点我已经尝试过预先计算路径(NavMeshPath),除了目标路径之外的所有内容都不会改变或重置得非常奇怪。我在while (float.Epsilon < agent.remainingDistance)
函数中也有wander
循环,但是没有运气,因为它将永远留在那个循环中,因为没有路可走。
我可能在这里遗漏了一些东西,或者在这种情况下我的逻辑是错误的。希望有人可以给我一点推动或者一些额外的调试选项,因为我不知道为什么目的地没有在我的漫游功能中更新。
答案 0 :(得分:1)
考虑在航点上使用触发器,因为这对系统来说更加轻微。下面是一个示例,通过从父变换中获取所有 WayPoint 类型的子项,您可以轻松获得可变数量的航点。唯一使用的协同程序是空闲的,因为你说你不希望你的更新功能混乱。
我还暴露了一些额外的变量,包括最小和最大空闲时间,以及巡逻机会,应该将其设置为小于或等于1的值,表示巡逻与空闲的百分比。您还可以选择最小和最大数量的巡逻点,以便代理导航到。
在 RandomActivity 中,您还可以看到无限空闲的错误处理(父级下没有WayPoint子级)。代理也不会在其导航到的点列表中包含当前Waypoint,并且不会导航到在当前巡逻期间已经导航到的点(每次将元素添加到 m_targets 时,它都是已从 m_availableTargets 中删除。
<强> AgentController.cs 强>
[RequireComponent(typeof(NavMeshAgent))]
public class AgentController : MonoBehaviour
{
[SerializeField]
private Transform m_waypointParent;
[SerializeField]
private float m_minIdle;
[SerializeField]
private float m_maxIdle;
[SerializeField]
private float m_patrolChance;
[SerializeField]
private int m_minPatrolPoints;
[SerializeField]
private int m_maxPatrolPoints;
private Waypoint[] m_waypoints;
private List<Waypoint> m_availableTargets;
private List<Waypoint> m_targets;
private Waypoint m_tempWaypoint;
private int m_currentTargetIndex;
private NavMeshAgent m_navMeshAgent;
public void Start()
{
m_waypoints = m_waypointParent.GetComponentsInChildren<Waypoint>();
m_targets = new List<Waypoint>();
m_navMeshAgent = GetComponent<NavMeshAgent>();
RandomActivity();
}
private void RandomActivity()
{
if (m_waypoints.Length == 0)
{
Debug.Log("Enemy will idle forever (no waypoints found)");
StartCoroutine(Idle(Random.Range(m_minIdle, m_maxIdle)));
return;
}
if(Random.Range(0f, 1f) <= m_patrolChance)
{
//Available waypoints
m_availableTargets = new List<Waypoint>(m_waypoints);
//Remove currentpoint
if(m_targets.Count > 0)
m_availableTargets.Remove(m_targets[m_targets.Count - 1]);
//Reset list
m_targets.Clear();
m_currentTargetIndex = -1;
//Add patrol points
for (int i = 0; i < Random.Range(m_minPatrolPoints, m_maxPatrolPoints + 1); i++)
{
m_tempWaypoint = m_availableTargets[Random.Range(0, m_availableTargets.Count)];
m_targets.Add(m_tempWaypoint);
m_availableTargets.Remove(m_tempWaypoint);
}
NextWaypoint(null);
}
else
StartCoroutine(Idle(Random.Range(m_minIdle, m_maxIdle)));
}
public void NextWaypoint(Waypoint p_waypoint)
{
//Collided with current waypoint target?
if ((m_currentTargetIndex == -1) || (p_waypoint == m_targets[m_currentTargetIndex]))
{
m_currentTargetIndex++;
if (m_currentTargetIndex == m_targets.Count)
RandomActivity();
else
{
Debug.Log("Target: " + (m_currentTargetIndex + 1) + "/" + m_targets.Count + " (" + m_targets[m_currentTargetIndex].transform.position + ")");
m_navMeshAgent.SetDestination(m_targets[m_currentTargetIndex].transform.position);
}
}
}
private IEnumerator Idle(float p_time)
{
Debug.Log("Idling for " + p_time + "s");
yield return new WaitForSeconds(p_time);
RandomActivity();
}
}
请注意,为此,我创建了一个名为Enemy的标签,以便轻松区分游戏中的敌人和任何其他跳跃者。
<强> WayPoint.cs 强>
[RequireComponent(typeof(BoxCollider))]
public class Waypoint : MonoBehaviour
{
public void OnTriggerEnter(Collider p_collider)
{
if (p_collider.tag == "Enemy")
p_collider.GetComponent<AgentController>().NextWaypoint(this);
}
}
我知道这是一篇很老的帖子,但希望这对某人有帮助。