Let’s fix those platform bugs. How hard can it be?

Last update I identified a few bugs, notably to do with bad collision detection when falling on to (or, uh, through) the platforms.

First, the “snapping” bug:

Whup! See that?

Catch that? Let’s look at the frames:

Last time I said

Reading through the code I’m not sure why that is, but I expect I’ll figure it out.

And I figured it out pretty much right after posting. It’s all to do with the hit areas.

When doing collision detection – at least in very simple games – one cannot really afford to do it with very great accuracy. I’m using a very basic method and comparing a single x and y coordinates for each 8×8 tile. Usually you will check the outer “bounding box” around the sprite to see if anything hit you on any side (enemies etc), but right now the only collision I need to check is landing, so that’s the lower bound.

The x and y coordinates for sprite placement are at the top left most extreme of the sprite area. Even though Jumpy is not-square, the area it inhabits is still an 8×8 square.

My collision detection has a look to see if the x & y coordinates of jumpy is going to move on top of a tile it should actually land on, and if yes instead snap to the top of the that tile and stop falling. In this bug it’s falling for one tile more than it should. Let’s take a look at that one erroneous frame but with Jumpy’s x & y coordinate marked in red.

I think I see the problem

According to the collision check, Jumpy was still above the ground and so being where it is is perfectly valid. It’s not until the next frame that the x & y spot overlaps the ground tile and our “landing” code kicks in.

Easy fix. Amend the checking code to instead look at the bottom of the sprite box (the y coordinate + 8) and, heck, let’s move the x coordinate to the mid-point (x + 4) while we’re at it so Jumpy doesn’t fall through platforms when only off by 1 pixel to the left.

So, that other bug:

If you’re falling quickly (i.e. big jumps in position) you can go right through a platform. Try jumping from the high platform to the low one 🙂

Any guesses? Let’s map that out with the x & y coordinate (remembering that we hadn’t fixed the previous bug yet) and for visibility invert the tile we were expecting to hit.

(I accidentally put the red dot at the mid-x point in this image, but what we’re interested in is actually the y position so the illustration is still valid)

Yup. We’re falling so quickly that the x & y check point never actually overlaps that 8×8 ground tile. Another straightforward fix: if we’re falling more than 8 pixels at a time then also check the tile above the one we are currently overlapping.

I could do this all day.

All done and good. As mentioned previously, my brain offered the bug-fix solution shortly after the last post was published, and the extra collision detection checks are very straightforward. So why did it take me about 5 hours to actually fix? 😳

C is a pretty low level language. If you don’t know what you’re doing, things can look OK but really not be OK under the hood.

In this case implementing a simple fix inside the collision detection just plain didn’t work. The logic checked out but running the code very much did not. I put in a printf to spit out what was in the variables, and something magical happened. The code worked!

But it was bad magic. Take the printf out again and the code didn’t work. It drove me nuts. I tried putting in a delay (in case of race conditions. Race conditions probably aren’t a thing on a 4.19MHz processor, but who knows), no joy. I tried removing pointers (I read up that printf calls malloc() and something-something pointers), again, nothing.

My learning was this: C is unforgiving. You do something wrong somewhere else and it is functionally fine but as you build on that hidden fault other strange things happen in code where it really shouldn’t.

I already knew this about C, but I hadn’t first-hand experienced it. This really isn’t one of the “ah, well, I knew what you meant, buddy, I’m still going to do what you almost asked.” set of languages. Sure it’s frustrating at times, but likely in the pursuit of become a far more attentive programmer. That’s going to serve me well if I’m going to do anything interesting on such a limited device as the Game Boy.

In the end I got it working by trial-and-error refactoring, but I later discovered that critical “first” hidden mistake I was making. More on that next update.

Time Spent: About 5 minutes determining what to do & how to do it, and 5 hours becoming a better C developer.

Leave a comment

Your email address will not be published.