Unity:How 使游戏对象到达最近的自由位置

Unity:How to make a gameObject reach the closest free position

我正在尝试为必须跟随玩家并定位到最近但尚未被另一个同伴占用的同伴制作 AI

我在同伴中有一个脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ReachPosition : MonoBehaviour
{
 public GameObject[] firstLine = new GameObject[2];

 Transform target;
 // Start is called before the first frame update
 void Start()
 {

 }

 // Update is called once per frame
 void Update()
 {
     //calculate distance from each position
     float dist = Vector3.Distance(transform.position, firstLine[0].transform.position);
     float dist1 = Vector3.Distance(transform.position, firstLine[1].transform.position);

     if (dist < dist1 && firstLine[0].GetComponent<Position>().isEmpty)
     {
         target = firstLine[0].transform;

         Debug.Log(0);
     }
     else if (dist > dist1 && firstLine[1].GetComponent<Position>().isEmpty)
     {
         target = firstLine[1].transform;

         Debug.Log(1);
     }

     //reach target
     transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(target.position - transform.position), 1 * Time.deltaTime);
     transform.position = Vector3.MoveTowards(transform.position, target.position, .01f);


 }

}

并在以下位置触发:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class Position : MonoBehaviour
 {
 public bool isEmpty;
 // Start is called before the first frame update
 void Start()
 {
     isEmpty = true;
 }

 private void OnTriggerEnter(Collider other)
 {
     isEmpty = false;
 }
 private void OnTriggerExit(Collider other)
 {
     isEmpty = true;
 }

}

实际上他们到达了最近的位置,但他们不在乎这个位置是否被占用。 (我还应该尝试使代码对现在没有意义的“firstLine”游戏对象数组正常工作)抱歉英语不好...

----------------编辑---------------- 我改变了选择到达位置的方式,正在编写编队脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Formation : MonoBehaviour
{
public List<GameObject> firstLine = new List<GameObject>();
public List<GameObject> Companions = new List<GameObject>();
// Start is called before the first frame update
void Start()
{
    
}

// Update is called once per frame
void Update()
{
    for (int i = 0; i < Companions.Count; i++)
    {
        //set the position to reach to the first non occupied position
        int a = 0;
        while (!firstLine[a].GetComponent<Position>().isEmpty)
        {
            a++;
        }
        Companions[i].GetComponent<Companion>().objectToReach = firstLine[a];
        Companions[i].GetComponent<Companion>().distanceFromTarget = Vector3.Distance(Companions[i].transform.position, firstLine[a].transform.position);
        firstLine[a].GetComponent<Position>().SetEmptyOrNot(false);

        //set the position to reach to the closest non occupied position
        for (int j = 0; j < firstLine.Count; j++)
        {
            float dist = Vector3.Distance(Companions[i].transform.position, firstLine[j].transform.position);
            if (dist < Companions[i].GetComponent<Companion>().distanceFromTarget && firstLine[j].GetComponent<Position>().isEmpty)
            {
                Companions[i].GetComponent<Companion>().objectToReach.GetComponent<Position>().SetEmptyOrNot(true);
                Companions[i].GetComponent<Companion>().objectToReach = firstLine[j];
                Companions[i].GetComponent<Companion>().distanceFromTarget = dist;

                firstLine[j].GetComponent<Position>().SetEmptyOrNot(false);
                
            }
        }
    }
}

}

并编辑了随播广告脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Companion : MonoBehaviour
{
public GameObject objectToReach;
public float distanceFromTarget;
Transform target;

// Start function not needed

// Update is called once per frame
void Update()
{
    target = objectToReach.transform;
    //reach target
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(target.position - transform.position), 1 * Time.deltaTime);
    transform.position = Vector3.MoveTowards(transform.position, target.position, .01f);
}

}

问题是,现在当一个位置被选中时,他们不再改变目标了...

为了解决这个问题,小伙伴们应该在占用的位置上调用一个函数,而不是使用onTrigger。 替换两个 OnTrigger 函数的位置代码:

public void SetEmptyOrNot(bool empty){
     isEmpty = empty;
}

第一个 if 语句同伴的代码:

lineToGoTo = firstLine[0];//needed for future step
//Position is the scripts name that is to be accessed
lineToGoTo.GetComponent<Postition>().SetEmptyOrNot(false);//In the future try putting the firstLine[0].GetComponent<Postition>() in a variable for increased performance
target = lineToGoTo.transform;
Debug.Log(0);

除了使用 firstLine[1] 之外,对第二个 if 语句执行相同的操作。

下一步就是在同伴不近仓的情况下平仓

为了让同伴在靠近位置时停下来(不需要位置碰撞器):

void LateUpdate(){
    if(Vector3.Distance(transform.position, target)>amountToStay)//amount to stay is to equal what 
    {
         lineToGoTo.GetComponent<Postition>().SetEmptyOrNot(true);
    }
}

继续使用对撞机的代码:

void LateUpdate(){
if(target.collider.bounds.Contains(transform.position))//amount to stay is to equal what 
{
    lineToGoTo.GetComponent<Postition>().SetEmptyOrNot(true);
}
}

Companion 脚本末尾的代码应该是什么样子:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ReachPosition : MonoBehaviour
{
 public GameObject[] firstLine = new GameObject[2];
 public float amountToStay;
 private GameObject lineToGoTo;
 Transform target;
 // Start function not needed

 // Update is called once per frame
 void Update()
 {
     //calculate distance from each position
     float dist = Vector3.Distance(transform.position, firstLine[0].transform.position);
     float dist1 = Vector3.Distance(transform.position, firstLine[1].transform.position);

     if (dist < dist1 && firstLine[0].GetComponent<Position>().isEmpty)
     {
         lineToGoTo = firstLine[0];//needed for future step
         //Position is the scripts name that is to be accessed
         lineToGoTo.GetComponent<Postition>().SetEmptyOrNot(false);//In the future try putting the lineTo.GetComponent<Postition>() in a variable for increased performance
         target = lineToGoTo.transform;
         Debug.Log(0);
     }
     else if (dist > dist1 && firstLine[1].GetComponent<Position>().isEmpty)
     {
         lineToGoTo = firstLine[1];//needed for future step
         //Position is the scripts name that is to be accessed
         lineToGoTo.GetComponent<Postition>().SetEmptyOrNot(false);//In the future try putting the lineTo.GetComponent<Postition>() in a variable for increased performance
         target = lineToGoTo.transform;
         Debug.Log(1);
     }

     //reach target
     transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(target.position - transform.position), 1 * Time.deltaTime);
     transform.position = Vector3.MoveTowards(transform.position, target.position, .01f);
 }
 void LateUpdate(){//use this or the collider option given above
        if(Vector3.Distance(transform.position, lineToGoTo.transform.position)>amountToStay)//amount to stay is to equal what 
        {
            lineToGoTo.GetComponent<Postition>().SetEmptyOrNot(true);
        }
 }
 }

位置脚本:

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class Position : MonoBehaviour
 {
 public bool isEmpty;
 // Start is called before the first frame update
 void Start()
 {
     isEmpty = true;
 }

 public void SetEmptyOrNot(bool empty){
       isEmpty = empty;
 }
}

这应该可以解决问题。第一个启动更新功能的将选择最近的位置。如果两个同伴的最近位置相同,则第一个更新的将是第一个选择它的人。

您可能想要进行的改进:

有两种方法可以改善这一点,具体取决于您打算做什么,以便它们相互合作。

第一种方式是让离位置最近的同伴去拿。

第二种方法是让离最近点更远的同伴占据那个点,这样它就可以赶上