By Mubariz Hajimuradov


2019-01-12 09:21:08 8 Comments

I'm trying to create a simple balloon which will enlarge as the user touches and holds the screen.

So I wrote something like this:

while ( Input.GetMouseButtonDown(0) ) {
        transform.localScale += new Vector3(1, 1, 1);
        yield return new WaitForSeconds(1);
}

It causes a compiler an error:

The body of 'enlargeBalloon.Update()' cannot be an iterator block because 'void' is not an iterator interface type

How can I fix this?

1 comments

@DMGregory 2019-01-12 11:15:39

It looks like you're trying to use Update as a Coroutine - a procedure that can suspend itself midway-through and pass control back to the game loop to keep updating/rendering frames, then resume where it left off later.

You can tell something is a Coroutine if it uses the yield return construct to pause itself like this anywhere.

To make a method a coroutine, you need to change its signature from:

void MethodName() {
    ...

to:

IEnumerator MethodName() {
    ...

The reason is that under the hood, running a Coroutine is actually creating an object called an iterator that implements the IEnumerator interface — something we can call MoveNext() on to make it step through a sequence of values/actions. That's how the engine pumps the coroutine each time it needs to be resumed. Instead of returning nothing (void), calling the method returns this new iterator object, so the return type needs to match this.


Now, there's a bit of a danger in calling Update as a coroutine: Update is already called every frame!

So if some of those calls don't end in the same frame, but continue/suspend for some time, they could pile up very quickly. In this example, if the player rapidly tapped their mouse button for a second at 60fps, you could have increased your size 30 times over and have 30 copies of the coroutine waiting to resume.

Fortunately, the engine knows what a disaster this would be, and won't let us do it. Many MonoBehaviour messages are allowed to be marked as IEnumerator and called as coroutines, but Update is not one of them.

MonoBehaviour messages that can't be Coroutines include:

  • Initialization: Awake, OnEnable
  • Core update loop: Update, LateUpdate, FixedUpdate, OnGUI
  • Shutdown: OnDisable, OnDestroy (Obviously, after calling one of these, the object is likely not eligible to keep running a Coroutine the next frame)

So, what can we do instead?

Well, since Update is already running every frame, we don't need a while loop to keep iterating. We can do that with the game loop itself, changing our while to a simple if:

public float inflationSpeed = 1f;

void Update() {
    if (Input.GetMouseButton(0)) {
        Vector3 newScale = transform.localScale;
        // Use deltaTime to grow smoothly, a little each frame.
        newScale += inflationSpeed * Time.deltaTime * Vector3.one;
        transform.localScale = newScale;
    }
}

Or, if you really want to do it in Coroutine style, growing in steps of 1 every second rather than smoothly every frame, you can do it like so:

public Vector3 growthPerStap = new Vector3(1,1,1);
public float stepDuration = 1f;

Coroutine inflation;

// Define a Coroutine method that inflates periodically.
IEnumerator Inflate() {
    while(true) {
        transform.localScale += growthPerStep;
        yield return new WaitForSeconds(stepDuration);
    }
}

// Check input each frame and stop/start the coroutine as needed.
void Update() {
    // Stop the coroutine if it's running and the mouse button is released.
    if(inflation != null && Input.GetMouseButtonUp(0)) {
        StopCoroutine(inflation);
        inflation = null;
    }

    // Start the coroutine if it's not running and the mouse button is pressed.
    if(inflation == null && Input.GetMouseButton(0))
        inflation = StartCoroutine(inflation);
}

@Mubariz Hajimuradov 2019-01-12 11:58:21

Thank you very much for your detailed Answer, Douglas. My background is Web Developer, looks like the concepts are much different here.But I'm very excited to learn more Unity stuff)) Thanks again.

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] How to completely stop the camera from clipping into the ground

2 Answered Questions

2 Answered Questions

2 Answered Questions

[SOLVED] Cannot implicitly convert type 'T' to 'UnityEngine.Vector3'

  • 2017-08-30 14:50:24
  • Adocad
  • 1014 View
  • 0 Score
  • 2 Answer
  • Tags:   unity c#

1 Answered Questions

[SOLVED] Unity2D: Creating a Cross-Platform Multi-Player Game in Unity Error!

  • 2016-11-05 18:48:38
  • Bakausagi-chan
  • 80 View
  • 0 Score
  • 1 Answer
  • Tags:   unity

1 Answered Questions

[SOLVED] Monogame - custom json content importer

2 Answered Questions

[SOLVED] Pause a Coroutine while it's waiting for seconds

  • 2016-07-28 03:24:18
  • Milen
  • 1997 View
  • 0 Score
  • 2 Answer
  • Tags:   unity coroutines

1 Answered Questions

[SOLVED] Fade to first level, on click

  • 2016-04-25 20:47:20
  • Hulio VanQuest
  • 484 View
  • 1 Score
  • 1 Answer
  • Tags:   c# unity monogame

3 Answered Questions

1 Answered Questions

Sponsored Content