Block not always spawning on time.

Hello,

I have a spawn script for a “Tetris” style game.
The idea is for blocks to spawn faster as more time from the start of the game goes by but not faster then a set time, reaching around every 2 seconds before the next block drops.

The problem is that every now and then when I start a new game the “spawn script” will drop the first block then randomly drop another block shortly after (This occurs like 1 out of 7 games). I was wondering if anyone could see why a block will randomly drop shortly after the first block that spawns.

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

public class SpawnBlocks : MonoBehaviour
{
    public GameObject[] Blocks;

    private float nextDrop = 0f; //The time for the next block to spawn
    private float dropInterval = 10f; //The interval between spawned blocks
    private float changeInterval = 25f;

    void Update()
    {
        if (Time.time >= nextDrop) //If ready to spawn
        {
            SpawnBlock();
            nextDrop += dropInterval; //Set next spawn time
            if (Time.time >= changeInterval) //If ready to change spawn interval
            {
                if (dropInterval > 4f) //Change spawn interval to 3/4ths what it was
                    dropInterval *= 0.75f;
                else //Make sure drop Interval stays above the set time.
                    dropInterval = 4f;
            }
        }
    }

    public void SpawnBlock()
    {   
          Instantiate(Blocks[Random.Range(0, Blocks.Length)], transform.position, Quaternion.identity);
    }     

    public void RestartSpawnTimer()
    {
        Instantiate(Blocks[Random.Range(0, Blocks.Length)], transform.position, Quaternion.identity);

        dropInterval = 10f;
        changeInterval = 25f;
   }
}

It’s not a great idea to use Time.time like that. I think the main issue is that there’s basically an unknown amount of time between the scene starting to load and your first Update call happening. The first update call is not guaranteed to happen at Time.time == 0.So it could be that even after adding your drop interval to nextDrop, nextDrop is coming very soon or has already passed.

The documentation for Time.time also warns against using it every frame: Unity - Scripting API: Time.time

Time.deltaTime is a more precise value you can use.
Here’s a better way to keep track of time between spawns:

float timeUntilNextDrop;
float timeUntilNextChange;

void Start() {
  timeUntilNextDrop = dropInterval;
  timeUntilNextChange = changeInterval;
}

void Update() {
  timeUntilNextDrop -= Time.deltaTime;
  timeUntilNextChange -= Time.deltaTime;

  if (timeUntilNextDrop <= 0f) {
    SpawnBlock();
    /* Adding our existing value here so we collect any leftover time. For example if timeUntilNextDrop is -.1, and dropInterval is 4, we want to spawn the next block after 3.9 seconds not the whole 4 seconds. */
    timeUntilNextDrop = dropInterval + timeUntilNextDrop;
  }

  if (timeUntilNextChange <= 0f) {
    // Change spawn interval to 3/4ths what it was
    dropInterval = Mathf.Max(4f, dropInterval * .75f);
    timeUntilNextChange = changeInterval + timeUntilNextChange;
  }
}
2 Likes

Thank you.

That worked like a charm. I thought it was something to do with “Time.time”.

1 Like