Tank Negotiator was released today on XBLIG. This post will just serve as a quick postmortem about the process.
I made this game several years ago as I was first learning XNA and modern 3d graphics. It was pretty much complete, but it sat “shelved” until I brought it back to life earlier this year with the intent of finally releasing it (proving to myself that I could ship a finished game). I did some work, and put it into an official playtest. But I didn’t really push it, and got no feedback.
I forgot about it again until the beginning of November, when I prepared it for an official peer review. It failed shortly thereafter when I was pointed out that I was forcing signed in controllers to take part in the game during network matches (many thanks to @NVOGames on twitter for the network playtesting).
Originally I planned to just fix that one issue and resubmit as soon as possible (you have to wait at least one week).
To properly fix it though, I had to do a a fair amount of redesign around how the network sessions are implemented. It would really have been nice if Microsoft had provided extensive/official guidelines on how to handle various situations. All you have to go on is any existing AAA or XBLA network titles you may have. They all do things differently, and some of them actually wouldn’t meet XBLIG standards!
I was a beginner
A lot of my network and profile signin/signout code is from when I was just getting up to speed on XNA. As such, it isn’t very well thought out. This definitely made it challenging to make fixes without risking regressions. I haven’t given a great deal of thought as to how to re-factor it, but I know it probably should be done.
As I was finishing up my changes and preparing to submit to peer review again, I noticed that I had some pretty big framerate drops at times. I decided to investigate this, and that turned into about a week of work making performance tweaks (as detailed in a previous blog post). I have improved things a lot, but they’re still not quite where I want them to be.
Visual and polish tweaks
This “forced probation” period also made me take a step back and try to look at the game with new eyes. What areas lacked polish? Were there an easy and non-risky changes I could make that would improve the look? In the end, some of the changes I made were:
- A better loading indicator at the start.
- Revamped the textures for the playing environments. Some of them just looked plain stupid before. I realized that extremely patterned textures didn’t look good on walls, so most of the wall textures have changed to more subtle textures. I also added a very very dark texture set. This entails absolutely no risk of regressions, yet potentially adds a new gameplay variation.
- A new flag model. When I examined the game with “new eyes”, I couldn’t believe how bad my flag model looked! It was completely inconsistent with the rest of the game – very out of place.
- I changed the UI colors a bit, and improved the look of the player selection screen in the lobby.
- The pause screen allowed you to rotate the board and take a look at a “freeze frame” of the gameplay from different angles. But it left the pause menu up, obscuring what you wanted to see. I polished this up a bit, fading out the menu if the user starts to pan around. So this is now an “official feature”. I also put in a small Easter egg here. Can you find it?
- Added support for MSAA and FXAA anti-aliasing methods. Surprisingly these incur almost no performance hit (despite MSAA resulting in predicated tiling).
- Put a QR tag in the credits screen that links to a webpage that provides more detailed info on the gameplay elements.
- Added a new recorded demo match that demonstrates a larger variety of power-ups.
- I put in a link to the demos from the “Tank Negotiator is a multiplayer game only”. Hopefully this will help drive a few more sales instead of driving people away instantly when they realize they can’t play the game alone.
- I made several of the environments not available in trial mode. When you choose an environment or maze that isn’t available in trial mode, instead of blocking it, I pop up a message box asking if you want to buy the game. Hopefully this provides a bit more of a carrot for people to buy the game.
I promised myself I wouldn’t add any new features. I wanted to be done with this game, not give myself more of a testing headache. Plus I didn’t have time to organize more playtesting sessions with friends.
But I couldn’t help myself. I did it very carefully though.
First, I made the choice of gameplay environment matter more. Prior to this, the only thing that was affected was the friction of the floor. One environment had less friction and one had more. But most of the environments were identical in terms of gameplay.
Now each environment is unique. The differences can be subtle, but now there is a reason to choose each one other than just the look. Weapons cooldown, bullet speed, and skill recharge time are a few of the things that are affected. I thought this was an easy low-risk change given the new variety it adds.
I did a similar thing with power-ups. I added two new ones : Turbo (increases speed) and Ice Cube (makes weapons cool down more quickly). But I did it so as to absolute minimize risk. These power-ups don’t add any new game logic, they just add a multiplier to use along with existing numerical game constants.
Generally adding new power-ups was a headache because I had to think about how they work in network play. But these new ones are simply “you have the power up or you don’t”. And there is a re-usable piece of code that manages power-up ownership across the network. So I didn’t need to write a single line of network code to add these.
The low risk of these new features is the only reason I felt comfortable adding them.
Any untested code probably has bugs
Most of the networking stack is testable on your own; but some Xbox Live features – like invites – are not. Realizing this, I decoded to work around it by writing code that simulated invites as much as possible. Basically, it would start a new Live network session from any point in the game. I worked out a few kinks this way, but didn’t find one remaining bug until I actually tried out Invites for real.
During the past few weeks, I spent several days writing automation that runs through a series of tests of the game. These mainly focus on the menus, network sessions and signing players in and out. I have between 20 and 40 tests (depending on how you count them) that probably take an hour total to run. Half of them can be run locally, the other half require 2 PCs and the Xbox.
In the end, I’m not sure the time payoff was worth it. I probably spent more time writing the tests than I would have spent manual testing. On the other hand, the results are probably more reliable; and if I ever need to do another update, these will prove invaluable to help prevent regressions.
Writing the tests does help you consider different scenarios you might not otherwise think about though. And in the end, I found 2 crashing bugs, one XNA bug, 2 pretty serious gameplay bugs, and 2 visual bugs. So overall, it was worth it.
For the actual gameplay, I have stress tests. This is something I wrote a long time ago, not in the past month. But I put them to good use when I finally tested network sessions between 3 devices, and found 2 pretty serious gameplay bugs.
I don’t have any unit tests for Tank Negotiator. I think they probably could come in handy for testing some of the network code though. I found some bugs in the network code only after sometimes more than an hour of the gameplay stress tests. So I suspect there are still some corner cases where things can go wrong.
When I submitted the game for peer review again, the most common piece of feedback was “this really needs a single player option”. That’s a very legitimate piece of feedback, and they’re right. But I don’t want to invest the time to do that now.
I worked on it before, and gave up after about of month of hard-core AI work. Any options I have to provide a single player mode are significant investments.
- I could provide full-fledged AI players that try to simulate human player. That’s what I tried before, but it is very non-trivial. It would require months more work to do a good job at it.
- I could provide a campaign mode where you play through different scenarios that teach you about the game. The AI could then be much dumber and easier to implement, because it wouldn’t have to fully simulate a human player. But then I’m basically making a second game. It would be a big investment to make it as polished as the current experience.
I do offer a single-player experience where you can practice against a dumb computer player. It’s so dumb that it doesn’t move or shoot. Someone commented that maybe it should move around and try to kill you – at least a bit. I considered that – but then I feel like I’m giving the message that this is an alternate legitimate gameplay experience in Tank Negotiator. Except it would suck and not be fun. So that’s why I’ve kept the computer player extremely dumb: so you realize this is not the real gameplay (I’ll display a big yellow “Practise Mode” on the screen).
Known bugs that shipped
Bumping into another unit causes them damage. But it doesn’t work in network play. I don’t recall the exact reason (I haven’t gone back and looked at the code in great detail), but I suspect it’s because I was trying to measure player velocity to determine the bump strength. And player velocity can be so erratic if you’re determining it by the remote player’s position deltas. It’s definitely fixable. At the very least, I should have made it clear that it doesn’t work over the network. Oh well. I’ll fix it if I ever need to release an update.
You can get into a bad state if you try to add a guest profile to a network session prior to the profile of whom this is a guest. I think there is an XNA bug here, but I should have coded up a work-around. It would involve some string parsing of gamertags, but I think it should be doable in a robust manner.