【问题标题】:Unity:How to make a gameObject reach the closest free positionUnity:如何使游戏对象到达最近的空闲位置
【发布时间】:2020-08-02 21:21:26
【问题描述】:

我正在尝试为必须跟随玩家并定位在尚未被其他同伴占据的最近位置的同伴制作 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”gameObject 数组正常工作)抱歉英语不好...

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

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);
}

}

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

【问题讨论】:

    标签: c# unity3d triggers artificial-intelligence game-engine


    【解决方案1】:

    为了解决这个问题,同伴应该在使他们被占用的位置上调用一个函数,而不是使用 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);
    

    对第二个 if 语句执行相同的操作,但使用 firstLine[1] 代替。

    下一步是在同伴未靠近仓位时关闭仓位。

    用于使同伴在靠近位置时停止(不需要位置碰撞器):

    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;
     }
    }
    

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

    您可能想做的改进:

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

    第一种方法是让距离该位置最近的同伴去拿它。

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

    【讨论】:

    • 所以要让距离该位置最近的同伴去拿它,我得在位置脚本中计算同伴的距离然后分配?
    • 在游戏管理器中,您必须计算每个同伴的最近位置。如果最近的位置相同,那么我建议最远的位置。这样,最远的同伴就能赶上。
    猜你喜欢
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    相关资源
    最近更新 更多