Quirks of Low Level Coding

As seems to be becoming a habit, I just tackled and beat a significant bug (which I’d actually noticed much earlier and had put off fixing until now) so I decided to write about it. The “moral” from this one seems to be that that low level coding will invariably have interesting little quirks and anti-features which will always be lurking in the wings to knock experienced and novice coders alike off their feet. This bug (like the last one) was in the grid cell code. As I have mentioned previously, this project involves a 3D grid map with various things moving in freeform around it but still interacting with the grid for some things.

In my mind map of future progress, the interaction between freeform objects and grid cells will mostly come about through environmental effects like airflow, gravity and toxic gasses. Without going into too much detail on gameplay (that’s for later), I’m still playing around with how best to handle it. My current implementation is a holdover of my old habit of premature optimisation, where each object that needs to check the grid will periodically (or after moving) recheck with the MapSuite to see if their latest position has resulted in a cell change – if it has, inform their old cell that they’re leaving and inform the new cell that they’re entering.

This is to replace a system where the objects simply grab and reapply the environmental settings every update regardless of cell changes or the like. The advantages of the new system is that (obviously) there’s less lookups, but also that there’s a more clear chain of communication for events such as gravity/atmospheric changes to be passed down from a cell to it’s contents. The only appreciable disadvantage that I see with it is that if I don’t account for all circumstances where something could move, it won’t update it’s cell location which will have weird effects with the aforementioned events system. I’ve got the periodical recheck as a failsafe in case the delayed cell changes miss out on something, but that’s still a symptom of the old system where there is a redundant system which may or may not be necessary. Tradeoffs, I guess.

Just quickly while I’m on the subject of the cell map, I thought I’d lay out how it works under the hood. It’s relatively simple, with all the cells being stored in an STL unordered_map and indexed by a hash of the cell’s co-ordinates (which are normalised to integers, but I’m still a little wary about possible floating point error). I’ve also got a plan in the back of my mind to have additional collections of cells where they’re sorted by relevant attributes, eg cells that temporarily need regular environmental updates.

But the bug! What was the bug? Well I mentioned it was a somewhat low level quirk of C++, to be specific in how it handles numbers. As I mentioned above, freeform objects determine their current cells by taking their exact position as a float vector and normalising it to an integer vector with an offset of (0.5, 0.5, 0.5) to account for rounding. For simplicity’s sake, the way I was doing the rounding was just casting the float to an integer. This set of warning bells even before I had written the system the first time, but I decided to try it out and see how it went.

Turns out that when casting from a float to an integer, values above 0 round down but values below 0 round up – which results in a whole extra anomalous tile on each axis when trying to find the current cell that objects are in! The way to fix it is just to add a correction value of -1 when casting from float to integer for values below 0, but I was getting some weird bugs with gravity before I found it almost indirectly while working with the player code.

Here’s to hoping that the bug where rays of artificial gravity being projected from a tile adjacent to where they were supposed to originate from will disappear! Speaking of improbable bugs, maybe my next entry will cover how I found and fixed the null pointer error while assigning bullet quaternions… better not. I might never write an entry here again 😉