Devlog #3 - Facial Sprites & Character Customization

Today's devlog is a joint effort between PECTIN and me (eZombo) but without further ado, let's start~

Devlog #3 - Facial Sprites

HI! Here's PECTIN! (ノ゚▽゚)ノ

I will tell you about my approach on creating facial sprites for //TODO:today and Teach Me Onegai!~. To be honest, this won't be anything ground-breaking but I came to learn some useful stuff during my work. I just hope there will be some helpful piece of information you can take from this.

Or you might feel better by basking in your superior knowledge about character expressions if there's really nothing new for you here.

Alright, let's do this!

Before I even begin making the sprites I have finished a body sprite with a "blank face". The omitted dominant facial features are usually distorted by strong expressions. I decided on the parts by thinking of something uncomfortable and grimacing. That makes the eyes, eyebrows and mouth. Usually the nose and cheeks of a human face also move but I left them static on the body sprites to keep it simple.

The next step is to make a list of facial features a character has depending on their characteristics/expressiveness and the situations they will be in.

I felt too satisfied by looking at these to uncheck them for the screenshot...

That's it for the preparations! Now they just have to be drawn!

It was convenient to have the facial expressions in the same .psd files with the body sprites of all characters to compare them during the process. Especially the male and female pairs of Teal, Joyce, and Phoenix had to be consistent. So the expressions would still have the same vibe even though they are of different gender. Each character has a folder in the layer structure of the file. In this folder I created an "expressions" folder for each. This is where I also create the layers for each expression.

To make the drawing process smoother a rough sketch is always helpful.

The real' tedious work was to make the positions of the eyes, eyebrows and mouth align. I make the default resting face first and then switch it to 20% opacity so I can reference it while working on the other expressions above the default face layer. Of course I cheated and copy-pasted some eyes over various expressions so I wouldn't have to redraw everything.

The "blush" and "sweat drops" are separate from the expressions and are placed on top of the face in-game. So I have to make sure they fit every expression when I only draw them once. I do this just by switching the visibility on for every expression (which looks pretty ugly) and then put the sweat drops and blush in some free space.

What I then did was saving the expressions, "blush" and "sweat" separately and in the same canvas size as the body sprites. Every set of expressions was put in the images folder corresponding to a character.

And that's how I made the expressions for each character! (人 •͈ᴗ•͈)

Character Customization

And now to the programming side of things!

When we started planning //TODO: today back in January we knew that we wanted to have variable genders for the main characters and so I started working on a prototype to see how you can actually build that.

Compared to //TODO: today or Teach Me Onegai!~ this prototype was really simple because the characters only used single images and the protagonist didn't even have graphics but it was still helpful to figure out how to implement this feature without creating additional work for writing the script.

The first two ideas I had were the following:

  • Displaying graphics with if-statements
  • Making different characters for each gender and using a variable to display the correct one

I quickly let go the if-statement idea because doing this every single time a character image changes is not even viable for small projects.

The idea with the separate characters didn't sound too bad until I actually tried to execute it.

I barely knew anything about Ren'Py back then but trying this out at least taught me one thing: you can't really use a variable as an identifier for an image. (Or maybe you can and I just didn't know how, but I ultimately found a simpler solution anyway!)

I tried a few more approaches that all had some sort of drawback, so the trial and error went on for a bit longer until I finally stumbled upon the solution that's currently in both games!

The basic idea is to store part of the file name in a variable to have the game dynamically display the correct image.

For example, Joyce is just one single character regardless of what gender they have in a particular playthrough.
So the code for Joyce's character images looks like this:

image joyce rest = LiveComposite(
    (800, 1300),
    (0, 255), "characters/[gjoyce]/[gjoyce]_default.png",
    (0, 255), "characters/[gjoyce]/[gjoyce]_rest.png")

As you already saw previously, the character sprites are made up of a lot of different images that are assembled in-game using Ren'Py's LiveComposite feature.

"[gjoyce]" is a variable that is assigned either "fjoyce" or "mjoyce" during the character setup in the beginning of the game.

We set up the folder structure and file names in a way that follows the same pattern for either version of Joyce and because the images aren't displayed before the "[gjoyce]" variable has a value, this doesn't lead to any errors either.

The graphics for Teal and Phoenix are handled the same way, and I also used this technique when implementing the censorship settings in Teach Me Onegai!~ (although as an aside, for the latter the value was stored in a persistent variable since we didn't want the settings to be bound to a single save file).

And that's pretty much it! For everything else you treat the images like any other displayable and if you wanted to, you could also change the value of the variable at any point in the game. In our case it wouldn't make much sense but the technique can probably be used in different ways than what we are currently doing!

But that's it for this week.
We hope you found this devlog interesting and as always, if you have any suggestions for future topics, feel free to let us know!
Thanks for reading <3

Get //TODO: today

Download NowName your own price

Leave a comment

Log in with to leave a comment.