"Scripting" with C++ coroutines

83 Views Asked by At

I'm trying to implement a simple scripting system for game enemies using coroutines as behavior scripts. As many average C++ coders, I'm having hard time wading through convoluted std::coroutine stuff but I managed to patch up something that works. My scripts now looks like this, where R and A are return and awaiter types pasted from one of coroutine tutorials:

R script(){
    command_moveTo(10, 10);
    co_await A;
    command_idle(3);
    co_await A;
    command_moveTo(20, 20)
    co_await A;
    // etc..    
}

This does the job but I'd like to eliminate the need to constantly write co_await after each command_*() call, so the scripts look tidy like this:

R script(){
    command_moveTo(10, 10);
    command_idle(3);
    command_moveTo(20, 20)
    // etc..    
}

Is there a way to somehow suspend the coroutine from within command_*() functions. The complexity of sdt::coroutine is often justified by saying it facilitates making any kind of coroutine system. Can this rather typical use be implemented?

The only thing I could come up with is using macros for command_*() functions that simply sneak in co_await into coroutine's source code. Is there a better way?

1

There are 1 best solutions below

1
Nicol Bolas On

A coroutine can only suspend itself by using co_await or similar syntax. Nothing outside a coroutine, even a function it calls, can force it to suspend.

If all of these command_ functions are intended to be followed by a co_await call, then you should have them return the awaitable. This means you invoke co_await command_*. And set the functions to be [[nodiscard]], so users can't call them without doing something with the return value.

This also allows the command to have a say in when it is finished and the next command should be executed. You could even make the awaitable something you can chain, so that you can have multiple commands that will be considered finished when all of them are finished.

co_await command_moveTo(10, 10) & command_idle(3);