https://gist.github.com/slembcke/ef7ae2 ... e9b2cbb948
For anyone that's not familiar, they are basically really lightweight threads that you explicitly switch between. They are really useful for things like animations or state machines where you want to a function that runs over several frames.
Basically, the game loop code for the block falling game I'm working on was getting a little confusing. A lot of code was spread out over several frames for animation or cost amortization reasons, and it was getting hard to see what the actual flow was. Something gross like this:
Code: Select all
void update(){
if(timer == 0){
// Make blocks fall
} else if(timer < grid_height){
// Blit updated tiles to the screen one row of blocks at a time
} else if(timer < wait_time){
// Apply matching logic, etc
// Possibly reset timer to grid_height to reset the wait, but not trigger logic above.
} else if(){
// ... more of the same
}
++timer;
}
Code: Select all
// ... Somewhere in the game init code.
// Sets the function to use as a coroutine.
coro_start(update_coro);
void update(){
// Resume executing the coroutine from where it last yielded.
coro_resume();
}
void update_coro(){
while(true){
// Make blocks fall.
// Yield jumps back to the main thread as if coro_resume() was returning.
coro_yield();
for(...){
// Blit row of blocks to the screen
coro_yield();
}
timer = 0
while(timer < wait_time){
// Apply matching logic and such.
// Possibly reset timer back to 0.
coro_yield();
}
// ... More events in the loop.
}
}
On my TODO list yet:
- Allow the stack buffer to be placed anywhere in RAM and not hard coded in the .s file.
- Allow switching coroutines (push their state onto their stack buffers).
- Maybe remove the values passed in and out of yield/resume. Not as useful as in Lua without dynamic typing.