Help with Spawn Manager

Goodmorning,

I am having issues creating a spawn system that relies on the distance of the last object spawned from the spawnpoint. I do not want to use a timer to determine when the next object is spawned but will revert to this if needed.

Spawner

The system currently in place works as follows.

1.) The spawner spawns and object.

2.) Once the object is spawn, it is then cached temporarily to track its distance from the spawner.

3.) Once the cached object has reached a distance of say 1 meter from the spawnpoint, the cached object is set to null and the spawner spawns another object. And the cycle repeats.

4.) After a target score is reached the system will rest for 3 seconds and the next wave of objects are spawned but with a slight increase in speed.

The Object

Each object currently has a script on it called GameCube which simply transforms the spawned object downward based on a set speed variable (1). On tap the object is destroyed and a point is awarded.

So far the system works as intended but there are 2 issues.

1.) Each object should maintain the same distance between each other regardless of the speed. But each time the speed is increased the gap between the spawned objects gets larger.

2.) If the object is tapped and destroyed before it reaches the required distance from the spawner, there is then no way to determine when to spawn the next object.

(This has been remedied by spawning the objects off screen, therefore when the player sees the objects they are already pass the required distance)

Here is a copy of the spawn code:

public Transform objectToSpawn;
    public bool canSpawn;
    public float DistanceFromSpawnPoint;
    public float MaximumDistanceLimit = 1f;
    public Transform lastObjectSpawned;

    // Use this for initialization
    void Start ()
    {
        canSpawn = true;
    }
   
    // Update is called once per frame
    void FixedUpdate ()
    {
        Spawn();
    }

    public void Spawn()
    {
        if (canSpawn && DistanceFromSpawnPoint == 0)
        {
            var SpawnedObject = Instantiate(objectToSpawn, transform.position, Quaternion.identity);

            lastObjectSpawned = SpawnedObject;
       
            canSpawn = false;
        }

        if (lastObjectSpawned != null)
        {
            if (!canSpawn && DistanceFromSpawnPoint < MaximumDistanceLimit)
            {
                DistanceFromSpawnPoint = Vector2.Distance(this.transform.position, lastObjectSpawned.transform.position);

            }
            else if (!canSpawn && DistanceFromSpawnPoint > MaximumDistanceLimit)
            {
                lastObjectSpawned = null;
                DistanceFromSpawnPoint = 0;
                canSpawn = true;
            }
        }
        else
        {
            canSpawn = true;
        }

    }

Object:

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

public class GameCube : MonoBehaviour
{
    [SerializeField]
    public static float speed = -15.0f;

    // Update is called once per frame
    void Update()
    {
        transform.position += transform.up * speed * Time.deltaTime;

        if (transform.position.y < -5.5f)
        {
            Destroy(this.gameObject);
        }
    }

    public void OnMouseDown()
    {
    
        if(this.transform.gameObject.tag == "White Cube")
        {
            Destroy(this.gameObject);
        }
    }

    public void ScoreEvent(int _score)
    {
        _score++;
    }
}

Rather than relying on the spawned object to store your information, store the required information as separate values (like Vector3 position). That way, regardless of if the last object was destroyed or not, you know where the next spawn point is.

As for the timing and distance issue, you could spawn all the objects together but only activate them whenever it’s appropriate for your game.

So do you believe that the instantiation method is what is causing the gaps? So I should pool the objects?

The way your code is written, yes the faster objects move the larger the gap.

You’re moving objects in update, but checking for spawning in fixedupdate, which are called at different rates. With a fairly simple game on non-terrible hardware, you will often get multiple calls to update between calls to fixedupdate. That means an object can already have moved far enough to justify spawning a new one, but update gets called again before fixedupdate, which again moves the object even further. When objects are moving faster, this issue becomes more noticeable.

Also, in Spawn when an object is far enough to result in a new spawn, you aren’t spawning it. You’re just setting variables so that on the next fixedupdate (after the object moves even further away on subsequent update calls) you spawn the next one. The faster objects are moving, the more distance they will travel between when you determined a new object can be spawned and when you actually spawn it.

Both of the above issues individually will result in a larger gap between objects the faster you have them move. If you want to maintain a more uniform spacing, call spawn in update, and if you determine that the last object is far enough away that a new one should be spawned then spawn it immediately instead of setting it up for the next call to spawn.

As for objects getting trapped, I’d either add code to detect that an object has become trapped (maybe track distance the object has moved over a period of time, and if it has hardly moved you assume it is trapped and destroy it), or add an additional spawn timer.

Thanks. I will try this out when I get home.

OK, I have tried a hundred things. I tried Mathf.Abs, I tried Decimals, doubles, I tried Vector3.Distance, I tried SQR Magnitude I tried to round the numbers to an int.

I understand that floats are not all that accurate and when speed is introduced, things get a little more difficult to track. I have been stuck on this problem for almost 2 weeks and I asked on here once and got some good advice above. This led me to tinker with how I was tracking the position among other things.

My latest version is working sorta. I hae a speed value that starts at 1 and caps at 15. The spawning works for the most part up to 10 (about 90%). The gaps are not that noticeable. But 10 and above the gap is not as bad as before but it creates a decent size gap that throws off the entire gameplay.

Anyone see something that I am not seeing? I simply want to spawn and object and track that objects distance from the spawn origin, then spawn another object once that object reaches say 3 meters from the spawn point. The newly spawned object then becomes the tracked object and the cycle continues.

After each wave the speed increases by 1 up to 15.

Is there a way to move an object down by a set/even amount while still using speed?

using System.Collections;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System;

public class SpawnSystem : MonoBehaviour
{
    [Header("Spawn Status")]
    public bool canSpawn = true;
    public bool expandPool = false;
    [Header("Pooled Object")]
    public List<GameObject> ObjectsToPool;
    [SerializeField]
    private int poolSize = 20;
    [SerializeField]
    private List<GameObject> ObjectPool;
    [Header("Spawn Points")]
    public List<Transform> SpawnPoints;
    [Header("Spawn Timing Details")]
    public float DistanceFromSpawnPoint;
    public float MaximumDistanceLimit = 1f;

    public GameObject lastObjectSpawned;
    public static Action spawnInstance;

    public float returnedMagnitude;

    #region

    public void PoolObjects()
    {
        ObjectPool = new List<GameObject>();

        for (int i = 0; i < poolSize; i++)
        {
            //creates pooled objects
            for (int j = 0; j < ObjectsToPool.Count; j++)
            {
                GameObject clone = (GameObject)Instantiate(ObjectsToPool[j]);
                clone.SetActive(false);

                ObjectPool.Add(clone);
            }
        }
    }

    #endregion

    // Use this for initialization
    void Start()
    {
        spawnInstance = Spawn;
        PoolObjects();
        //Invoke("Spawn", 3.0f);
       
    }

    private void Update()
    {
        Spawn();
    }

    private void FixedUpdate()
    {
        if (lastObjectSpawned != null)
        {
           
            returnedMagnitude = GetSqrDistXZ(SpawnPoints[0].transform.position, lastObjectSpawned.transform.position);
        }

        SpawnCycle();

    }

    //Get the Object from Pool
    public GameObject GetPooledObject()
    {
        for (int i = 0; i < ObjectPool.Count; i++)
        {
            if (!ObjectPool[i].activeInHierarchy)
            {
                return ObjectPool[i];
            }
        }
        return null;
    }

    //Activate the Retrieved Object
    public void Spawn()
    {
        //Check if I can Spawn
        if (canSpawn)
        {  
                //cache the Retrieved Obj
                GameObject obj = GetPooledObject();
               
                //if no object has been retrieved the try again
                if (obj == null)
                    return;

                //if an object has been found then Enable it for play and set its coordinates
                obj.SetActive(true);             
                obj.transform.position = SpawnPoints[0].transform.position;
                obj.transform.rotation = SpawnPoints[0].transform.rotation;
               
                //track the position of the last object spawned
                lastObjectSpawned = obj;             
               
                //turn off spawner
                canSpawn = false;        
        }
    }
   
    //Calculate Distance from spawner using Custom Sqr Magniture instead of Vector Distance (faster??)
    public static float GetSqrDistXZ(Vector2 a, Vector2 b)
    {
        Vector2 vector = new Vector2(0, a.y - b.y);
        return vector.sqrMagnitude;
    }

    //
    public void SpawnCycle()
    {
            /*if (Mathf.Abs(returnedMagnitude - MaximumDistanceLimit) <= 1.0f)
            {
                canSpawn = true;
                //spawnInstance();
                Debug.Log(returnedMagnitude);
            }*/

            if (returnedMagnitude >= MaximumDistanceLimit)
            {
                Debug.Log(returnedMagnitude);
                //turn spawner back on
                canSpawn = true;
            }
       
    }

}

Should I track the object that is spawned and the next object spawned and then adjust the position of the next object to the already spawned object with an offset

Anyone

Okay I have even tried to use raycast. I am completely lost at this point.

Is the anymore informwation I can include to try and get some help? It has been quite some time.

Setting a numerator/update method on the spawned object - that checks the distance between it’s spawn point and current position then calling a function on spawnerScript whenever it has travelled far enough?

To illustrate:
spawned object script…

private vector3 spawnpos;

void Start() {
    spawnpos = transform.position;
}

void Update() {
    if(Vector3.Distance(spawnpos, transform.position) >= 3) {
        FindGameObjectWithTag("spawner").GetComponent<SpawnerScript>().CanSpawn(true);
    }
}

spawner script…

public void CanSpawn(bool b) {
    canSpawn = b;
}

I hope I am understanding the problem you’re having…