My seven days are up, and although I can’t say that I succeeded, the challenge was a success. I didn’t walk away with a full game, but damn near close enough. As you read my accounts of the XNA 7 Day Challenge, you’ll notice that although I was able to create and manage the game engine itself in a timely fashion, it was putting it all together that really threw me for a loop. So, enjoy the read, and take as much as you can from it. If you’ve never tested yourself with something such as the 7 Day Challenge, do it. It’ll be exhausting as hell–as it should be–but well worth the efforts.
Day 1 – Setting the Stage
As I brainstormed different ideas regarding what sort of game I was going to make, it was important to note that deadline trumps all. I wanted to make something in 3D; however, I wasn’t about to make a first person shooter in a single week. I wanted to keep things as simple as possible but allow myself room to take it further depending on time. Knowing my own abilities and limitations, I settled into the battle racing genre.
I originally planned on some form of car style racing; however, I quickly switched to ship style racing to ease the need for physics. By default, car racing requires ground detection; this being a 3D game, that would have most likely been a bit more than I could handle. Ships, on the other hand, only require collision detection based on needs. This was much more suitable considering the time restraint, so I decided on ship racing.
I didn’t actually spend a whole lot of time planning. Normally, I would try to get as much as I could on paper before jumping into the code, but this being abnormal circumstances, I decided to play it by ear. Knowing that I would be making a ship battle/racing game, my goals for day one were pretty simple: I needed a ship and an environment.
Creating the assets were very quick and easy; I didn’t need anything special at the moment, just some place holders so I could start messing around with the mechanics. So I opened up Blender, made a very ugly ship, and that was that. The environment was nothing more than a sphere with a cube map; just something that could help me keep an eye on my ship’s orientation.
After that, I began implementing basic movement. I wanted “flight simulation” sort of movement–yaw, pitch, and roll–so I started off by tracking my ship’s orientations: forward, up, and left. The rest was pretty easy. Turns rotated about the ship’s “up” vector; tilts about the “left” vector; and rolls about the “forward” vector. Thrust simply pushed the ship in its forward direction.
After flying around for a bit, I thought I would get a little fancy and add some HUD aspects. Now this part was by far the easiest… it was the one piece that I added from my generic library–actually, it’s the only member of my generic library, but that will someday change. It’s a nice system; you can create windows inside the HUD object, and then add image/text fields to each window. It also incorporates an alignment system: windows are aligned within the HUD and the fields are aligned within its parent window. When you draw the HUD, you can either call its generic Draw() method which draws all windows, or you can pass a string–Draw(string windowName)– which will draw only the given window
I’ll be honest and tell you that using my pre-made HUD system saved altogether about a days worth of time. I can’t remember how long I spent when I first created it, but it’s highly robust, and something that I happily never have to create again. So, with a pretty solid foundation and plenty of wiggle room, I called it day.
Day 2 – Adding Flavor to the Mix
Once I had the basics down, I needed to figure what Thunderstruct was really going to be about. I already knew that I was looking at some form of battle racing, though at this point, I was beginning to think that only one of those types were going to make it in the end. Since I was still unsure which direction I wanted to go, I decided to expand on something that the two were certain to have in common: the environment.
At this point, I still only had a basic sphere mesh and a cube map representing the environment; this could possibly pass as being an arena, but by no means could it represent a track. A track needs some form of direction, which a sphere can’t provide on its own. To help myself brainstorm I little, I quickly added some more spheres. As an arena, this could have proved interesting, allowing players to move between different areas amidst the battle. As a track, it still didn’t provide much; however, I noticed that if I allowed my spheres to be in-line in some way or another, they could essentially provide direction.
Playing with this idea for a bit, I starting asking myself, “how would players transist from one sphere to another?” Sure, I was simply flying around from one to the next, but what could make it interesting? What could make it challenging? And so began the idea of gravity fields–it’s a bit of a misnomer because their technically anti-gravity fields, but life goes on. The general idea was simple: if you’re inside a sphere, gravity doesn’t affect you; otherwise, down you go.
Adding the gravity effect wasn’t too much of a challenge. I added mass to my ship, came up with a general constant for gravity, and then allowed it to be toggled on and off. The overall implementation didn’t take too long; however, I spent quite a bit of time adjusting my mass and gravity constant until it seemed to have that right sort of feel.
After that, I didn’t do a whole lot; I just played around with what I had, jumping from sphere to sphere. Everything seemed to be working alright, and I was happy with what the gravity fields brought to the mix. So, I tightened up some code and called it day.
Day 3 and 4 – Overhaul
By day three, I still wasn’t entirely sure whether I would be focused on battle or racing, but more and more, I found myself leaning towards racing. Once again, due to my indecisiveness, I spent the day expanding on common ground. With the gravity fields in place, my first order of business was creating an actual track (or arena) that would give me a plethora of testing space. My setup from day two was good enough for the basics, but by day three, I had to be able to test things like top speed and control which require a much more defined track. It wasn’t anything fancy or over the top, just a long line of gravity fields set different lengths apart from one another. I did add a little something on one of the ends; a couple of smaller spheres set slightly above the rest, and one last sphere placed even higher. Now I could fly back and forth for long lengths of time as well as climb to different levels.
Once the new track was in place, it was time to really spice things up. For starters, I wanted to be able to boost. The whole reason I added the upper spheres was so I could climb up there and pull as big of a “Dukes of Hazzard” as I could; something much more exciting if your vehicle can boost. Creating the boost was actually a rather simple task. My ships already had max speeds and rates of acceleration, so I figured, why not just increase both during a boost. It worked perfectly.
Creating the visual for the boost was a bit more challenging. I wanted a gradient bar that went from blue to red, but also with a slight curve; something to help keep the HUD looking smooth. The challenge came from me never having done this before; you’d think with the time restraint and all, that I would have made do some box-shaped, uniform-colored, ugly looking sort of thing, but no, I had to be difficult. Since I didn’t have time to research or learn how best to achieve this type of effect, I threw in a hack. First, I created the overall shape and border of the bar using Paint; then, I threw it into Paint.NET and used the gradient tool to fill it in. The secret to my hack (which you will understand in a second) was setting the border to some uniform shade of gray.
The boost bar is passed through an effect file along with a value (0 to 1) representing the amount of boost to show. The pixel shader worked in two steps. First, it determined whether or not it was a border pixel by looking at the distribution of its component values. The smaller the distribution, the closer it is to being a shade of gray (now you get it) and thus being a border pixel. If it’s not a border pixel, the shader determines how far the pixel is from the start point, compares it to the amount of boost to show via percentages, and then returns the appropriate color.
Some Extra Time Well Spent