Spawn prefabs upwards with a fixed gap

I am making a simple ball game that moves left and right when it hits a wall. I want the game to be like an arcade type game where the ball is on a platform and it keeps jumping up. So I’ve written a code to spawn a list of prefabs randomly upwards with a fixed gap. Since this is an endless runner I want the bottom Prefabs to be destroyed and new one to be spawned on top of the previous one. But when a new prefab is being spawned sometimes the gap made on the y axis is off but a decimal point and the more you play the bigger the gap is until the ball can’t make the jump to the next platform. Any Solutions??

public class PlatformSpawner : MonoBehaviour
{
public GameObject[] prefabs;
private GameObject platform;
public float gap = 3f;
public int maxInstances = 20;

private int numInstances = 0;

public ArcadeMovement scoreCountScript;

private float spawnerPosition = 0f;
private float lastSpawnedPosition = 0f;

private GameObject newPrefab;

private void Start()
{
    spawnerPosition = transform.position.y;
}
void Update()
{
    float scoreCounter = scoreCountScript.scoreCount;

    Vector3 currentPosition = transform.position;
    Transform currentRotation = gameObject.transform;
    currentPosition.x = 0f;
    currentRotation.eulerAngles = new Vector3(currentRotation.eulerAngles.x, currentRotation.eulerAngles.y, 0f);
    transform.position = currentPosition;

    if (numInstances < maxInstances)
    {
        if (scoreCounter < 25)
        {
            int index = Random.Range(0, 3);
            currentPosition = transform.position + new Vector3(0f, (numInstances * gap), 0f);
            newPrefab = Instantiate(prefabs[index], currentPosition, Quaternion.identity);
            currentPosition += newPrefab.transform.position;
            numInstances++;
        }

        if (scoreCounter >= 25)
        {
            int index = Random.Range(0, 5);
            currentPosition = transform.position + new Vector3(0f, (numInstances * gap), 0f);
            newPrefab = Instantiate(prefabs[index], currentPosition, Quaternion.identity);
            currentPosition += newPrefab.transform.position;
            numInstances++;
        }

        if (scoreCounter >= 50)
        {
             int index = Random.Range(0, 7);
             currentPosition = transform.position + new Vector3(0f, (numInstances * gap), 0f);
             newPrefab = Instantiate(prefabs[index], currentPosition, Quaternion.identity);
             currentPosition += newPrefab.transform.position;
            numInstances++;
        }                
    }
}

private void OnTriggerEnter2D(Collider2D collision)
{
    if (collision.gameObject.CompareTag("Ground"))
    {
        Destroy(collision.gameObject);
        Debug.Log("Platform Destroyed");
        numInstances--;
    }
}
}

It seems like the issue is caused by cumulative inaccuracies in floating-point arithmetic. To fix this, you can calculate the exact Y position of the new prefab before instantiating it. You can use Mathf.Round to round the Y position to a specific decimal point to ensure the gap remains consistent.

Just editing your code a bit, but something like this:

public class PlatformSpawner : MonoBehaviour
{
    public GameObject[] prefabs;
    private GameObject platform;
    public float gap = 3f;
    public int maxInstances = 20;
    
    private int numInstances = 0;
    
    public ArcadeMovement scoreCountScript;
    
    private float spawnerPosition = 0f;
    private float lastSpawnedPosition = 0f;
    
    private GameObject newPrefab;
    
    private void Start()
    {
        spawnerPosition = transform.position.y;
    }
    void Update()
    {
        float scoreCounter = scoreCountScript.scoreCount;
    
        Vector3 currentPosition = transform.position;
        Transform currentRotation = gameObject.transform;
        currentPosition.x = 0f;
        currentRotation.eulerAngles = new Vector3(currentRotation.eulerAngles.x, currentRotation.eulerAngles.y, 0f);
        transform.position = currentPosition;
    
        if (numInstances < maxInstances)
        {
            int index = 0;
            if (scoreCounter < 25)
            {
                index = Random.Range(0, 3);
            }
            else if (scoreCounter >= 25 && scoreCounter < 50)
            {
                index = Random.Range(0, 5);
            }
            else if (scoreCounter >= 50)
            {
                index = Random.Range(0, 7);
            }
            
            float newYPosition = Mathf.Round((numInstances * gap) * 100f) / 100f; // Round to 2 decimal places
            currentPosition = transform.position + new Vector3(0f, newYPosition, 0f);
            newPrefab = Instantiate(prefabs[index], currentPosition, Quaternion.identity);
            currentPosition += newPrefab.transform.position;
            numInstances++;
        }
    }
    
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            Destroy(collision.gameObject);
            Debug.Log("Platform Destroyed");
            numInstances--;
        }
    }
}

This modification should help maintain a consistent gap between the prefabs as they spawn. Note that I combined the three if statements for spawning prefabs based on the scoreCounter into a single if-else block, making the code cleaner and easier to understand.

Let me know if this helps you, and note that this code is untested, just a few edits to the code you posted.

@SteenPetersen Thanks for cleaning up those if statements. Looks good and glad I don’t have to edit each code again and don’t know how I missed the 2nd and 3rd condition being applied together. I tried using the code you’ve given but still no luck. The first platform spawned on the y axis is 3 then its 5.7 instead of 6 and so on. I then tried using the Roundtoint() but still the same result.