itch.io is community of indie game creators and players

Devlogs

Face Generator Updates

Mars After Midnight
A downloadable game

Since putting together the first playable alpha I've pivoted back to work on the procedural face generator. Original details over here.

The face generator is written in Python but in a C-like style that could potentially port to full C. The idea was to eventually move the code to run on-device and generate an infinite number of faces at runtime.

As the game design solidified I realized this runtime generation wasn't going to happen. For one, it's not really necessary: I can generate thousands of faces offline and just include them in the game -- each face is just a few kb.

Second, the face generator is not quick. Part of the problem is Python's leisurely pace but even with conversion to C and heavy optimizations it'd never be as quick as loading a small PNG on-device.

Third, although I'm well focused on the success rate of the generation, there's still a clear range from bad-to-good with the resulting faces. Being able to curate these and choose exactly what appears in the game will save us all some grief.

Pre-generating the faces does require a quick system to check/approve faces, and a reliable way to re-generate a face when aspects of the generation code change, but none of that's been a problem so far.

Besides drastically simplifying the runtime this choice also let me refactor the generator code to be more Pythonic and easier to manage/extend.

Of extending, here's most of the new stuff that's been added recently:


More Part Variations

The simplest way to expand the face generator output is to add new part variations. Just draw new features on their respective grids and the generator can drop them in.



 Some added eye, nose, and mouth variations


More Part Types

Besides the basic eye/nose/mouth, I also added a few rarer parts types like whiskers, antennas, and wrinkles. Each of these needs special logic to integrate with the face layout.



 Whiskers, antennas, wrinkles. The whole rodeo.


Overlayed Parts

Some game mechanics require certain accessories on the face. Currently that means sunglasses and respirators but I expect more eventually.



 Sunglasses and respirator overlays


Shape Upgrades

The core structure of the face is determined from the initial eyes/nose/mouth layout. These hand-drawn parts are then surrounded with a bezier path that defines the shape of the head.

The path is stroked using a hand-drawn texture ball. Adding more texture balls is one way to add variety, and the precise way the border surrounds the core features is also variable. Since the last face update I've added more textures and a few new shapes. I'd planned to add a lot more shapes but found a better way to get variety was to apply a lumpiness deformation to the path instead.



 Border textures, head shapes, and lump deformations


Faker 3D

Everything about this game is 2D but I am faking a lot of 3D with the style and the in-game layer parallax. Mucking around with things recently I made a few subtle tweaks to the face generator to add some dimensionality.

// Shifted Parts, Muted Lumps

Each face has a left or right "look direction" to establish a slightly off-center view so the simplest improvement is just shifting the parts horizontally to match. Another technique is to reduce the lump deformation effect on one side to simulate a more edge-on view.



 Original, shifted parts, & reduced lump deformation on right side

// Banana Warp

Applying a gentle bend of the entire face away from the look direction also adds a hint of volume.



 Warping the face along a slightly curved spline


Status

I feel pretty done with the martian generator right now. Even if I still have to dip in for fixes and customizations, the general output is basically shippable.



 Martians generated with all the latest changes


Other Species

Up until recently I've put all my effort on make funny looking martians and it was only in the back of my mind that I'd need to change things up somehow. Bring that to the front and now I've added humans.

The main focus for this game is on the martians so anything else is really intended for flavoring. On first getting the humans in, I noticed they made the martians seem more interesting by comparison. That seemed like a good thing so I leaned in to making the humans slightly more grounded to emphasize that gap.



 A Mars-faring human

These use most of the same face generation logic as the martians, with a bunch of parameters locked down (eyes = 2, nose = 1, mouth = 1, etc), new head-shape logic, and all new hand-drawn parts.

I wanted to keep the work manageable here so they're all in spacesuits as an excuse to stay covered up. I've only bothered to hand draw a few eyes/noses/mouths so far and need to add more eventually.



 Human face variety

As with the martians, the heads are generated from a stroked path. I tried to do the same with the shoulders but I don't have a good pipeline for the path editing -- it's all just numbers in code. I gave up on the paths and just drew the suits by hand instead.



 Stroked-path bodies replaced with hand-drawn ones

The upside is that this inspired me to define six factions, each with their own badge and suit design. May come in handy for the narrative.



 Human factions

It's also possible to put a martian in one of these suits. I haven't figured out if that's useful or not yet.



 Never seen a more useful dude


Now Do Robots

Refactoring the Python code for humans put me in the right place for adding more fundamental face types so here's robots. There are now three supported species -- martians, humans, and robots -- which is surely enough.



 Robot!

Along with new hand-drawn parts, the big change for robots is the head shape generation. Without getting too clever, I wanted something simple and distinct from martians and humans. Same idea: to create contrast with the martians that make up the majority of the population.

After placing the core hand-drawn parts, the generator divides the face into stacked rows and assigns them discrete randomized widths. These are joined together and combined with shifts and other 2D fakery to add depth. I happily punted on the bodies and just use a shaded box for all of them.



 Randomizing robot head profiles and row depths

Shading on the front is the same as with martians/humans. For the sides I built a simple hatching system that strokes a bunch of parallel lines with selectable density.



 Shading effect

With added shadows, variable necks, and strategic skews they all basically look like Futurama rejects. Good enough.



 Robots


Regular Intelligence

The rise of AI in the last few years has got me reflecting on the futility of this kind of hand-built random face generation. I'm still happy with the results and I don't think generative art would get quite the same effect but I bet it'd be close.

Anyways, all this offline work has been fun but at this point I'm looking forward to getting back to narrative design and game code.

Read comments (16)