21. How to create custom character creation screen with Unreal Engine part 2

This is a multi part post and is the second part:

In this episode we’re going to cover the nested options that go into character creation screen. This is a universal topic so may be useful in many other parts of the game, but we will specifically focus on the character creation part.

The assets used here are from N-Hance, I am not affiliated with them but like their content.

Character creation part 2

Specifically it is this part that we’re focusing on:

Focus on the options for character creation screen

In order to do this work, you will need 2 widgets. First is the root widget for the character creation screen and the other is for the option toggling – because the options will be set out dynamically.

Create character widget

Creating root widget for character creation

So first you have a horizontal box, this is not essential, you could have a simple canvas panel instead of it as root component.

Next you add a size box component, which you will need to align to the right of the screen and stretch it vertically.

Align to right and stretch vertically

Next, add a border component, to which you will add styling too, as well as adding necessary padding.

Add a border with your desired styling and some padding

My border was part of the 4k full fantasy GUI asset pack – but you can use others, its a styling pack so will not have impact to the code we write.

Next, I added a vertical box to fit a couple components – a title, the options, the character name and create button.

I will focus specifically on the custom options part.

Nested border for the dynamic options

So part of the Horizontal box, we have a border component which will draw a nested table view. This is optional. But inside that you have a scroll box component. This is where we will start adding the nested options.

The scrollbox component is key here, but it could’ve been others, for example uniform grid panel or similar. I think the scroll option would work nicely here therefore would advise that one, but use whatever suits you application more.

Ok now you have the design sorted out, before we go into the blueprints, let’s create the component which will go inside the scrollbox.

Toggle options widget

The toggle widget is as described. A widget which will allow you to toggle options.

Toggle widget

It will contain a ‘Title’ and the ‘option’ value. It will also have 2 buttons, to toggle left and right.

It will not do processing inside this widget itself, but provide callbacks for when those buttons are pressed.

This is similar to design pattern in React js – a UI library for web development.

The blueprints for this widget are relatively straight forward

Blueprints for toggle widget

First create some variables, CurrentValue and Title, both as String – see part 1 in screenshot above.

Make them both Instance editable and Expose on spawn so that you can fill them out part of constructor for this widget

Instance editable and expose on spawn

Next create a custom event (right click -> custom event) and call it Update value – this is to update the dynamic value that’s written in the widget.

See 2 in blueprints for populating this custom event – effectively setting Current Value to the textbox inside the widget.

Next, see 3 for populating the constructor – this is populating the static Title field which is static. If you want it to be dynamic, you can add it to Update value custom event too.

Then we want to create some event dispatchers – see part 4. Create two event dispatchers, LeftClick and RightClick.

Finally in 5 we link those events to the button presses. This means that when a user clicks on the left button, an event is fired which we will utilize in the parent widget to handle the change.

Preparing the data – structures

Now we want to prepare the data that we will be traversing.

This part can be very tricky to get right, so I’d suggest you draw some things on paper to see if it will all fit together. i.e. dry run your solution.

What approach did I take?

For my create character options, I think the core of the nesting relies on the race + gender of the character.

For example, what hair meshes are available?

  • Human + male = [option1, option2, option3]
  • Human + female = [option4, option5, option6]
  • Orc + male = [option7, option8, option9]
  • and so on…

I hope you see what I am saying here – the base for the options for me in my use case, was race + gender – it could potentially be different in yours.

Furthermore, note that option will also potentially want a dual value, i.e. user facing name and internal key. User facing names can have spaces and special characters etc. But keys should avoid those.

Note that it will get a bit more complicated in future (when applying meshes to character) when you will also have to evaluate items that the character has equipped.

i.e. you will evaluate face mesh + material (based on race + gender + skin option) – then you have to worry about whether the player is wearing a helmet, which is yet another option. Simplifying these options will be key and we will cover some of this as we go through this post and part 3 when we’re applying these to the meshes.

Ok so now that I know what I want my options to be and their data type, I can start preparing the data structures to support this.

First I create a new structure (Right click in Content browser -> Blueprints -> Structure). I’d suggest creating a separate models folder to keep these in.

Create two structures, OptionsArr and RaceGenderPair (or whatever options you need)

Inside the RaceGenderPair we simply have two string fields, for Race and Gender. This will be used as a key (composite key) for our Map of data that’s to come. In reality, what we’re aiming for is creating a structure like this: Map<RaceGenderKey, OptionsArr>.

RaceGenderPair structure

Next, we create the OptionsArr structure:

OptionsArr structure

In this structure, I utilised a previously created structure called Tag and made it array (this is because Map in UE will not allow you by default to stick array of values inside the value field of Map).

For reference, the Tag structure is a name and value pair, create this if you don’t already have it:

Tag structure

This is useful in many places, particularly when displaying values to users and linking to internal data structures.

Ok now you have prepared the models required, you will want to start populating the actual options.

Preparing the data – available options

Create a Blueprint Function Library called something like CreateCharacterOptions – or whatever you like.

Creating blueprint function library

Inside this blueprint, we will start defining what options will be available for the character creation screen.

Defining the options for the character creation screen

We will start with simple GetAvailableRaces function.

Create a local variable here to store all available options for races. This local variable is of the TagStructure array type.

Inside this variable I populate all available races, for you it could be more, or less even.

For example, I have data for:

  • name = human (key for data structures etc, could’ve been just ‘h’)
  • value = Human (human readable name, to display in toggle widget etc)

Next, let’s create the available genders. The input variable here is Race which is a String and output is TagStructure Array.

Available gender options

The gender options above are based off race. You could just make it same as race where you just provide the options out, but some genders may be different. For example, what if you had a robot in your game as an option, it may not require to follow same structure as others.

In my case though, both human and dk have both male and female options.

Next is where it starts getting interesting.

Preparing options for hair styles

Hair mesh options

Here is where we start seeing and utilizing the power of composite keys.

We create a function for GetAvailableHairMeshes and the input for this function we have input of RaceGenderPair structure and output of Tag Structure Array.

Inside the HairMeshes variable, which is a Map of RaceGenderPair for key and OptionsArr for output, we define multiple options for hair meshes.

Have a look, the initial key is: race: human, gender: m (defined in options from previous 2 functions) and the value contains an array of valid options for this selection: h_m_hair_1, h_m_hair_2 -> h_m_hair_4.

Then you define the options for all other available keys, i.e. where gender is female etc.

Do note that your skeletal meshes and materials (typically color differenece) can be disjointed.

So for example, hair style 1 can have color 1 or color 2 etc.

This is also why you have skeletal meshes and materials on different functions, so below is one for the hair materials:

Hair material options

So in a very similar fashion, you have a variable for HairMaterials which accepts a RaceGender key and OptionsArr as value.

Then the hair material can contain values: h_m_color_1 which has user facing value of Blonde.

Handling skin

This part is also kind of interesting, as I combined multiple data points here.

Handling skin options

Note that in above, the key is the Race Gender pair as usual, and the value is also the Tag Structure Array. However if you look into the values, you will notice that I actually combine the data of race + gender into skin.

i.e. the race + gender is combined for the skin style.

Skin styles combine race + gender

This will be important as we will want to start aggregating some options as you get closer to applying these data to skeletal meshes. But you can do it many ways, this is just one of them.

Optional data

Finally we have some race/gender locked options. In this case I have human male beards

Facial features – beard implementation

Note that for the keys I only put human male. For human female I left it blank, and its effectively the same for my other race dk. The empty values will be handled in the widget.

Finally let’s cover Classes just for completeness.

Eligible classes

As you can see, you can actually make classes race/gender locked. E.g. in WoW where you have some classes only available to certain races.

Alternatively, you can simply remove the key and return all options to simplify this.

Back to Create Character Widget

Ok now that we have the data prepared, let’s go back to the Create character widget that was built in the beginning, this one:

Back to the create character widget

Let’s now start looking at the blueprints for this class, they will appear quite big and intimidating, but if we look piece by piece then will not be so bad.

First, let’s check the variables that I created:

Variables used in Character Creation Widget

The first part I want to point out, is that for each of the options we will have 3 variables. The options array, the toggle widget reference, and the current index that selection is on.

In retrospect, there’s a way to keep this cleaner. That is to have 3 Maps of <String, Object> where object is the variable type.

For example, I have RaceWidget of type ToggleWidget. I could instead have: Map<String, ToggleWidget> where the String key = "RaceWidget".

Note I specifically didn’t do this – I had it like that originally and it made my variable section a lot cleaner, however every time I wanted to use the variable I needed to fetch it in my blueprints, which made my blueprints look more complicated. So its a tradeoff, choose one you prefer.

Ok let’s start looking at the constructor. This is relatively long function, but is fairly straightforward once you understand what its aiming to do.

Constructor for Create Character Widget

Here it is broken down into three images just for better clarity.

event construct part 1
event construct part 2
event construct part 3

We can ignore section 1, we will be covering this in next post – it is spawning the skeletal mesh that we will be modifying.

In section 2 we get the available races and setting it to the local variable. Remember races did not require a key, its base data. Note that these are the functions we created in Preparing the data section.

Section 3 we get the genders. Remember we utilized the race as a key, which potentially you may not use. Again update/promote these to local variables.

Part 4 is important as this is where we create the RaceGenderPair key which will be used to reference other data options.

This is a local function created here by pressing the plus icon:

Create UpdateGenderRaceKey

We will go through all of the functions covered here eventually, some covered in next post.

The content of this function is:

Update Gender Race Key function

Simply put, you find the values from race / gender options based on current index of each and make the RaceGenderPair structure – setting it as a local variable.

The function for GetTagName and GetTagValue are as follows:

Get Tag Name function
Get Tag Value function

The GET is by ref. On UE4 you may not have ‘IS EMPTY’ which you can change to size > 0.

They’re very simple functions, but since we use them quite often in our blueprints, its much neater to refactor them into their own function calls.

Note that the return for empty is not really necessary, but it can avoid any unexpected error messages when data is missing. Empty data will be handled in several ways.

Ok now we can move to the next part, of creating the actual widgets for toggling.

Starting to look at the create toggle widgets

All of these create calls are custom events. Furthermore, they’re all relatively similar, so once you get the hang of one, you should be able to understand all of them!

Create race selection widget

Ok so it may seem like a lot is going on, but it can be split into 3 basic parts.

  1. Create the custom event for create race selection. This will only be called once. Its responsible for creating the toggle widget, we get the Tag Value (user facing value) from the RaceOptions variable (0th index as its initializing), that we populated in constructor. Set the title based on the selection, in this case Race. Once the widget is created, add it to the ScrollBox by calling Add Child function on it.

Note if the scrollbox is not visible in your variables list, go back to the designer, and ensure its selected here like so

Ensure the scrollbox is a variable

2. In the toggle widget we created 2x event dispatchers. They were for LeftClick and for RightClick. That’s what we see here for part 2, we created the toggle widget and using that reference, we bind to those two events.

3. Create two custom events, for LeftClickRace and RightClickRace. These are what handle the actual button clicks from the toggle widget. You will see that we have a function to Update Index , Resolve Changes and update all options.

Update index is a simple function to help us increment/decrement index. This is just to keep things neater as this functionality will be used in multiple places.

This was my implementation, I wonder if there’s a simpler way.. It’s really mainly adding or subtracting 1 from the index value. It also checks if the index value is going below/above allowed (i.e. can’t be -1 or larger than size of array).

Update index function implementation

Resolve changes – this function is updating the toggle widget. Remember that on the toggle widget we’re displaying the currently selected value. This function sets that up.

Resolve changes implementation

We simply get the array of options, the index and use the Get Tag Value function to obtain the user facing name. From the toggle widget, we set the current value (inside the toggle widget) and call the update value method, which was also used in the constructor.

We also call Update Gender Race Key function, that we covered few steps above. The main reason for that is that this universal resolve changes function can be called on any options, including race and gender. It can either be called here, or after race/gender resolvers.

Finally, Update all options is another custom event inside the Customize Character blueprint.

In this custom event, we call individual resolvers on each of the options which affect the appearance. I.e. race and gender does not directly affect the appearance, what it does is modify the hair options, the skin options, facial features, etc – then it gets applied to the mesh.

Update All options

The Update character appearance struct will be covered in the next post.

The rest of the options

The rest of the options past race actually follow the same principles. This is because we used generic components to build the functionality. The only additional piece is the ResolveGender, ResolveHairMesh etc.

Create Gender widget flow

As you can see, the Create<Widget>, LeftClick<Option>, RightClick<Option> are the same, but we also have a resolver here too.

CheckValidIndex blueprint

Furthermore we have 1 additional check in facial feature widget which we will cover in last screenshot.

And now we covered all the fundamental functions for the rest of the options, so here they are for reference.

Hair Mesh (style) widget
Hair Color widget
Skin widget
Classes widget
Facial feature widget

Note that on this one, after getting the available facial feature options, we check if the length of that array is larger than 0. If not, we hide this widget.

And that’s it! Hopefully you managed to follow along and understood the principles shared here, there’s a lot of data to go through but this way you should save more time long term as it should be easier to work with.

The next post will cover processing this data to decide the skeletal meshes and the material to apply to the character option.

Best of luck!

6 Comments

Comments are closed