You mentioned that you have a simple probability system for the randomization of the faces. Have you thought about controlling the correlation between features? For instance if the face is boot shaped there is a 90% chance the ears are fin shaped, but if it's flop shaped then there's a 80% chance it has horns instead.
Making Martian Faces
Most of the work on this game so far has been figuring out how to make interesting-looking martians. I've been prototyping this in Python, writing a script that combines individual facial features with a head shape and some extra stuff. None of this is very complicated but that rarely stops me from posting about it.
Right now there are 8 main types of facial features: ear, eyebrows, eye, hair, hat, horn, mouth, and nose. I thought I'd get my drawing arm limbered up for this and wanted lots of different variations of each type. Instead of using a tablet for sketching this time, I printed a light cyan grid on paper and drew a bunch by hand.
After scanning these in, the script breaks the page into cells, thresholds the green channel to ignore the cyan lines, and extracts the individual features.
One extra step is that I can edit the scanned image before the script processes it to add magenta lines where I want closed areas. This gives me basic control over the transparency channel.
The script then builds a face by combining a few features together into a simple stacked set of rows. Each row is one or more of the selected feature, randomly rotated/scaled slightly.
Eyes, a nose, and a mouth, stacked
The mouths are treated specially with basic curves to get some more variation.
Sad! Sad? Happy! Happy?
And once the eyes are set an eyebrow row can be added on top, also stroked along curves for variation.
Certain regions of the original feature grid cell are marked as non-solid, which allows snuggling the rows together vertically with natural overlap.
I played around with different types, repeats, and orders of the rows but since I'm mostly drawing human-looking features, not much beyond an eyes-nose-mouth stack makes much sense or looks very good.
Just changing the number of features per row, and collapsing some rows can give interesting results though.
Ok, nothing too special happening so far. Moving on.
Containing the Features
Now that we've got some junk on the face, it'd be nice if there was a skull to hold it all. You could do a good job of this by just drawing lots of variations and dropping the facial features onto them. If I was less lazy and more talented that's what I'd do. Fortunately my alternative is interesting enough for some devlog details.
The first step was deciding that I'd use splines to define the face shape, specifically bezier curves. Of all the options, beziers are a bit of a pain to work with -- each control point requires two tangent handles and editing tools have complex finicky ways of dealing with these.
Bezier path editing in Illustrator
Still, I think beziers look the best when done well and if you want an easy way out like me then you need an algorithm which automatically generates smooth tangent handles from a given set of control points. I adapted a bit of code I used on Obra Dinn for this. Editing bezier curves in 2D is no fun but in 3D it's absolutely tortuous so this technique was necessary to keep my sanity and give me nice smooth curves on the ghost smoke trails and tentacles in that game. Instead of free positioning on every handle for every point, there's a general "smoothness" setting that affects the whole path.
Automatically generated bezier handles with increasing smoothness
Ok so just port that code, slap a path around the head and we're done.
Our good friend, Eggy
Hmm. I'll deal with the overall shape more below but first, surely the stroke could be more interesting than just a solid line. I went back to pen and paper and drew a few textured balls.
A few textured balls
Load these in and unroll them into straight lines.
Ball edges unrolled into straight lines
Then, instead of stroking a solid line, the script chooses a small segment that matches the desired tangent of the curve and splats that down, repeating the process over and over along the path.
Splatting the texture segments along the curve
Depending on how complicated the texture ball is the result can be a little disjointed where the splats don't line up, but I don't mind it. The ease of adding new textures by just drawing a ball is hard to beat.
That mostly takes care of spicing the line up, now to fix the egg shape.
A round enclosing path is a good start and a bad finish. I first tried jostling the control points around to make a more interesting shape but that was underwhelming. Eventually I worked out a fairly simple system:
1 // Divide the face vertically into a top and bottom.
2 // Apply one of a few custom path generators to translate and enclose the top/bottom rectangles in different ways.
BEAN . BOOT . FLOP
Best part of these path generation algorithms is their names in the script. I've got five shape generators right now and plan on adding more. The top/bottom split point can be randomized, along with the forehead, chin, padding, and other spacings.
At some point I got the feeling that the features I'd drawn were a little too simple, hitting the limit of my ink-on-paper skills. The next step was to go digital so I took the scans into Procreate and redrew them with much more detail.
Along the way I also buffed up the script to procedurally add features around the outside, some basic shadows, extra internal border segments to define rough shading, various blemishs, and thick outlines to the border.
Your favorite childhood cartoon, reimagined for today's streaming series
Yikes. The stark face of working on something, getting tired of what you're looking at, and fiddling with it forever. No doubt I'll exhaust myself before this thing is done.
All of the features, shapes, and other bits of the face generation are driven through a simple probability system that lets me control how rare or common certain configurations are.
Some configurations, like a missing nose, are rare
One thing I haven't fully decided is if I'll port this Python script code to C and try to run it on-device. The alternative is to pre-generate the faces as part of the build process and just load/use those in the game. Since I don't have the exact gameplay nailed down I don't need to figure this out yet.
Log in with itch.io to leave a comment.
The system itself does support species like that but I haven't loaded it up with much yet. It's more-or-less based on some ideas from Papers Please, where what you really want is to define some criteria, then generate papers (or a face) that explicitly matches or does not match in interesting, non-confusing ways.
the Bean Boot and Flop idea I think is what is selling this!
This is great detail. The ball -> texture flow is nice.
Reminds me so much of those Donruss monster baseball cards/stickers I collected as a kid, I am very excited!
Brilliant, as ever amazed by the amount of thought and care put into this process. This approach makes complete sense to me; nothing more excited then being genuinely surprised by your own procedural creations. Would be great if you manage to port it to C, if not I imagine each face only takes up a few kb. Current favorite martian: top left, I'm sure I saw that guy in Heavy Metal.
Love that flop shape. Delightful stuff!
Wow this is amazing and I never thought of scanning in paper for art in a game. How cool! Also, loved the dry humor language used. Gave me a few good chuckles. Hope for more!
"Our creator made us for frivolous pleasure. Much care was taken that we were unique, none that we were happy"
- Martian from the mature rerelease of Mars After Midnight (probably)
These are looking pretty good, I'm enjoying the dev logs. You're making me want to dev for the Playdate
Can you please change highlighting color of the page? It's invisible and I can't select text for the translations...
I got surprised by that part where you added more features and details with procreate. In my mind it was already good enough with the ink sketches. Made me think of how easy it is to see something as good enough before it’s actually good and has enough details.
As someone who draws characters a lot, this approach is coming at the problem of “I want to design an alien” from such a vastly different direction than I would ever think of, and I absolutely love it. All these designs turned out great! I love these martians!
What an incredibly cool thing to get a peek at. Thanks for sharing! Good luck with the rest of the project!
You're willing to spend a lot a time for a "quick game" for a little device such as PlayDate. I find that very interesting, Very impressing too. But designing custom "monsters" from the beginning isn't an easier way instead of making an algorithm to build pre-generated ones? I understand that it means caring for your own project, but I wonder in what there is a big difference? If there is one yet of course!
I like to be surprised by what an algorithm can generate from the pieces I feed it. Designing all the martians by hand would probably look better but be a lot less fun to work on. Also I don't know how many I'll need yet. Probably in the hundreds/thousands.
You are really dedicated for this project and that is really nice, for you and for the players out there, I can't wait to get the playdate, hope to get updates from you and I certainly hope it'll take less dev time than Return of the Obra Dinn. Cheers
I love to use random generation in my projects where I can to avoid bias when designing something, you end up with a lot of happy accidents or combinations that you never would have thought of. One project I have used generates random soft colour tones and I come up with colour pairings I never would have considered before.
wow what a process. Love this little dev dive