Friday, July 15, 2011

Re-Cursing at the Screen

I will get around to making these more frequent. Although there is a lot of stuff to cover each time I load up ye' olde blog machine to write one of these. The hours are getting eaten up by other...well, stuff. Good stuff though. Very positive stuff, but stuff I can't really talk about. Consequently, when I do get to writing these, it's because I have a little extra time that Paper Zeppelin doesn't want right now.
In any case, I got to playing with the Level Editor and building a new level. It's the rolling hills level for the Hard Path. So I got into it and realized that the similarities between it and the other grassy levels that I've built were smaller than I would have liked. I didn't have a specific hook to hang the level on. Granted, I've spoken at length about how I can modify how the encounters themselves play out to give different experiences for the different levels, but conceptually it's easier to start with a little more than the default Windows XP Wallpaper as a guide. So I got to playing and found that I really liked the idea of tall structures with little ledges on them. I could put turrets on these and control the specific encounters inside these areas.
This got me to trying to figure out how I could justify the towers at all (and the associated costs involved). The conceit that I settled on was that the Zeppelin Team were attacking an enemy base. Not just the "base" itself (I guess HQ would be the better term), but an actual military establishment. Then the towers make sense...and all was good.
But you know what else bases have? Bunkers. So then I started laying out some of the bunker areas. I find that if you make a twist in the level about midway through it keeps it interesting and the players a little more engaged. "Ah," they say, "it's the same kind of thing, but now presented differently. I enjoy it in the same way, but differently, like sushi and sashimi." Anyway, other than wanting to double fist hand rolls like I'm the star of a John Woo film about competitive eating, the bunker areas also gave me a reason to hide the bomb and split the pathways.
The thing was though that there really isn't enough real estate on the screen given the sizes of the tiles and sprites to do that terribly well. But I really liked the idea and was convinced that it could work given a little TLC. "If," I reasoned, "I could facilitate movement between these paths somehow, I can open up the spaces a little more. But, I can't do it too well as to make the differences meaningless." Granted, when I'm in my reasoning mode I tend not to talk like an 18th century natural philosopher, but it got me thinking about how to fix that. What I came up with after iterating a couple different ideas in my head was the idea of making ground that I could shoot and destroy. It's an idea that's been rattling around up there almost since the inception (conception?) of Paper Zeppelin but I couldn't rationalize a reason for it. Until a few days ago at least.
However, to make sure that this new ground would fit with the rest of the active elements in the game, it needed to have those sweet Paper Zeppelin physics added somehow. What I came up with was to have the ground fall down after you shoot it. If I'm going to do that, why not just let the pieces stack up on top of each other then? Then, if they stack, they should cascade like everything else.
The thing was actually then having to create that object. Let's take it from the top. Making an object that you can shoot that makes a crasher enemy afterwards is easy, everything already does that and have well mapped functions. Making a different thing when it hit the ground is also easy. Usually the things are smoky wrecks but they don't have to be. Stacking though, that was quite a trick. In effect that specific design wanted me to change the states of the object back and forth. But then, are the objects actually destructible? Think about it for a moment. If it makes a crasher when it's shot, and turns back into ground when it hits the ground, if the object is already lying on the ground, it is invincible. It never quite goes away but flickers in an out like some kind of blackout induced clown nightmare.
Worse was that last clause, the part about making the things cascade. This rule was there to ensure reasonable results. That's the part where something should have a reasonable result based on how the player knows the world works. Granted, the suspension of disbelief goes a long way, but rewarding a player for trying something that should fuggin work in the first place is a good thing too. Anyway, if the cascade effect worked then if you shot at a stalagmite in a Cavern Level, the whole thing should come down as a giant stalagmite shaped chunk.
This cascade property also dicked the phase change thing. If that was in play if you shot the top of a column of destructible ground, the top would hit the second, immediately phase change itself and the next all the way down, dropping the bottom piece off.
What I figured out was that I really wanted 2 different kinds of destructible ground so that I could give them different properties. So I created a kind that falls that I called Gravity Ground, and another that's just good ole Destructible Ground. When Gravity Ground is hit, it makes a crasher and when than crasher hits the ground it turns into the other kind. So you can shoot it down, watch it fall, and then shoot it to pieces once it's living comfortably on the ground.

- Which bring me to the titles. I learned a few very important lessons about XNA this week. The first is that the game does not like it when you destroy things inside their own loops. This caused the biggest headache in the implementation of the new ground objects. If you have a loop and that loop is checking through a list, if you remove the item in the list that the system is looking for, it will crash...if's it's being nice to you. What was happening with all of the crasher enemies, was that they were hitting the ground multiple times. So I would see a little more fire than was expected, but it didn't seem weird at the time.
This is the titles part. It's what I call a Recursive Bug. It's a new magical class of bug that I hate really hard but can easily avoid in the future now that I know what to be aware of. How the Crasher code is set up is that it goes through the list of Crashers one at a time and runs their little robot class methods. It does this with a loop - a sequence of code that is repeated multiple times. Then, for each one of the Crashers it checks to see if they are touching any of the ground by running a Loop inside the Crasher loop. This is called a Nested Loop in programming jargon.
What the multiple blocks of new ground were leading me to find was that, although I had told the Crasher to remove itself if it touched any ground, the system was finishing the loops that I had requested before it does that. It was probably doing that to protect me from myself, since if you try to call up a variable or an object that doesn't exist, the system will crash itself.
Now I'm going to get into a hypothesis here, so bear with me. I think that when XNA is running nested loops it creates a "Virtual" copy of the lists involved. Any changes to the order of the lists (like say, removing an object) happen to the actual list, but the loop is using the copy that XNA has made. This would explain why changes to variables for items on the list (like the placement of enemies) would change, but I would get the weird bug that caused my bricks to multiply like so many moist tribbles.
To dodge this in the future (and the fix that makes it work now) is to pass along a variable to the outside of the loop and use the break command. Break stops the current loop. So if I am on ground piece #52 out of 197, it'll skip the rest if I break out. Then, once the loop is all done with whatever, I make my changes when I am reasonably sure that the data that I'm working with is the real data again.

- Wow, long one today.

...you spin me right round baby right round like a record baby....

No comments: