Monday, March 1, 2010

Doodle Blast! - Day 2 - Collisions

Stats: 50 code files, 3871 lines of code, 2 textures, 11 sounds

Today, I introduced a simple set of “enemies”. I added a helicopter I copied from the original game sketch and I also added a building that I shamelessly stole from Pop Fizz, the Airplanes world. I introduced the concept of enemy hit points, simple collision detection, and continuous fire. The final game supports continuous fire for only a certain types of guns to make the game play more varied and to prevent players from just holding their fingers at the corners of the screen as they plow forward. However, at this stage, I made every gun (namely the two that I implemented) support continuous fire. This was partly because it was fun to feel the destructive power of the tank and partly to run a preliminary test to see how many objects I could throw on the screen before the frame rate began to suffer. So far, the code faired remarkably well. Even in the craziest of situations, Cocos2D was pulling at a solid 45 fps.

The frequency at which the enemies were spawning was controlled by a constant and it was the first time I started playing with how many enemies are fun to destroy vs. how many enemies are just too overwhelming. I showed the preliminary results to my brother, pointed him to the constant and let him play. His findings were that there was no such thing as too many enemies and he was rooting for the biggest mayhem on the screen he could get. I liked the idea of having a more leisurely play. To accommodate us both as players, I’ve started scheming for an enemy-spawning logic that adapts to the player’s style, lovingly referring to it as Skynet. But I’m getting ahead of myself because Skynet didn’t get to see the light of day until a couple of days later.

The most interesting part in today’s addition was the collision detection elimination. As I mentioned before, Chipmunk has a handy way of filtering out unnecessary collisions, thus decreasing the amount of computation and boosting perf. There are three tiers at which you can filter out collisions
  • Groups
  • Layers
  • Collision handlers
You can read all about these here. But the basic idea behind them is simple. Bodies within the same group do not collide with each other. Bodies that do not share at least one layer (layer being a bit in a bit mask) do not collide with each other. And finally, bodies for which there doesn’t exist a collision handler (defined by a function pointer for a bodyType-bodyType pair) do not collide with each other. Chipmunk creates a default collision handler that is a catch-all handler for all bodies that satisfy the group and layer requirements. This default handler handles all collisions that trickle down to it. In Doodle Blast, I’ve overridden this behavior such that no bodies collided by default unless there was an explicit collision handler defined. Then, I’ve split all objects within the game into groups and layers as follows:
Item Group Layer
Player guns 1 PLAYER
Friendly fire 2 ENEMY
Enemy fire 3 PLAYER
Enemies 4 ENEMY | PLAYER
Bonuses 5 BONUS
I’ve added a collision handler (using the same generic function pointer returning “yes, please, handle this collision”) for the following types of bodies:
Player <-> Enemy
Player <-> Enemy Fire
Enemy <-> Friendly Fire
Et voila! Now I knew about all the collisions I cared about without the overhead of calculating too much of anything else.

There was one more trick. I wanted the guns to stack neatly on top of each other. So, I gave each gun a stacking shape (essentially a rectangle), didn’t assign any group to it (meaning, they all collided with each other), placed them all into their own collision layer (meaning, they all collided with each other but nothing else), and added a generic StackingShape <-> StackingShape collision handler to deal with the guns bumping into each other.

That’s it. These assignments essentially gave me all of the game interactivity for free. Chipmunk was my friend.

I added a couple of more tweaks here and there (scores, bonuses, ...) and, at the end of the day, this was the result so far:

No comments:

Post a Comment