【问题标题】:How can I check FindGameObjectsWithTag during runtime?如何在运行时检查 FindGameObjectsWithTag?
【发布时间】:2020-06-02 13:23:18
【问题描述】:

我的敌人 NavMeshAgent AI 遇到问题,首先它搜索标记为“防御”的游戏对象,然后我根据敌人的防御距离设置第一个目的地,当防御被摧毁时,数组值加一,并将目的地更改为下一个防御。

我的问题是,我的玩家可以在游戏中创建(实例)新防御,当我所有的防御都被摧毁时,我的敌人变得疯狂,所以,我需要一种方法来将这些新防御添加到我的阵列中,下面是我的敌人脚本。

 public class NavMeshEnemy : MonoBehaviour
 {
     [Header("References", order = 0)]
     [SerializeField] NavMeshAgent enemyAgent;
     [Space(10)]
     [SerializeField] GameObject[] destinations;
     [Space(10)]
     [SerializeField] float distanceObjects;
     [SerializeField] int arrayElements = 0;

     void Awake()
     {
         enemyAgent = GetComponent<NavMeshAgent>();
         destinations = GameObject.FindGameObjectsWithTag("Defenses");
     }

     void Start()
     {
         destinations = destinations.OrderBy((d) => (d.transform.position - this.transform.position).sqrMagnitude).ToArray();
     }

     void Update()
     {
         distanceObjects = Vector3.Distance(this.transform.position, destinations[arrayElements].transform.position);

         enemyAgent.destination = destinations[arrayElements].transform.position;

         CheckArray();
     }

     void CheckArray()
     {
         if (destinations[arrayElements].gameObject.activeInHierarchy == false)
         {
             if (arrayElements < destinations.Length - 1)
             {
                 arrayElements++;
                 enemyAgent.destination = destinations[arrayElements].transform.position;
             }
             else
             {
                 arrayElements = 0;
             }
         }
     }
 }

感谢您的阅读! :)

【问题讨论】:

  • 如果我是你,我会实现事件系统。当您创建一个带有标签“Defenses”的新游戏对象时,您会引发一个名为例如的事件。 OnNewDefensesCreated.Raise(createdDefenses);。然后,在NavMeshEnemy 类中你可以实现AddDefensesGO(GameObject defenses) { destinations.Add(defenses) }。因此,您可以保持阵列更新。 Unity3D Event System。如果您愿意,我可以为此提供一些示例代码,但您应该提供一个代码示例,您可以在其中实例化一个新的防御游戏对象。
  • @PandaStrong 哦,谢谢,这将非常有用,这是我在 tablet 中用于实例化防御的脚本:

标签: unity3d artificial-intelligence navmesh


【解决方案1】:

我宁愿在你的预制件上使用static 列表来实现一个组件,例如

public class NavMeshDestination : MonoBehaviour
{
    public static HashSet<Transform> existingDestinations = new HashSet<Transform>();

    private void Awake()
    {
       if(!existingDestinations.Contains(this)) existingDestinations.Add(this);
    }

    private void OnDestroy()
    {
        if(existingDestinations.Contains(this)) existingDestinations.Remove(this);
    }
}

然后甚至不按标签,而是简单地做

public class NavMeshEnemy : MonoBehaviour
{
    [Header("References", order = 0)]
    [SerializeField] NavMeshAgent enemyAgent;
    [Space(10)]
    [SerializeField] float distanceObjects;
    [SerializeField] int arrayElements = 0;

    void Awake()
    {
        if(!enemyAgent) enemyAgent = GetComponent<NavMeshAgent>();
    }

    void Update()
    {
        destinations = NavMeshDestination.existingDestinations.OrderBy(d => (d.transform.position - this.transform.position).sqrMagnitude).ToArray();

        distanceObjects = Vector3.Distance(this.transform.position, destinations[arrayElements].transform.position);

        enemyAgent.destination = destinations[arrayElements].transform.position;

        CheckArray();
    }

    void CheckArray()
    {
        if (destinations[arrayElements].gameObject.activeInHierarchy == false)
        { 
            if (arrayElements < destinations.Length - 1)
            {
                arrayElements++;
                enemyAgent.destination = destinos[arrayElements].transform.position;
            }
            else
            {
                arrayElements = 0;
            }
        }
    }
}

但请注意,这仍然无法解决您没有可用目的地的问题。因此,如果数组为空,您可能应该停止执行,例如

if(NavMeshDestination.existingDestinations.Count == 0)
{
    // Stop the enemyAgent
    return;
}

【讨论】:

  • 我稍后会检查这个,这似乎是一个很好的解决方案,特别是因为我是初学者。感谢您的帮助! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2020-06-20
  • 2015-08-13
  • 1970-01-01
  • 2013-04-19
  • 2011-12-04
  • 1970-01-01
相关资源
最近更新 更多