InvokeRepeating not using Random.Range but initially set value instead

Viewed 1250

I've been puzzled by this one for a few hours now:

I have a variable 'spawnInterval' that is used to randomise the interval at which objects spawn on screen when a function is called by way of a method called InvokeRepeating.

In the function 'SpawnRandomBall' the value is randomised and the rest of the code is run to instantiate the ball and randomise its X location on screen.

However, when the spawnInterval value is randomised and InvokeRepeating is called again it doesn't take into account 'spawnInterval's newly assigned value and will only repeat if a value has been set to begin with.

If it's 0 then it won't repeat at all.

If it's any other positive value, it will repeat instantiate at that value/time.

If I try and set the spawnInterval inside InvokeRepeating to end with Random.Range it will generate a new value but only once as it's in the void Start() function.

I've used debug.log() to check to make sure the spawnInterval variable is indeed randomising and it is, but InvokeRepeating is seemingly ignoring that change to the value.

private float spawnLimitXLeft = -22;
private float spawnLimitXRight = 7;
private float spawnPosY = 30;
private float startDelay = 3.0f;

// This value needs an initial value set otherwise it won't repeat in the InvokeRepeating method.
// random.range cannot be used here
float spawnInterval = 0.5f; 


// Start is called before the first frame update
void Start()
{
    // Though spawnInterval's value is changed when the SpawnRandomBall method is called, it doesn't effect InvokeRepeating as it should.
    InvokeRepeating("SpawnRandomBall", startDelay, spawnInterval); 
}


// Spawn random ball at random x position at top of play area
void SpawnRandomBall ()
{
    // Randomise ball interval
    // Gave up and used HINT which gave me this solution. Ultimately didn't work either
    spawnInterval = Random.Range(0.1f, 6.0f);

    // Generate random ball index and random spawn position
    int ballIndex = Random.Range(0, ballPrefabs.Length);
    Vector3 spawnPos = new Vector3(Random.Range(spawnLimitXLeft, spawnLimitXRight), spawnPosY, 0);

    // instantiate ball at random spawn location
    Instantiate(ballPrefabs[ballIndex], spawnPos, ballPrefabs[0].transform.rotation);
}


void Update()
{
    // Displays spawnInterval float variable randomising but not effecting the InvokeRepeating method
    Debug.Log(spawnInterval);
}

}

This is part of a Junior Programmer course pathway on Unity Learning and a lot of learners on there are running into the same problem but have yet to figure this out themselves and the hints they've provided don't solve the issue.

So any help anyone here can provide will ultimately help a lot of other people.

Thank you.

1 Answers

Well, yes, InvokeRepeating takes the parameters only once. Changing your local field value afterwards doesn't change the values you have already passed into the method call at the beginning. float is a value type and is not passed by reference!

Instead just use Invoke recursively like

void Start()
{
    Invoke(nameof(SpawnRandomBall), startDelay); 
}

void SpawnRandomBall ()
{
    spawnInterval = Random.Range(0.1f, 6.0f);

    int ballIndex = Random.Range(0, ballPrefabs.Length);
    var spawnPos = new Vector3(Random.Range(spawnLimitXLeft, spawnLimitXRight), spawnPosY, 0);

    Instantiate(ballPrefabs[ballIndex], spawnPos, ballPrefabs[0].transform.rotation);

    // Trigger the invokation of the next recursive call
    Invoke(nameof(SpawnRandomBall), spawnInterval);
}
Related