NOTE: This post is two years old, and references some techniques no longer used in my games because they only work on XBOX 360, though most of what's here still applies to my current games as well.
When creating games in a short amount of time, such as I’ve done with the seven games in my “monthly” game series, you need to find places to cut corners. I’ve done that to some extent in every aspect of game creation, and one “cut” that’s helped on the visual side of things is to place restrictions on what I do and follow certain rules in my workflow. That also happens to be a good way to define an art style too, and somehow I’ve stumbled upon a set of restrictions and rules that aren’t used very often in games and I’ve now created a “Radiangames” style.
Before I get into those restrictions and rules, every artist (I use that term loosely in my case) has an inspiration, and for the monthly series, mine has always been abstract computer-generated art. To be more specific, a site called DEPTHCORE has a collection of artists create a bunch of images centered around a theme (look for the Chapters in the upper right). I occasionally browse those to check out what looks cool and what I think I could imitate to some degree in my games. While my games don’t attain the level of beauty seen in those images, this image sums up what I was going for in Inferno, particularly for the enemies:
And here’s a closeup of a screenshot from Inferno:
While the colors and extra details are a bit different, the mass of shiny, translucent orbs turned out about as well as I could have expected. Granted you’ll never see stuff quite like this in the real game because this is zoomed in a bit and slightly post-processed.
For most of my games, I usually don’t have such a direct influence. Instead I try to find a combination of rules, restrictions, and colors (and shaders, more on that later) that look cool and it usually evolves over time until I have something that looks good enough to go with. Yet you can see by this partial Ballistic screenshot that I’m still using some of the same general techniques as in Inferno, albeit with different parameters:
So let’s get to the basic restrictions for all of my games and then I’ll break down how a scene is drawn using Ballistic as an example.
First, I make things simple as possible from a high level. For my games, this means they all use a resolution of 1280×720 and run at 60 frames per second. When my games try to do too much and can’t run at 60 FPS (as they do on occasion in extreme situations or due to other minor issues), they always still process every frame as if running at 60 FPS instead of skipping frames (aka using a longer frametime in code). This kind of slowdown always looks better in my opinion, and it’s something I can do because these are not synced online games. Games running at 60 FPS also look really nice in motion, particularly for games with fast and smooth movement.
Secondly, I only use sprites and full-screen shaders to draw the graphics. I’ll cover those shaders below, but using sprites means not having to deal with vertices or mesh management. I just have to make the textures, copy them into the project in Visual Studio, then add them to my list of textures in-game and use a simple reference when I do sprite drawing.
The other basic things about my sprites: I (almost) always color them in code rather than using a paint program, which means I only have to worry about the alpha channel when I make my sprites. The sprites themselves are just white bitmaps. Coloring them this way lets me change colors more quickly, and I can do lots of nice fading and blending tricks, such as when the colors completely change between waves in JoyJoy.
Because I color them in code though, I have to draw multiple layers of an object when I want two colors, such as the blue outlines around the gray enemies in Ballistic. This actually helps create the “blended” enemy hordes seen in lots of my games.
At this point I think I need to show rather than say, so here’s how enemies are drawn in Ballistic. Everything is rendered normally in these screenshots except enemies (which are drawn 50% bigger). First, draw the bright blue “outlines”:
As you can see, they’re not outlines but actually just a bunch of slightly-scaled solid circles. This enemy type in particular stretches to show how fast it’s going, but the stretching is actually just scaling the sprite. Very simple stuff. Next, draw the black layer:
Now you can see the blue “outlines”. I’m drawing the same enemies again with a slightly smaller “black” circle, aka the same solid white circles colored in code. Next comes the blended light gray layer:
Now they’re starting to look like a living mass of mercury, minus the shininess. Unlike the previous two layers, these circles have a strong gradient in their alpha channel. This has to be a separate layer in order to blend together nicely.
If you tried to put these three layers into the color of the bitmap you wouldn’t have a cool organic mass, but instead a bunch of obviously overlapping sprites that emphasizes (in a bad way) the intentionally soft collision in my games. We haven’t even added the shiny bits yet, which have to be a separate layer anyway, so using separate layers to get a blended look actually feeds into the next part.
The Reflective/Refractive Pixel Shader
To get the shiny “reflections” (and “refractive” distortion seen in Fluid, Inferno, and Fireball), I took one of the XNA pixel shader examples that showed distortion using normal map sprites and modified it a bit. Each game since Inferno (even Crossfire 2) has used its own tweaked version of the shader. Here’s a quick snippet of the shader code that shows Inferno’s version:
What that basically means is: There are three colors added together in varying amounts (based on the alpha of the normal map image, which I’ll show soon). Those three colors are:
The original color (part 2 of color1): The color of the pixel we’re drawing before the shader is applied.
The refractive color (part 1 of color1): The color of a pixel offset a small amount. The distance is based on the red and green values in the normal map image. This ends up looking like a distorted version of the image where the normal map is strong.
The reflective color (color2): The color of a pixel offset a large amount, with no input from the pixel’s actual position, where the range is the entire screen (but again based on the red and green values in the normal map image). This is a more distorted version of the image and ends up looking like a reflection even though the game is completely 2D.
So those three colors are added together in varying amounts, and you get a nice result. One other minor difference from the XNA example is the image used in the refractive and reflective colors is actually the previous frame, not the current one. This made things look a bit smoother because of bloom being applied twice (once on the previous frame, then again before the current one is finished).
The normal maps for this shader drawing phase are generated using xNormal (free), though if you have CrazyBump (not free) that works just as well if not better. Either way, I usually end up blurring the output of those programs in an image editor. Here’s more or less what the normal map (and alpha channel) ends up looking like, with this image actually being from Fluid:
Returning to the Ballistic example, here’s what the normal map image from the scene above would look like. Normally this image isn’t drawn to screen, just to a backbuffer that’s used in shader calculations, but it’s good to know what it looks like (though you can’t see the alpha channel in this image, which is also important to the shader):
Combine that image with the one above using the Ballistic shader (which does not use refraction, unlike Inferno) and you end up with this:
So there you go, at least for enemies in Ballistic. Note that this is a fill-rate intensive way to draw objects, so you have to be sure not to overdo the fill-rate for other portions of the game, and it probably won’t work well on platforms like iPhone where fill-rate is a bigger constraint.
Though particle systems are an important part of my games, the systems are actually very simple. Every game has used the same basic system, which means a small list of different sprite-based particle types (sparks, streaks, rings, gradients and a few others) are used in various ways. These types are easy to change, as the only differences per type are the maximum number alive and the image used.
The code for processing the individual particles is quite short:
Move the particles, adjust their alpha, size, rotation, and speed, and destroy them if they should be destroyed. Every particle system does these things. The key to making them look cool comes in setting up simple algorithms for generating the particles, then layering and tweaking them like crazy to get something that looks good without killing the framerate.
A nice simple use of particles is in making a nice trail behind homing weapons. Every frame, I generate a streak particle at the location of a the homing projectile. The streak particle is oriented in the direction of the projectile, and it fades (alpha) and shrinks in the X axis over time. Then I make sure the projectiles don’t turn too fast and the particle texture fades nicely, and you’ve got nice looking trails like this:
You can see a bit of the trickery starting to fall apart (jaggy edges at the top) because the strong homing shots in Inferno turn really fast, but in motion it’s very hard to notice, and this is the worst case I could find.
A more standard use of particles would be the bombs in Ballistic. There are six different function calls made to create the effect:
1: Light streaks explode with a speed of 5-8 pixels/frame from the center.
2: Heavy streaks explode with a speed of 2-6 pixels/frame from the center.
3: Heavy streaks exploide with a speed of 1-4 pixels/frame 250 pixels from the center (in a ring).
4: Sparks explode with a speed of 0.5-3 pixels/frame from the center.
5: Sparks explode with a speed of 16-17 pixels/frame from the center (with very high friction).
6: Sparks explode with a speed of 0-2 pixels/frame 250 pixels from the center.
All together there are over a thousand particles from this explosion, not counting the ones from enemies that die in the explosion. There are also a bunch of other parameters that get tweaked, such as size, lifetime, and so on. Together you end up with this image, which looks even nicer in motion:
Most explosions in my game aren’t that complex, but the same general concept still applies.
Everything Else: UI, Levels, Bloom, Etc
With UI, I usually have three layers. The first is behind the game elements, the second is on top (after the reflection and refraction shader is applied), and the third is for the pause menu (on top of the second layer, of course). In earlier games I used lots of little reusable objects for UI, but starting with Inferno I used larger custom UI objects per screen with reusable draw calls for things that needed to be consistent. This reduces the amount of things that can be easily animated, but allows for much faster creation and iteration of complex interface screens, partly because of the way my systems are set up more than the general idea being better.
The levels for Inferno and Fluid use the same sort of multi-layered drawing system as enemies, which allows for nice smooth circles in the levels without much effort. It was fairly fast to implement but not the best way to do it since it’s pretty fill-rate intensive and limits the backgrounds to mostly solid colors and outlines.
I’ve used bloom in every game, though I’ve cut back on the strength for Crossfire 2 and Ballistic. For the original Crossfire I used two passes (with different settings) of bloom to create a softer overall effect, but since then I cut back down to one pass since the R&R shader eats up a bit of drawing time. The bloom shader I use is literally the bloom from the XNA samples with tweaked parameters. In games after JoyJoy, I started tweaking the bloom in real-time to create an extra special effect to use, but generally I only use it when the player dies, and in Fireball and Ballistic I switched the death effect to desaturate the screen at the same time. Here’s what Fireball looks like before and after bloom is applied:
Oh, and I don’t normally use sprite sheets (putting all my images into one large texture), even though I should. I’ve used them for a couple things (enemies in JoyJoy and a couple particle types in Fireball), but with the way I draw things I generally don’t switch textures very much so it’s not a major issue.
And that’s about all I can think of in terms of how I do visuals. If you want more details on a specific area, feel free to email me or comment below.