When Bugs Cause Bugs
Last night was one of those "bang your head repeatedly on the desk" sort of nights coding Hypership Out of Control. I finally did get my issue resolved but not without a lot of frustration and having to stay up far later than I intended.
I was working on adding a feature where when you respawn, you automagically destroy any blocks your ship overlaps with. Previously you would respawn on top of things and while your ship is invincible for a few seconds, it was kind of annoying to have to immediately rush for safety. This should be a pretty easy thing to do, especially considering I already have collision detection written in my game for collisions between blocks and the player's ship. So I wired it up and like whatever the opposite of magic is, it didn't work and thus began a long search for the reason why.
On a respawn, ships in Hypership are placed at specific locations on the screen. At this exact moment, I need to create a bounding rectangle and check if that collides with any blocks / asteroids / mines / cats / etc. Looking at the debugger (because the debugger is your friend), I saw that the rectangle was being created but it oddly was using the on-screen position of the ship (X,Y) instead of the absolute position in the game world. This was very strange, especially given that this used the same CollissionRectangle property that was used in my other collision checks and those checks returned the absolute value.
My first thought was to try and create a new rectangle outside of the CollissionRectangle property. When I did this though, it appeared at the same position. Using the camera position on the level, I adjusted this rectangle so that it (in theory) would appear in the right position. I even added a spritebatch.Draw() call so I could visually verify this. It appeared to be correctly placed. And yet when it did the collision check, no collision occurred.
Scrapping my idea to create a second rectangle, I started to look into why the first rectangle was appearing with the wrong X/Y coordinates. Because the rectangle was generated based on where the ship was, it must be the ship position that is actually wrong. I found that on a respawn, the ship is placed at a specific on-screen location. That has worked correctly for a long time so I dismissed it as being an issue, instead rather assuming there was something in my code somewhere that updated this respawn position to the correct absolute game world position. I would need to call this before getting my collision rectangle.
After thoroughly searching my code for such a feature, I came to the conclusion there was no such feature. But then how did the on screen location end up becoming the correct absolute game world position? After a hard thought session, it dawned on me and a subtle bug that has been in my code for a long while became obvious (as did the reasons why my collision checks didn't work).
I was setting a position relative to the screen on a respawn (it was always something like 200,600). When the camera was at 0,0 this would be the same as the absolute position but incorrect with the camera anywhere else. My movement code also contains constraints that keep the ship within the camera's viewing range. If you try and go too high, too low, too left, or too right, it reins you in. When I was incorrectly placing the ship at a Y coordinate of 600, the subsequent update of the movement code would then see it was out of the camera's range and adjust it to a valid Y coordinate. Thus for the duration of less than one frame, my ship would be at 200,600 before jumping to some value relative to the camera (correct game world position).
Updating my respawn method to use the correct location relative to the camera, my collision detection on a respawn now worked as intended. The lesson to be learned from this? Just because som
This article has been view 1126 times.