Since releasing the first public alpha demo of Voidship I’ve gotten a lot of interesting bug reports.
Sometimes there are bugs which are so unlikely to ever happen that I find it extremely surprising that anyone found them at all. But everything that can happen in a game will happen. Sometimes quite unlikely stuff in the first 10 minutes of gameplay.
A player ran into a game crashing when playing Voidship. What happened was the game crashed to windows from the battlemap when he paused the game. Pausing the action is pretty integral to the gameplay so this was instantly a priority 1 thing to fix for me.
The specific cause I found though was that the player managed to pause the game exactly at the same moment he killed an enemy ship. Two things clash here:
1.When you kill an enemy ships bridge all the modules of it update themselves to also destroy themselves.
2.When you pause the game all objects on screen get “thrown into memory” and replaced by static clones of them. That is how I keep the game mechanics still interactable but freeze everything without complex timing code.
So the player destroyed an enemy ships bridge. Then by pausing the game at the exact same moment managed to start the game pausing code. Throwing everything off screen and replacing it with clones. Due to the awesome timing the game did this before the modules destroyed themselves. So now we have no paused version of the ships bridge (because it got blown up), but we do have paused clones of the modules. The modules orient themselves according to the bridge and since they couldn’t find it the game went haywire resulting in a crash.
This is a pretty unlikely scenario. One which I personally (as far as I know) haven’t ever seen in all my time of testing. Yet a player ran into it just 10 minutes into playing. This is what happens when you let your games loose into the world. This is why your game has to be as failsafe as possible.
A tip on avoiding problems like this in GMS
Basically Game Maker Studio wise the problem in the previous bug was that we were referencing an object in code which didn’t exist anymore. Getting the dreaded “Unable to find any instance for object index FATAL ERROR”.
This is a type of error that keeps popping up in every game I develop in GM:S ever. Since I always have complex interlocked systems and you can’t ever be 100% sure in what order you’ll have to unlink them again when one of the objects referenced gets destroyed. I could fix this by being super super careful and thoughtful about the order I run my scripts in. How I link the objects etc. But I usually have a game to finish and things are tight enough as it is time wise.
So what I do is this: Pretty much absolutely everywhere ever I get even the slightest gut instinct that this object I am referencing in code might not be there when I want it. I put if instance_exists(object_im_referencing) {} around the code I’m running. So we only run it if the object actually exists. I do this preemptively and you can find this function everywhere all over my code. (Looks like I obviously still miss a few spots at times though).
It’s not stupid if it works
Depending on the situation it’s somewhere between a solid robust fix and extremely hacky.
But on the hacky side let’s see what would actually happen in the above scenario with this “hack” fix (which I already implemented). If this unlikely scenario that this bugtester found ever happens again (it will). Then instead of trying to orient the module clones in the paused game according to the ships bridge… we do nothing with them. I create them already in the same place as the object their clone anyway. Heading in the same direction. They might not be in sync positionally as well. Maybe a modules is a frame off in position since we are not updating. But all the player will really see is an enemy ship with an explosion instead of a bridge module. Not much wrong there. I think the player will understand if when they unpause the whole ship blows up.
Since the rest of my code is usually pretty robust it’s almost always fine if these extremely rare cases of objects being referenced just don’t execute their code if the object isn’t there. Some things will be out of place slightly. A pop up will not be created. A bullet will not be given the correct speed etc. Tiny things. Much much better for these unlikely happenstance scenarios to result in a small floating bullet with speed 0, or a ever so slightly misplaced module. Nowhere near as nice if the game just completely crashes.
So basically my tip to you is stick if instance_exists absolutely everywhere!