Skip to content

Coroutines⚓︎

Sometimes it's required to perform large, complex calculations in a script which might take a long time to compute.

As we discussed in the basics, the game runs in a single thread. Therefore, performing a costly calculation will cause performance issues. These issues can manifest in either frame drops, or even freeze frames which can annoy players.

To mitigate these issues, we can take full advantage of Coroutines.

Coroutines

A coroutine is a function that allows the execution to be suspended and then continues from where ever it is left.

Defining a Coroutine⚓︎

A coroutine is just a normal function with its own flow of control like a thread. Only one coroutine ever runs at a time, and it runs continuously until another coroutine is activated, or a coroutine.yield(); is called.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
do
    local script = LUA.script;

    local x = 0;

    -- declare the coroutine function
    local function coroutineFunction()
        while x < 100000 do
            x = x + 1;
            coroutine.yield();
        end
    end

    -- start function
    function script.Start()
        -- start the coroutine
        script.StartCoroutine(coroutineFunction);  
        Debug.Log(x); -- will print 1, because the corotuineFunction executed up until yield
    end
end

Here, at the line number 7, we declare a function which increments the variable x inside of a while loop function. However, after each increment, we call the coroutine.yield(); method. This method suspends the execution of this function and lets the thread move on. On the next frame, the thread picks up the execution from the place it left and continues to execute the code until it reaches another yield call.

By using coroutine, we let the thread execute our time-consuming function piece by piece for increased performance.

Note

The coroutines run in the same thread as the rest of the code, right after the update function.

Warning

If your coroutine function doesn't have a yield call, it is not a coroutine, it's just a normal function. There is no point in running a normal function as a coroutine.

Handling Coroutines⚓︎

Calling the Start Coroutine returns a handle (reference) to the Coroutine. You can use that coroutine to check out its state, or cancel it.

do
    local script = LUA.script;

    local x = 0;

    -- declare the coroutine function
    local function coroutineFunction()
        while x < 100000 do
            x = x + 1;
            coroutine.yield();
        end
    end

    -- start function
    function script.Start()
        -- start the coroutine
        var myCoroutine = script.StartCoroutine(coroutineFunction);  
        script.StopCoroutine(myCoroutine);
    end
end

You can also use the script.StopAllCoroutines() to stop all coroutines started with that script.