Character creation is always the first thing I have on my feature list, and the last thing I actually implement. Truth be told, I'm not happy with the games I make unless you can customize your look in them; they're expressive, they're fun, and if you build them right they're even economical. Once you have a framework for building custom characters, you can design your NPCs using the same parameters as the player characters.
Here's my crash course. I used GDevelop 5 so I could embed the end results, but the principles generalize to other engines. I recommend reading straight through to understand the entire start-to-finish process (rather than following it step-by-step) so you'll have the hindsight to do it right.
Most game engines distinguish between "global" and "scene" variables; variables retrieved in every scene, and variables retrieved in specific scenes. If the player character can be renamed, that's generally a global--the data has to be pulled so often, you might as well always keep it in memory.
Information narrower in scope will be confined to the scene that needs it. Even narrower data, like a specific creature's health, will be stored as an object variable.
Character creation data is troublesome because it's narrow in scope but needs to be global. The volume of information is high: hair color, eye color, skin color, height, hair style, and other variables, all need to be retrieved constantly to define what a character looks like in nearly every scene. The more complex this data gets, the more of a burden it becomes on the engine and the hardware.
Scenes can be very complex, because content can be dynamically pulled in and out of memory as it leaves the viewport. A created character is always visible, so its data eats up a permanent chunk of memory and its variables are being referenced on every frame.
For that reason, it's best to simplify the globals as much as possible. In this example, instead of tracking each limb, eye, shoe, pants, shirts, etc., I streamlined everything into four broad variables: PlayerColor, PlayerSkin, PlayerHead, and PlayerBody.
I can structure it so simply because the game's art style is built around a few vibrant colors and strong contour lines. A more complex art style requires more tracking. For players to recolor each eye independently, you need separate variables to track each eye's color, and the same principle applies to any extra clothing or accessories.
(In GDevelop you can also add variables by modifying your project's game.json file in a text editor or IDE like Bluefish. Just use the frontend to add a variable the first time, then open up the json file and see how the formatting works to write your own.)
The way a character creator functions under the hood is tied to the art style. Here all of the characters are composed of flat colors drawn to separate layers that are allowed to anti-alias at the edges. Consequently, the player character is made up of 5 primary layers:
To avoid conflicts between the order the colors are layered in, the eyes and mouth exist on their own separate layers containing the contour and base color. Furthermore, the contour lines are really broken up into the head contours and body contours, as is the base color. This brings the total to 9 layers. In-game each layer gets its own object, a "sprite."
Separating each color into its own layer allows us to independently recolor each of them without affecting the others, while putting the eyes and mouth on their own layers makes it possible to animate them independently of the body. Breaking up the contour and base color layers into head and body versions makes it possible to have effects like hair hanging down behind the body.
To recolor the layers, we add a Color Replace effect to every object we want recolored:
Then, we write events on an event sheet that modify the Color Replace function depending on the text of the PlayerColor variable:
Note that there are many more objects making up the player character than there are variables controlling how they look. "ch_mid_head" "ch_mid_body" and "ch_mid_eyes" all refer to the "midtone" or "base color" making up the sprite, and what color they are is all determined by a single "PlayerColor" variable. "ch_line_head" "ch_line_body" and "ch_line_eyes" all refer to the "contour line" making up the darkest part of the sprite, and again are all controlled by the PlayerColor variable.
In this example, I combined the variables for the eyes and mouth with the body, so the eye and mouth colors are controlled by the same events as the body colors. I could give them an their own variables and corresponding events that replace their colors separately, but that would clash with the Game Boy Color-inspired art style.
We can't just start from any particular color when using Color Replace. While I designed the "Mango" character palette first in Clip Studio Paint, if I were to Color Replace from Mango I would end up with significantly darker colors than specified. This is because trace amounts of red and green light would be left over when shifting the values.
Instead, I use "Lock transparent pixels" in Clip to paint each layer absolute white before the sprite ever reaches the game engine:
Lock transparent pixels preserves the gradual loss in opacity at the edges of layers that creates smooth anti-aliasing, so we don't end up with jagged pixels when making a high-resolution sprite. (In another context jagged pixels would be desirable, but we're not making Owlboy today.)
The reason we use absolute white (255;255;255) is because white light is composed of all colors, and can be split into any of them subtractively--the Color Replace function only has to remove information from the pixels, not add any in, so when it modifies the colors in the base image you don't end up with leftover values darkening the sprite.
The Color Replace events are a simple process repeated many times over. When the Mango button object is clicked, the string of the global variable "PlayerColor" is set to Mango, and a separate event changes the Color Replace value of the sprites making up the player character. ("ch_line_head", "ch_line_body", "ch_line_eyes", "ch_skin", "ch_mid_head", "ch_mid_eyes", "ch_mid_body", and "ch_dark." "ch_light" never actually changes because all character designs use the same highlight color as part of the art style, and "ch_skin" is controlled by a separate set of buttons.)
To make the other colors, I copy-and-paste this exact event and change the string to "Grape", "Blossom", "Cosmo", or whatever other color name I'm using for a palette, and change the Color Replace values to the desired RGB range. Recoloring each of the layers happens the exact same way, just with different targets for the Color Replace effect and different RGB values.
For changing skin tones it's the same, but instead of a string I assign each tone a numeric value ranging from darkest to lightest. (In a more complex editor the player would be picking these values out of a color picker matrix, but I'm keeping my character creator simple because I don't want to create choice paralysis. Lessons learned from Xenoblade Chronicles X...)
Keep in mind how the interface actually presents itself. I made this demo for both mouse and touchscreen inputs, with some influence from Pokémon Battle Revolution's pointer-driven editor:
Try mining the Games UI Database if you're feeling stuck and lacking ideas. Not all of them are winners--interacting with a flat UI is like reading tea leaves--but you can't go wrong with something friendly, fun, and easy to use. If a complete novice who's never touched a video game before can know how to play your game just by looking at it, it's good design. Turn to a Don Norman for the authoritative voice on user interfaces, and Scott Forstall for good principles.
So now we can palette swap the characters, but what about actually changing the character design? This is where things get a little tricky. What we're essentially doing is changing the animation of the individual layers depending on another global variable. For simplicity, I divided the player character into "Top" and "Bottom" components. The top is just the head and hair, while the bottom is everything from the neck down.
First, we add animations to our objects reflecting the new character designs. Like the first set of sprites, they're recolored white before being imported--the exact same events we made before will recolor them, with no further work on our part.
Then we create two sets of events. The first set updates the global variables for the player's body parts ("PlayerHead" and "PlayerBody") when the Top/Bottom buttons are clicked, and the second set changes the animations of the objects ("ch_line_head", "ch_line_body", "ch_mid_head", "ch_mid_body", and "ch_dark") depending on the variables' values. So if PlayerHead = 2, then the animation of ch_line_head is set to 2, and you get Sailor Mars' haircut.
This covers the fundamentals of a 2D character creator, but there are some deeper points to consider. When actually moving a character around the screen, we need to change which animation plays depending on the contents of the PlayerHead and PlayerBody variables. The variables also need to be included in the game's save procedure so they can be loaded with the player's file, and other scenes that draw the player will need to have the player sprites added to them, plus these events have to be linked to their event sheets, so they can reference the colors and sprites to draw.
Furthermore, the way I did it here in this prototype isn't quite optimal. The issue is in how hair is drawn; in the current configuration, hair sprites are fused with the Top sprites. ("ch_line_head", "ch_mid_head" and "ch_dark.") For the head to actually be ordered in front of the body, all pieces of the hair "behind" the back need to be carefully erased to make sure they don't occlude the body. The alternative is to order the entire head behind the body and selectively erase the neck to avoid it occluding the face, but no matter how I approach this I also need to account for every character variation having running animations:
This would require me to either add more animation frames to each style of hair and erase different parts for every frame, or selectively erase the neck and shoulders where the head intersects with them. (Depending on whether the Top sprites are in front of or behind the Bottom sprites.) No matter how you cut it, that's making a lot of extra work. The better way to do this is to break the "front" and "back" pieces of hair into their own layers, so that elements that are supposed to be behind the body can truly be drawn behind it. Then I won't need to make extra animation frames for things that aren't moving.
At this point we're straying away from the subject of making a character creator, and starting down the path of "skeletal" animation. It's a technique 2D artists appropriated from 3D artists to keep pace with polygons. In a nutshell, you have a set of sprites stapled to other sprites along specific "bones" or "connection points." Since each sprite is a separate object, it can be drawn in front of or behind others based on its "z-order", and animated or transformed independently. That helps expedite the animation workflow while doing a lot of things you can't normally do in 2D.
Sophisticated implementations use actual rigs like a 3D model, and properly separate anything that needs to occlude other pieces of the skeleton. You can see examples of it in modern 2D games like 13 Sentinels: Aegis Rim and Super Robot Wars Original Generation: The Moon Dwellers, where each piece has its own animations but is able to rotate and scale independently. In The Moon Dwellers, Granteed's main body gets about ~275 frames of animation simulating different perspectives, positions, and distortions for its limbs. That sounds like a huge number, but to traditionally animate all its attacks would probably take at least double that.
I'll do a deep dive into skeletal animation another day. I'm tied up on a battle module for now, and I've been building out test levels in Pandako's excellent 3D extension, so I'll probably write something on those further down the line. Go ahead and take the character creator for a fullscreen spin if you like.