My current task in Heat Signature is to tweak the airlocks so there’s room to put a closed door between you and the rest of the ship when you board. That way, you have as much time as you like to plan out your attack and wait till the guards are where you want them.
I needed the airlocks to clear 4 squares on the ship’s collision grid, to give you room to stand. But I hit a weird bug: some of them, maybe a third, did not clear. I checked the ‘clear grid’ function was executing on each of them, but still some of them ended up blocked.
I could see nothing wrong with the code no matter how hard I looked, so the only way to solve it was to look at a lot of test cases and see if I could spot what the bad ones had in common. As I said in my tutorial episode on debugging, it’s often impossible to see the problem until you get a clue about where to look. So I spawned lots of ships, checked each airlock, and screenshotted each one. And it was only looking back at the screenshots that I spotted what all the bad ones had in common – or rather, what all the good ones did.
I thought it might be fun to just put up all the shots I looked at and see if you can spot it yourself. Not the actual explanation of the bug, of course, that’s tricky without seeing all my source code, but I was just looking for any commonality at all. And in case you think I’m Tom Sawyering you into solving it for me, I have no compunction about just asking for help when I really am stuck. This one was kind of fun to figure out, for a certain definition of fun.
Here are all the bad ones. The grid thing is showing what bits of the ship are solid, and these are ‘bad’ because the part I’m standing in is all red – I’m stuck. None of the debug text is relevant.
And here are all the good ones – the area I’m standing in is green, I’m free to move.
So there’s something all the bad ones have in common and something all the good ones have in common, and it’s evident in these shots. Comment if you spot it!
Update! People have got it! Both here and on Twitter, in fact I think most people who took a stab either got it or got something close enough. Kudos to Pompolic for the first correct solution I saw. I’ll detail what was going on below, but hide it until you click to reveal the solution, for anyone who still wants to try it for themselves.
As many spotted, all the good ones are indented from the outer edge of the ship. It’s not as clear from the bad ones in isolation, but the real problem they share is that they’re all on the very outermost module of the ship. This is a problem because the collision grid only covers the smallest rectangle the ship’s modules fit into, so the protruding part of the airlock is outside the grid entirely. My collision grid visualiser doesn’t seem to have a problem with that, but the ‘clear grid’ function REALLY does. Not only does it not clear the cells that are outside the grid, it also fails to clear the cells that ARE. It doesn’t crash but essentially gives up.
Fixing this is a scarily big job, and it’s something I’ve attempted before. What we need is for the collision grid to leave some room around the ship. But this is awkward because the way the collision grid is generated depends on using the module and objects’ ship-wise co-ordinates to figure out where on the collision grid they lie. If we add extra space to the collision grid, all those references would be wrong by the size of the border. We could add an offset in the collision grid generator, but then we also have to add that same offset EVERYWHERE we EVER reference collision, including for things like line of sight checks. Nightmare.
We could make the collision grid generate correctly automatically if we changed the ship’s module grid to add empty modules all around the ship. But we have to decide whether to mess with the loops that generate the ship: right now they go from row 0 to ModulesLong, and column 0 to ModulesWide. Should we keep that the same but add new module spaces outside of those values? That’s tempting, but now every modules ‘row’ and ‘column’ variable is technically wrong, and won’t relate to its ‘fore’ and ‘starboard’ co-ordinates in ways that I’ve relied on all over the place.
So in the end I did change those loops – they now go from ModuleBorder to (ModulesLong – ModuleBorder), etc. It seems messy at first, and lots of littel variables did need adjusting to account for this, but crucially all of that was in the ship generation scripts. After a few crashes and weird, asymmetrical ships:
My third set of tweaks finally fixed it, and seemingly nothing else needs changing. That’s a huge deal, I think both the other routes to solving this would have had me still fixing little exceptions and unforeseen consequences months down the line.
Thanks for indulging me!