Search code examples
c#unity-game-engineaugmented-realityvuforia

MoveTowards issue in AR


An object(stationaryPrefab) is instantiated at a specific location in AR. As soon as it happens a limited amount of objects(enemyPrefab) spawn. What i want them to do is - to move towards a "stationaryPrefab" object very slowly.

Here's what i've already done. Instantiating both types of objects. But when it comes to making those game objects move it doesn't really seems to work. This is my first unity project, so please don't be too harsh on me for this messy code:

public class Spawner : MonoBehaviour
{
    public GameObject enemyPrefab;
    public GameObject stationaryPrefab;
    public int maxEnemy = 5;
    private GameObject[] enemies;

    public float timeSpawn = 3f;
    private float timer;

    public float distance = 5;
    public float speed;

    private void Start()
    {
        timer = timeSpawn;
    }

    private void Update()
    {
        timer -= Time.deltaTime;
        if (timer <= 0)
        {
            timer = timeSpawn;
            if (transform.childCount < maxEnemy)
            {
                enemies.Append(Instantiate(enemyPrefab, UnityEngine.Random.insideUnitSphere * distance, Quaternion.identity, transform));
                foreach (GameObject enemyInstance in enemies)
                {
                    enemyInstance.transform.position = Vector3.MoveTowards(enemyInstance.transform.position, stationaryPrefab.transform.position, speed);
                    Console.Write(enemyInstance.name);
                }
            }
        }
        
    }
}

Solution

  • well you only move your objects in the moment you spawn them due to the timer check.

    You most probably want to separate the spawning from the movement:

    private void Update()
    {
        timer -= Time.deltaTime;
        if (timer <= 0)
        {
            timer = timeSpawn;
            // could probably consider to use a while
            if (transform.childCount < maxEnemy)
            {
                enemies.Append(Instantiate(enemyPrefab, UnityEngine.Random.insideUnitSphere * distance, Quaternion.identity, transform));
            }
        }
        
        foreach (GameObject enemyInstance in enemies)
        {
            enemyInstance.transform.position = Vector3.MoveTowards(enemyInstance.transform.position, stationaryPrefab.transform.position, speed * Time.deltaTime);
        }
    }
    

    Note also the

    speed * Time.deltaTime
    

    for a frame-rate independent smooth movement.


    you should also rather use a List instead of an array if you are going to append objects on runtime

    As I suppose the enemies are also destroyed at some point you should also consider to either use

    • object pooling - this means you do not all the time use Instantiate and Destroy but only disable objects (SetActive(false)) and re-use the same instance for the next spawn.

    • or manage the existing instances in the type itself like e.g.

      // Attach to the enemy prefab(s) 
      public class Enemy : MonoBaheviour
      {
          private static readonly HashSet<Enemy> instances = new ();
      
          public static IReadOnlyCollection<Enemy> Instances => instances;
      
          private void Awake()
          {
              instances.Add(this);
          }
      
          private void OnDestroy()
          {
              instances.Remove(this);
          }
      }
      

      This way you can always access all existing instances / check the amount without needing to keep track yourself:

       // could probably consider to use a while
       if (Enemy.Instances.Count < maxEnemy)
       {
           Instantiate(enemyPrefab, UnityEngine.Random.insideUnitSphere * distance, Quaternion.identity, transform);
       }
      
       foreach(var enemyInstance in Enemy.Instances)
       {
            enemyInstance.transform.position = Vector3.MoveTowards(enemyInstance.transform.position, stationaryPrefab.transform.position, speed * Time.deltaTime);
       }