Wednesday, April 7, 2010

Just A Drop In The Bucket (or was it?)

I had a known bug in my new game, "Cloud Cover" which involved detecting a "caught" rain drop when the drop actually hit the side of the beaker instead of in the opening. I knew about the issue, but due to the mechanism I was using to detect collisions (a pre-made function from the PyGame library), the solution wasn't immediately apparent. It would have been difficult and clunky to adjust the iteration on each collision detection to then ensure that the drop that had been detected as a collision was in the acceptable range, being y <= the top of the beaker (y increases towards the bottom of the screen).

So, after some thinking, I came up with the following solution: Instead of checking the y-value of the drop once a collision is detected, only check for collisions against rain drops that are within the acceptable range. It works great, and it's pretty slick if I do say so myself.

First, I store the heights of all beakers in the current level. Currently, each level has at least 1 beaker, no more than 2, the beakers exist for the duration of the level, and they are all of the same height. However, in the future this may change, and beakers may even be destroyed as the level plays on, so I had to ensure that I was able to keep track of the beakers that were currently on the screen: having a static list of the beakers that the level started with wouldn't have been sufficient. Then, I sort the list of beaker heights. This ensures the smallest beaker height will be in the front of the list. This is crucial because I need to use the y-value of the *smallest* beaker as my baseline for accepting collisions because even if I have taller beakers, a y-value of <= the smallest one will also suffice for any beakers taller (remember, y gets larger as it approaches the bottom of the screen). Now that I have the y-value of the shortest beaker, I check against this value when a collision is detected. If the rain drop's y-value is <= this number, I know it is within the area of the opening of the beaker, and I can consider that a collision, and thus a "caught" rain drop.

This also has a nice benefit in that it eliminates a number of otherwise useless and costly collision comparisons. Before, every drop on the screen was being checked for a collision. Now, any drop that is below the shortest beaker is ignored entirely. With enough drops on the screen, this can be a big savings in performance.

The code for this is as follows:

No comments: