Sunday, May 13, 2018

Dreamhouse process diary and prototyping notes + a better retro 3D low precision vertex shader

In collaboration with local NYC-area arcade collective Death by Audio Arcade, me and several other gay / queer artists are making small games for an event at a Brooklyn queer arts space called Dreamhouse / (formerly known as The Spectrum). My contribution is shaping up to be a retro low polygon 3D brawler called "Dream Hard."

If you want to play it, you'll have to visit The Dreamhouse, which will house the only public display of the game in the world (for the time being), starting in late May 2018.

I don't have much time to work on this, so grounding the concept firmly within a clear retro arcade genre helps me work quickly with less realistic visuals and simplified character art, while also engaging deeply with the arcade tradition of game design. Specifically I'm riffing off one of my favorite genres, beat 'em up games like Die Hard Arcade, X-Men Arcade, Simpsons Arcade, or the iconic Street of Rage series, which all offer breezy brawling with strange setpieces and colorful sets.

Here's some prototype GIFs and notes from my development process...

I don't really care that much about making a "pure" brawler game, and I'm not doing anything radically experimental with the gameplay, so I decided to build off a "Warrior Pack Bundle 1" template that I got for free years ago via the now-discontinued Unity Asset Store "Level 99" promotion.

The assets and character controller script were surprisingly robust, but the author's decision to base everything off of coroutines and then freely interrupting coroutines with StopAllCoroutines() means a lot of random timing errors and race conditions where you never really know if a coroutine will complete, which makes it difficult to manage the character's state. Like, imagine there's a "JumpKick" coroutine that resets the player at the end of the kick -- but if the player gets hit before the kick completes, and the hit calls StopAllCoroutines, then the player won't get properly reset!

After a lot of "defensive programming" I finally got it feeling stable enough, and started doing more AI tests.

I prototyped the basic enemy AI bots rather quickly. It technically uses the same prefabs as the player characters, but with a "use AI" mode activated, which fakes keyboard input to the bot. The end result is systemic consistency, where the bot can do anything a player can do, and vice versa. Unfortunately this fairness ends up feeling unfair to humans, because the AI will just totally gang up on the player and kick their ass with perfectly executed combo attacks. I ended up implementing an "AI skill" parameter that decides how efficiently the bot will circle strafe, attack, and/or react.

Also note the isometric camera perspective. I thought I was going to emulate the 2D perspective of old school brawlers, but it never quite felt right to me. And because I wanted to emulate retro 3D Playstation 1 era graphics, this camera also felt unfaithful and anachronistic: at a time when 3D graphics were still very new, flattening the perspective was precisely the last thing a game developer would want to do.

At that point, I decided to do an art pass. I built out the arena to resemble the main room at The Dreamhouse, and I tried to light the space with a color palette from a moodboard of Dreamhouse photos that I collected from their Facebook page.

I also art passed the characters, improvising a basic procedural character generation system that randomly toggles body parts on/off and chooses random colors. It often results in some very good outfits and looks. Much of this system's power comes from the abstraction of working with a low polygon look -- I can just parent random cubes to the characters joints, to suggest a hair style or a shoe, and it feels consistent enough to me.

Lastly, I did some overall art direction decisions and overhauled the shaders. To get the feeling of an older television, I render the game at 640x360 resolution and then layer this CRT post process shader from demonixis on top, with some minor edits to weaken the overly sharp scanline effect. Note that most Unity projects should use a low resolution render texture to get this pixelation effect, which is resolution independent and thus works well for windowed and HTML5 embed display modes. However, since I'm designing this game specifically for one arcade machine, I can guarantee it will run full screen.

I also relied heavily on this psx_retroshader pack by dsoft20, with its posterize post process and its low precision vertex shader. But then I was encountering problems with the vertex distortion, and I also wanted more control over the degree of distortion... so I mixed in the low precision parts of Keijiro's Retro3D shader, to get the best of both worlds: better vertex distortion from Keijiro as well as vertex lighting / fog support from dsoft20's version. I also have a suspicion that Unity's automatic shader API upgrades might've been "fixing" the distortion and perspective de-correction before, so I added a "UNITY_SHADER_NO_UPGRADE" line to the shader file to make sure it leaves the code alone.

My combined shader code "VertexLit-Retro3D.shader" gist is embedded below if you want it, under MIT license:

Anyway, that's just what I've been up to this month, and hopefully I'll have more progress to show next week when I finish it. Peace out.