Coroutines for game logic, in plain C++.

Squid::Tasks is a header-only C++14 library of coroutine-based tasks for games. Each task is a coroutine, not a thread: it runs only when you resume it, usually once a frame, and pauses only where you write co_await. So behavior that plays out over many frames is written as straight-line code, not a state machine.

GDC 2022 The talk C++ Coroutines are NOW! Elliott Mahler on using C++ coroutines in games, from GDC 2022's programming track. Watch the talk

What it looks like

An enemy that waits for the player to come close, chases them while they stay in range, then rests for two seconds. This is the whole behavior, from the README's first example.

Task<> ManageEnemyAI()
{
    TASK_NAME(__FUNCTION__); // Gives the task a name for debugging purposes

    while(true) // This "infinite loop" means this task should run for the enemy's lifetime
    {
        // Wait until player gets within a 100-pixel radius
        co_await WaitUntil([&] {
            return Distance(GetPlayer()->GetPosition(), GetPosition()) < 100.0f;
        });

        // Move toward the player as long as they are within a 100-pixel radius
        while(Distance(GetPlayer()->GetPosition(), GetPosition()) < 100.0f)
        {
            MoveToward(GetPlayer()->GetPosition(), 100.0f, DeltaTime());
            co_await Suspend();
        }

        // Cool-down for 2 seconds before following again
        co_await WaitSeconds(2.0f, GameTime());
    }
}

Suspend()

Waits until the next time the task is resumed, usually one frame.

WaitSeconds()

Waits until a number of seconds have passed in the time stream you give it.

WaitUntil()

Waits until a function you give it returns true.

To run it, give the actor a TaskManager m_taskMgr;, start the task with m_taskMgr.RunManaged(ManageEnemyAI());, call m_taskMgr.Update(); once per frame, and m_taskMgr.KillAllTasks(); when the actor leaves the scene.

What's in it

A handful of headers in include/. Only Task.h is required; take the rest as you need them.

Task.h

Task handles and the standard awaiters.

TaskManager.h

Runs and resumes a collection of tasks.

TokenList.h

Tracks shared state across many tasks.

FunctionGuard.h

A scope guard that calls a function as it leaves scope.

TaskFSM.h

A finite state machine whose states are task factories.

Requirements

Compilers

  • C++14 with coroutines turned on by a compiler flag (MSVC /await:strict), or C++20's <coroutine>.
  • Proven on MSVC in Visual Studio 2019 and later, and in Unreal Engine 4 and 5.

Getting started

Used by

Giant Squid, 2020 Giant Squid, 2025
In Untested, their open-source coroutine testing framework for Unreal

Using Squid::Tasks in your game or tool? Write to support@plumfire.dev and we'll add it.

Credits and license

Squid::Tasks was created by Tim Ambrogi Saxon and Elliott Mahler at Giant Squid Studios, and is now maintained by Plumfire. It's free and open source under the MIT License. Questions? Write to support@plumfire.dev.