0
\$\begingroup\$

I've gotten used to using coroutines as a way to ensure a things are done sequentially in my code, i.e. instead of calling method a, method b, and method c on back to back lines I will sometimes yield return StartCoroutine(method a()), etc to ensure method a is completely finished before starting method b. (Is it practical or necessary to do this? I could be missing something obvious that would let me ditch using coroutines in this way. Still a relatively new programmer!)

Anyway, back to my main question. Is there a way to use a coroutine that essentially bypasses the use of a yield return null at the end of it? Since the yield return null waits an extra frame before the coroutine is allowed to finish and I use them a lot, I'd like to get around any unneccessary waiting around in my code. Hopefully my question makes sense, let me know if I can provide any clarification!

Edit: I don't have a great code example to provide but let me try to explain a bit better.

for (int i = 0; i < enemies.Count; i++) { yield return StartCoroutine(enemies[i].SetMovePoint()); }

So let's say I have the above code, where I need to make sure each enemy's SetMovePoint coroutine is complete so the next enemy in the for loop can accurately account for where other enemies are moving and avoid moving to the same location. Since the SetMovePoint function involves pathfinding and takes a bit of time to execute I've written it as a coroutine to ensure it finishes before I move on. And since it's a coroutine, it has to return something hence it has a yield return null at the end, which waits an extra frame for each iteration of the loop above which I'd like to avoid.

In a different area of my project where I'm starting work on procedural generation with the cellular automata algorithm, the code looks like this:

    protected virtual void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            DoSimpleAutomata(numberOfRepetitions);
        }

        if(Input.GetMouseButtonDown(1))
        {
            ClearMap(true);
        }
    }
    protected void DoSimpleAutomata(int numRepetitions)
    {
        generationInProgress = true;

        ClearMap(false);

        if(terrainMap == null)
        {
            terrainMap = new int[width, height];
            GenerateNoiseMap();
        }

        for (int i = 0; i < numRepetitions; i++)
        {
            terrainMap = GenerateNewTerrainMap(terrainMap, i + 1);
        }
        SetTiles();

        generationInProgress = false;
    }

    protected void ClearMap(bool eraseCurrentMapData)
    {
        tilemap0.ClearAllTiles();
        tilemap1.ClearAllTiles();
        tilemap2.ClearAllTiles();

        if(eraseCurrentMapData) terrainMap = null;
    }

This probably isn't a very good example of somewhere I'd need to use coroutines, but this is where the short delay from "yield return null"s was more apparent. I changed DoSimpleAutomata(), ClearMap(), GenerateNoiseMap(), and SetTiles to coroutines and did yield return StartCoroutine(someCoroutine()) instead of simply calling the void methods.

Ultimately my goal here was to ensure everything was executing in the right order and the smaller sub methods I was calling weren't trying to run before the previous ones were finished.

Before using coroutines, I could left click multiple times and DoSimpleAutomata would run and I could see the terrain step through another iteration of the Cellular Automata algorithm. When using coroutines with yield return null at the end, each time I left click the terrain will flicker for a frame from the yield return null in ClearMap, then display the result afterward. I thought using yield break instead of yield return null would fix the 1 frame delay and the flicker I was seeing, but nothing changed when I tried this.

\$\endgroup\$
8
  • \$\begingroup\$ Are you looking for yield break;? But then, why use a coroutine at all? Can you edit your question to show an example of the code you're currently using with coroutines, what that code looks like without coroutines, and what specific problem that non-coroutine version has that you're trying to fix? I'm getting the sense there may be a different issue or misunderstanding here, but it's hard to identify without a concrete example. \$\endgroup\$
    – DMGregory
    Nov 30, 2022 at 17:42
  • \$\begingroup\$ I edited my question to give some further information on the problem, let me know if it's still a bit confusing! It's a bit of a case of I don't know what I don't know, so it's a bit difficult to present the question in a clear way. \$\endgroup\$ Nov 30, 2022 at 19:59
  • 2
    \$\begingroup\$ Showing a case where you do not use coroutines does not help clarify how you're trying to use coroutines. It sounds to me like you fundamentally misunderstand how control flow works in C#. When you have three lines of code MethodA(); MethodB(); MethodC();, control flow enters the MethodA() function and runs it to completion before it reaches the MethodB() call. You can verify this by setting a breakpoint and stepping one instruction at a time. If you believe the control flow is doing something different, it's likely you're misinterpreting some symptom - try documenting that root issue. \$\endgroup\$
    – DMGregory
    Nov 30, 2022 at 20:03
  • 3
    \$\begingroup\$ Coroutines are great when you call something that takes some time (moving character from a to b, doing long calculations, recursion or similae) and you don't want to stop the rest of your code afterwards. However, it’s important to remember that coroutines aren’t threads. Synchronous operations that run within a coroutine still execute on the main thread. \$\endgroup\$
    – Zibelas
    Nov 30, 2022 at 20:46
  • 2
    \$\begingroup\$ To me too it seems like you misunderstand coroutines. "Ordinary" code already ensures the order of execution. In the general case coroutines influence the order of execution in relation to code that is not part of that coroutine. But in both cases the order of execution inside the method is sequential. \$\endgroup\$
    – Nikaas
    Dec 2, 2022 at 10:42

0

You must log in to answer this question.

Browse other questions tagged .