Wednesday, June 11, 2008

Day 151: It's Never Easy

Today's subject is a ripoff of a line from the Phantasm series of movies. The movie's been around for as long as I've been alive, so I'm about to spoil the ending.

When the intrepid heroes finally kill the bad guy, they sit back and have a moment to recuperate. They do all their "Sure is better now that the bad guy's dead!" talk, and one of them says "Thank God, it's over"

That's when the bad guy appears behind them, stating "It's Never Over", and the movie ends. All the sequels followed this pattern. This was the first horror movie I saw that that didn't have a "protagonists escape and everything's better" ending (I hadn't yet seen A Nightmare on Elm Street)

So just when I think I've got an easy task ahead of me, I open the editor and the Tall Man appears, looming, intoning "It's Never Easy!" and then throwing killer spheres with knives into my head. Trust me, this is very scary if you've seen the movie. Especially if you saw it at the age of six.

The easy task that actually was easy today was #99, better radar coloration. Since everyone can get ahold of the player's ship, it was trivial to change the color if the current ship was either the target of the player or targeting the player.

I had plenty of time left over after that, though, so I tried my hand at #184, having a 'nearest hostile target' button. Writing it was not hard, and as it turns out the logic was mostly right. The problem came in testing. I'd start up the game, shoot someone until they were angry at me, and hit the button.

The game would freeze.

What this usually means is that it's about to crash and Ruby is about to give me a stacktrace. I don't know if it's Rubygame or my machine or what, but sometimes this takes anywhere from 5 seconds to several minutes to actually happen, and it's eating up 100% of the CPU the entire time. Very inconvenient for debugging, and incredibly inconvenient for detecting infinite loops.

I spent an hour. I thought the error was in the comparison code, as that's one place that it'd be easy to get stuck in a loop. I had print statements everywhere. It was yet another horror of coding, and nothing I did helped.

Until I put a print statement at the very end of the targeting code, that is. This entire time, I'd been assuming it was this new code locking up the game. But it wasn't! Debugging told me that the targeting logic was all working. Furthermore, looking at the output showed me exactly what I was doing wrong. I was doing this:

player_ship.target = chosen if chosen

But 'chosen' in this case is a sprite, not a ship. The player_ship is expecting a model object, not a view! All that work, for a six-byte change:

player_ship.target = chosen.model if chosen

Thus, today's Programming Tip of the Day: Don't try to use your view as your model.

No comments: