The programming behind Octavia!
When we began discussing Octavia all I could hear
Thirteen saying was, "None of this is going to be easy with Game Maker because it's single-threaded."
The lack of asynchronous/threaded capabilities definitely is hindering to most GM users but that alongside my dismal amounts of confidence in completing a project of this scale has caused me to prepare like never before.
How to bypass our lack of threading
From the beginning I realized having a school full of students that can walk, talk, follow routines, and interact in lots of different ways could cause some
major performance issues. On top of this we needed to generate our world with tons of random variations that would take loads of time to process. Now you see when GM gets caught up processing code in a single frame the window simply stops responding. Dropping a few frames isn't a major issue but the game appearing to have crashed
is an issue.
At first I attempted to write the world generation to work itself out across multiple frames with some code that looked something like this...
How not to do multi-step processing
Code:
// Create Event
step = 0;
// World Generation
switch ( step ) {
case 0:
// Generate rooms
++ step;
break;
case 1:
// Generate corridors
++ step;
break;
}
Now here's why that approach is horrible under-cooked lasagna. Say that
generate rooms takes 15 frames to process on my computer but it takes 350 frames on a some other slower computer. This would make porting to consoles (one day in the future) a massive pain in the butt. The Nintendo Switch might take 2x longer to do CPU-based work than the Xbox One and generally writing code in a
one size fits all style is ill advised.
My second attempt was far better and made a lot more sense. It takes this idea of breaking up code into multiple steps a bit further by providing a framework for deferred processing. I am now able to give the game
tasks to complete. These tasks contain sets of scripts and a desired framerate. The framework handles everything else.
The way this system handles code is also much cleaner and more readable than my previous approach. Here's a sample...
The right way to do multi-step processing
Code:
gml_task_create(
// Task name
"world_generate",
// Target framerate
60,
// Scripts
chunk_ini,
chunk_generate_rooms,
chunk_generate_corridors,
chunk_generate_corridors_cleanup
);
You can
grab it for yourself right here for free.
I hope this post was informative and useful. I'll continue to post more GML tech stuff such as this as we move forward!