0

I'm having troubles with my enemy NavMeshAgent AI, First it searches for GameObjects tagged with "Defenses", then I set the first destination based in how close the defense is by my enemy, when the defense is destroyed, the array value is increased by one and it changes the destination to the next defense.

My problem is, my player can create (Instance) new defenses during the game, when all my defenses are destroyed, my enemy turns crazy, so, i need a way to add those new defenses to my array, below is my enemy script.

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

Thank you for reading! :)

  • If I were you I would implement the event system. When you create a new game object with tag "Defenses" then you raise an event named e.g. `OnNewDefensesCreated.Raise(createdDefenses);`. Then, in `NavMeshEnemy ` class you can implement `AddDefensesGO(GameObject defenses) { destinations.Add(defenses) }`. Thus, you keep your array updated. [Unity3D Event System](https://unity.com/how-to/architect-game-code-scriptable-objects). If you want I can provide some example code for that but you should give a code sample where you instantiate a new defenses game object. – Panda Strong Jun 02 '20 at 13:31

1 Answers1

1

I would rather implement a component on your prefab with a static list like e.g.

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

And then don't even go by tag but simply do

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

Note however that this still won't fix your issues with no available destination. So you probably should stop the execution if the array is empty like

if(NavMeshDestination.existingDestinations.Count == 0)
{
    // Stop the enemyAgent
    return;
}
derHugo
  • 83,094
  • 9
  • 75
  • 115