Squishy Diary, Volume 5
Posted by Alex Jordan on
See that image above? I'm still not telling you the real title of my game until I'm good and ready. Buuuuuuuut... see that video below? I did some work, yay!
That took a few weeks longer than I expected, as I waddled away from my rigid design timeline to experiment with my art skills, or lack thereof. Y'see, I made this pretty (ish) mountain that I wanted to show off, but I needed a neat lighting system to really show it off, so, I, uh... just gave you an example of how feature creep works.
But hey. My dev diaries of late haven't been too process-oriented, so let's take a time machine back to late 2009 when I'd ramble incessantly about normal maps and whatnot so I can... ramble about normal maps and whatnot. Come venture with me!
Well. Just because I'm making a 2D game, doesn't mean it can't be pretty. That's one reason for my emphasis on hand-drawn art. However, static art will only get you so far. The beauty of XNA - and one of the few things that doesn't invite my ire - is that you can draw 2D art with all of the panache and special effects that you can use to draw 3D art. Remember how I spent my first couple of Around The World development diaries toiling in High Level Shader Language, trying to learn how to draw models and effects properly? That required both a vertex shader (for putting the 3D model at the correct screen coordinates) and a pixel shader (to sketch/shade the model with the kind of lighting and other effects I was going for). The cool thing about using shaders on 2D art is that you don't need the vertex xhader, cuz you're not playing with 3D models. All you need is a pixel shader to get the desired effects.
Anyway, to give you an example of a 2D game that creates a lot of dazzling 2D effects, check out the Radiangames Inferno launch trailer:
Lots of intense flickering, lots of glowing and over-exposure effects. The end result is luminous, a successful combination of minimalist 2D art and expressive shader effects.
That's what I'm going for with Project Squish (the effects usage, not those exact aesthetics).
So far, there are two shader effects visible on the Project Squish gameplay screen. The first is when you move your target over a physical object, like a critter. The object in question will glow with a blue outline to signify that, yes, this is what you'll be grabbing and flicking. The other effect is the aforementioned lighting system, which was a two week boondoggle that fortunately came out alright in the end.
I've long since wanted a robust lighting system to go with the varied backgrounds that the final game will showcase. Right now, the purple mountain and pink sunset give the static world blocks a pinkish hue coming in from the top right of the screen. But, you ask, how can 2D objects be lit like 3D objects?
It turned out to be really, really complicated. I knew that I wanted the lighting on solid surfaces to be consistent, so I couldn't have each block light itself. Otherwise, you would've seen the light be picked up by the side of every block, even if it was flush against the side of another block. So, the first step was to have the game take a snapshot of a blank screen with only the world blocks drawn on it, to give it a picture of where all the solid objects go. (This happens too fast for the player to see.)
Then, that composite image is given a Gaussian blur. Blurring the solid objects means that I can soften the light when the time comes. Also, getting the Gaussian blur to work took fucking forever, because the math is a bit beyond me. Thank you, Google.
Then, the blurred image is run through a normal map filter. You might remember normal maps from all my talk about ATW... normal maps are 2D images that store surface angle direction encoded in the image's RGB values. Running a normal map effect on the blurred image converts it into instructions on what direction each block's surface points. Furthermore, the previous blurring effect means that those angular surface instructions will be nice and rounded, with minimal hard edges, which will lead to a much softer lighting effect.
Usually, normal maps are computed once in Photoshop with nVidia's special filter and are stored as static image instructions. However, since levels are made dynamically in Project Squish with a Level Editor, it's not like the end user can crack open a copy of Photoshop on their Xbox 360 and make their own normal map. It needs to be automatically handled for the end user, which means that I needed to write a shader that does it on the fly (also invisible to the user). I eventually figured it out, but only after several bouts of angry crying and ice cream-eating.
To recap: first, the game captures only the solid objects and nothing else to figure out what the contiguous surfaces are. Then, it blurs that image. Then, it takes that blurred image and converts it into a normal map, and the previous blurring allows that normal map to have soft, rounded edges. Good? Moving on!
The final step is to take the normal map and plug the level's lighting info into it. For the purple mountain level, the light comes from the upper right of the screen and has a pinkish hue with darker purple shadows. Thanks to the normal map, this last effect knows to give any surfaces facing the upper right of the screen the most light, with the opposite faces receiving the least light. This lighting data is saved into its own image which is about 50% transparent. Finally, that image of colored light is drawn on top of the actual ingame level's world blocks. The computed coloration gives each block the soft (and contiguous) lighting I was going for, and the transparency I mentioned makes it so that you can still see the underlying level architecture instead of it being completely washed out.
Shorter version: I spent two weeks making something pretty rather than adding gameplay functionality. That, right there, is the perfect credential to be a producer at a major video game publisher. Hear that, EA?