Portraits


Portraits

The portraits was an unexpectedly difficult part of game development. The vast majority of code in the game is actually handling quirks with the portrait and character customisation screen.

To give an idea, here's the rough outline of how a character's sprites are assembled:

-------

The character has an property,  e.g. head 0-7. This is what the user selects on-screen, it's then translated into an image name for the portrait, usually this is something like: head_0.png

but some of them are different, 

  • e.g. wings have 2 images, front and back
  • capes are named 0 and 3 for some reason, no 1 or 2

So depending on the option a player picks, the game needs to generate the correct file name and apply these quirks.

But that's just the portrait. The character sprite also needs to be generated. Given each portrait, there's a corresponding set of sprites

e.g. a portrait might be called "torso_2" we need a set of torso sprites for the directions left, up, down (right is assumed to be a mirror image of left). That might look like:

 ['chest_back_2','pelvis_back_2']

But these numbers don't necessarily match the portrait. 

  • e.g. the arms have names:
  • back_arm3x_0
  • back_arm1_0x

so more special cases are needed depending on what the destination file name is. Additionally, the folders are inconsistent, 

e.g. for the torso, both the torso and the pelvis are in the same folder, but for the cape, they are in different folders:

  • cape_side/cape_back0_0
  • cape_back/cape_back_0_1

Then, since the original portrait only has arms, head, etc, you need to match the arms to the legs.

Then you get an array of sprite names. But each of them can have different sizes. For example, side view of arms are bigger than front-view. So you end up with lookups like:

 'torso':{x:-353.941834,y:683.037442},//portrait position

for the portrait, and 

 'torso' :{abs_x:-18 ,abs_y:80 ,z_index:5},//sprite position

These are essentially hard-coded values that need to be applied on a case-by-case basis.

But we're still not done yet! Just knowing the image name and the offsets would be enough to show the sprite, but would require having 

Each image as its own file. Multiply 2 genders, 3 directions, 8 options and 3 animations frames is over 100 files per item this quickly would fill up the limited number of files allowed on itch.io (1000), so the sprites are packed into a sprite atlas.

But this means the atlas needs to be translated from the source image->another lookup 

 {"name":"chest_back_0","x":212,"y":65,"width":36,"height":56}

Finally, the image from this atlas can be extracted and drawn on the screen.

That's 5 different layers needed just to go from the user clicking a button to showing the image on the screen. Each layer needs a bunch of distinct patches to fix quirks found with the source image names, sizes, folders, or offsets.


The game would have to look through all this data every frame, for every character. Thankfully, I can cache the images before they are drawn, so that it can be quickly redrawn without redoing all these lookups.


Forever spent squashing bugs. To find and fix these issues, it was necessary to click through every combination of every option. Often looking for a single frame that might not work.

Composing these sprites is by far the largest amount of code in the game. 

  • Composing the lookups is around 370 lines of code
  • Using the composed lookups: 200 lines of code
  • Consolidating inconsistencies from portraits->sprites: ~780 lines of code
  • This is excluding the 40+ files that contain the offsets and image data

Comparatively, the entire logic for the main game, is ~400 lines of code.

 For example, I spend hours tracking down why a single arm would not display, only to find the source file name has a space before the extension:

Would you have spotted it?


Comments

Log in with itch.io to leave a comment.

Oh. My. God.