Using invokerepeatng in update

I’m working on a version of Conway’s Game of Life in Unity, and I’ve got the code working for checking cells and stepping through the next generation. However, I’m running into problems using update:

    void Update()
    {
        bool spaceKey = Input.GetKey(KeyCode.Space);
        
        if(spaceKey && _start == false)
        {
            _start = true;
        }else if(spaceKey && _start)
        {
            _start = false;
        }

        if (_start)
        {
            InvokeRepeating("GoThroughGenerations", .5f, .5f);
        }
    }

    private void GoThroughGenerations()
    {
        for (int i = 0; i < numCols; i++)
        {
            for (int j = 0; j < numRows; j++)
            {
                CheckNeighbors(i, j);
            }
        }

        NextGeneration();
    }

Once I hit space, it looks fairly well, but there is some jumpiness. Once I hit the space bar again, it runs the function every frame.

My goal is to run through the functions, display the next generation on the grid, then wait a short break before going to the next generation. What’s the best way of doing this, or is InvokeRepeating the best way of doing this?

The jumpiness might be caused by repeatedly calling InvokeRepeating; Input.getKey will return true during every Update() while the space key is down, which will probably happen several times when you press Space. You should try using Input.GetKeyDown instead, which will return true only on the first frame after pressing the key.

@foxjasond You could use a Coroutine that you can start at the beginning or wait in the Update method until something happens first. In Unity’s documentation (docs link) “A coroutine is like a function that has the ability to pause execution and return control to Unity but then to continue where it left off on the following frame”. A coroutine has the ability to WaitForSeconds (X). This allows you to pause for a moment before continuing your operations. Here is an example of what I mean…

void Start () {
    StartCoroutine ("GoThroughGenerations");
}

IEnumerator GoThroughGenerations() {
    for (int i = 0; i < numCols; i++){
        for (int j = 0; j < numRows, j++){
            CheckNeighbors(i, j);
            yield return new WaitForSeconds(2); // Or however long in seconds
        }
    }
}

You could add an if statement to wrap the StartCoroutine in and you could even place it in the update function. Just make sure if you are using in the update function you use it with some sort of loop or bool to ensure only one of your Coroutines runs at a time.

The other thing you could try is within your current InvokeRepeating method do this…

InvokeRepeating(“GoThroughGenerations”, .5f, .5f * Time.deltaTime);

What this does is changes the rate at which invoke is called according to the time that passes between frames. Unity docs (Docs Link) says this “If you add or subtract to a value every frame chances are you should multiply with Time.deltaTime. When you multiply with Time.deltaTime you essentially express: I want to move this object 10 meters per second instead of 10 meters per frame.”

I hope this helps!

Your problem is that you call InvokeRepeating every frame after hitting the space button.
InvokeRepeating just have to be called once to repeatedly Invoke a method.
So when you hit the space button again, there is already tons of InvokeRepeating that’s why you end up with your function being called every frame.

Using GetKeyDown would not be enough because your boolean _start set to true will repeatedly call InvokeRepeating anyway.

You could do :

void Start(){
	_start = false;
}

void Update(){
	if (Input.GetKeyDown (KeyCode.Space)) {
		if(!_start){
			_start = true;
			InvokeRepeating("GoThroughGenerations",.5f,.5f);
		}else{
			_start = false;
			CancelInvoke("GoThroughGenerations");
		}
	}
}

CancelInvoke stop the InvokeRepeating set in the parameters.

I haven’t tested it.

I’m as new as possible but possibly try using Invoke instead of InvokeRepeating or find a way to cancel the repeating before you Invoke it again.