Several things have moved from my TODO list to my DONE list where Nucleus is concerned, and I’ve learned a few useful things along the way. In keeping with the current trend in this blog, I’m going to share the experiences once again, particularly the issues conquered.
We start with some interesting problems that crop up in trying to deal with tombstoning in XNA in particular, and then move on through a couple of design changes and other bits of progress. Tally ho.
I’ll have Chicken and Black Olive
…on my Tombstone, you see. No? I didn’t think it was that clever, either. Anyway. Tombstoning is the term for what happens when the phone receives a call or brings up a chooser or other built-in UI and your game/app gets suspended. You’re supposed to handle this by saving whatever state you need to and such, so that you can resume the app right where it left off and process anything you might be waiting to come back from the interrupting task.
This is all pretty well documented, especially for Silverlight. For XNA, it’s a little different, in that you overload the Game object’s OnActivate() and OnDeactivate() functions. Which is actually a bit easier. In my case, I save the state of all my active orbs, the ring structure, and the score before I lose focus, since that’s what is needed to put the game back the way it was. This needs to be written out to its own file, because there’s a fair bit of data involved, so I create and write a temporary file into the isolated storage. Then I load it back in to resume. Easy enough.
I also delete the file(if it exists) when I exit normally, to prevent the startup code from resuming the last game(though I may expose a setting to allow user-suspended games, another advantage to my particular choices). I chose to do this by overloading the Game.OnExiting() function, which seemed reasonable.
As it turns out, this is a problem. The exit code gets called when the app gets tombstoned. To make matters worse, the deactivation code also gets called when the app is exited normally. To elevate this to enormous heights of confusion, while debugging, I found that when tombstoning by pressing the Windows button, they are called in the opposite order that they are when you exit the game normally. Confusing? Hell yes.
The good news is, this made it fairly easy to figure out which exit condition I was seeing, and I set up a pair of booleans. Since tombstoning seems to fire Deactivate and then Exit, and Exiting fires Exit and then Deactivate, it worked out. Still… it was so entirely not the flow of execution I was expecting, and it threw me off very badly until I figured it out.
Stupid Mistake Is Stupid
I’m going to embarrass myself publically (for the second time; I already did so on Twitter) and admit to a really dumb mistake. I’m doing this because it’s an easy mistake, and the resulting errors are not immediately obvious.
I forgot to close a file stream after I wrote to it.
Yeah. Wow. Turns out, this doesn’t immediately pitch a fit all over your code, actually. In fact, the only error I was getting from this forgetfulness was a null exception. While reading a line from the file, using a stream object that appeared to have opened fine. After tombstoning and resuming execution. If this seems like the sort of thing you could spend all day trying to figure out, I did spend over an hour on it before I realized what I’d forgotten. About 2 minutes after asking about it on Twitter. Go me.
On a side note, it’s important to know that if you use StreamWriter’s WriteLine() function to write an enumeration out to a file, you actually get a string matching the name of the enum choice. NOT a numeric or whatever you might be expecting. I tripped over this and ended up writing a quick switch() to fix it. There’s probably a better choice, there. But it works and that’s what matters this time. We’re not talking about a performance-critical code section.
On One Hand or the Other
Another change I made was to the button layout on the title screen. Or, to be more accurate, I re-used my previous two layouts and reversed the decision between them. While at it, I added support for an eventual choice of left/right-handedness. The decision reversal was to move the “right-handed” option back to buttons being on the left. I previously wrote:
I realized, while thinking about how I’d use the phone that the buttons weren’t convenient for typical right-handed use, so I moved the text to the left and the buttons right, since it would make them a more natural reach for how I expect the phone to be used.
I’ve since decided that I was incorrect in this decision. Or rather, that the thought was good, but my expected use scenario isn’t the best or even most likely choice. Now, I’ve moved the default right-handed mode to have buttons on the left on the belief that it will be more comfortable to press them with the thumb of the left hand(which is holding the phone). Some users may prefer to use their right hand to do it. But that’s why there’s an option available. I suspect the thumb will feel more natural, especially for the pause button.
That’s right, I said pause button, because Nucleus can now be paused. it works rather nicely, too, and looks great, dimming the game field down and superimposing a pause icon over it. It worked out really nice, though it took me a while to work out how it needed to be done.
It’s not possible in the current release to directly capture the current backbuffer, so instead, I set a boolean flag that tells the main draw loop that we’re getting ready to pause after the next frame. I then, when that flag is set by pressing the pause button, re-direct that one frame of the draw loop to a new render target, copy the render target to the screen, and throw that target over to the pause game state, which draws it at half-intensity as a background image. It works beautifully. I only do this when needed, to save on cycles I don’t need to spend on most frames.
Another change past readers of this series will notice is that the center structure is no longer blue, but a neutral dark grey. This was done for two reasons: one, blue is one of the orb colors, and it made it confusing by keeping the blue orbs from “popping” as much to the eye, and also suggested some sort of specialness to the blue orbs that wasn’t present. It also has made all of the orbs appear more vibrant, as there is no longer a local color perception effect (color appears different based on what colors it is next to—you can see a great example of the effect here).
I also cleaned up some of the code that governs how the orbs “fall” into stable positions. There’s a lot less of the little errors where an orb decides it’s done moving before it should, which happens a few times in the video I posted earlier. there’s still a bit more to do here, but it’s a major improvement so far.