So I spent all of yesterday putting preferred character selection together and I’m real proud of it ’cause I had to come up with all this logic myself so let me show you it.
If you follow the official Unreal Multiplayer tutorial, you end up with situation where you spawn into the lobby as an invisible base character. This character has all the functionality of the playable characters. In fact, all those characters are child blueprints of this character, but obviously they have visible models. Anyway, you spawn in as this invisible character, but your Ready button is disabled until you switch to an actual character through the character menu.
Now, I like being able to switch characters in the lobby and I’m leaving that functionality in. I think even with preferred selection, sometimes even established crews would use it to try out new characters. Moreover, sometimes when you’re playing with randoms, it’s nice to just be able to negotiate for characters. Plus, it minimizes having to wait for Certain People leaving and rejoining to get the character they want if their three preferred ones are taken.
Nonetheless, I think people generally do prefer to just spawn in as the character they want instead of having to fight for it so preferred characters was a feature I wanted.
I made it happen and here’s how you can too.
You start with your PlayerInfo struct. A struct is kinda like an array, except you can put all kinds of variables in it instead of just one type. Here is the one I currently have for PlayerInfo.
At the bottom there, you’ll see my preferred character slots, which are integer values. Each character has a ID number, so that you don’t have to use a character class reference for everything. In this case, 0 = Cairo, 1 = Dixie, and 2 and 3 are our remaining heisters. If I add more characters later, they will be numbered 4 onward.
DEVELOPER NOTE: Do note that I’ve changed the CharacterID values from what the original tutorial had: 0 was originally for the base character, but I don’t want my players to be able to access that character so I shifted the values down by one. This is important to know for a few adjustments that had to be made later. You’ll also need to go to your CharacterSelect screen and remove the Deselect Character button and change the values on the Set CharacterID nodes off your OnClickedButton events. Also, if you follow this process, you can make the base character’s mesh visible by default. As is, any time you make the mesh visible for editing and then set it back to invisible, you have to go through all your child characters and set their meshes back to visible.
Since I don’t have the menu for assigning these values built yet, let’s just assume you like Cairo, Dixie, and Character3 most in that order, like in my struct here.
In your Lobby Player Controller (PC_Lobby), you’ll want to make a PreferredCharacter array of the integer type and build this function:
What this does is collects each of your preferred character ID’s and puts them, in order, on a list.
Now, still in PC_Lobby, make a boolean variable called PreferredCharacterAvailable (unchecked) and another function called GetSpawnCharacter. It should look like this:
Yeah, it’s big. I’ll walk you through it.
So first off, you cast to the Lobby Gamemode (GM_Lobby) and then you get its values for AvailableCharacters. You use the GM’s values, which have default values, to set the PC’s which don’t. Those values, which you may need to change per the dev note above, should look like this:
All the boxes are checked, meaning all of the cooresponding characters are currently available.
DEVELOPER’S NOTE: I also reversed the true/false values for this array because the way the guy did it in the tutorial, he set the variable to check true if the characters weren’t available. It just made more sense for it to check true if they were.
Now that you have your AvailableCharacters, you want to run a loop to check each of your preferred character id’s against it to see if they’re available. That’s this part of the function:
The PreferredCharacterArray has three values in it, corresponding to your characters. This loop checks each of them in the order they were added to the array, to see if they are in the AvailableCharacters array (which they all will be regardless) and then asks if their current bool value is true. If it isn’t (because someone else is already that character), it does nothing and checks the next value on the list. If it is, it sets that PreferredCharacter variable to true and moves on to this part of the code:
Now, nine times out of ten, one of your three is gonna be available and that PreferredCharacter bool will check true, so it takes the integer value that it hit upon and changes the SelectedCharacter variable to whatever that is. Then we run the CharacterAvailabilityCheck function, which you should already have.
DEVELOPER NOTE: It was originally called CharacterCheck in the tutorial, but I changed the name to be more descriptive.
I’ve made changes to that function though so let’s take a look at that real quick.
DEVELOPER NOTE: Obviously I took out the conditions if the CharacterID was 0, since that’s not for a special case anymore and I swapped the check boxes on the Set Array Elem nodes. I also changed the default value of PreviousSelection to 999. If you leave leave it as 0 and you spawn in as the first character in your AvailableCharacter array, it doesn’t disable that character’s button in the CharacterSelect screen, since the function would make 0 unavailable, and then immediately make it available again.
Basically this function checks if your SelectedCharacter is in the AvailableCharacters array and if its value is true (that it is available), and then sets that value to false. It then takes your PreviousSelection (which in this case won’t have been set since your initial spawn into the lobby bypasses the function where it would be set) and sets that back to true. This is for when you pick a character via the selection screen, so it re-enables the button for the character you switched from. From there, it gets the array of Characters from the GM_Lobby, selects the one that corresponds to your CharacterID, and feeds that into the AssignPlayer function.
Getting back to the GetSpawnCharacter blueprint, after CharacterAvailbilityCheck enables/disables the appropriate CharacterSelect screen buttons, you get the Characters array from the GM_Lobby, check your SelectedCharacter value against it, and it gives you the correct Character class, which you can then feed out of the return node.
From there, in GM_Lobby, you just add a Character Class input to your RespawnCharacter function, and change the end of your Event PostLogin function to look like this:
That runs your two new PC_Lobby functions and gets the character you want, then feeds it into the RespawnCharacter function, which only runs when you first join a lobby.
From there, you change the class in the SpawnActor node from your base character to just Character, link the character class node from the event node, and you have automatic character selection!
But what if all of your preferred characters were taken? There’s a 25% chance of that so let’s go back to GetSpawnCharacter.
In the event all your characters were taken and therefore the PreferredCharacterAvailable bool checked false, we move on to this part of the code:
Now at this point in my game’s development, since I only have four doods, I could get away with just telling it to find the first true value in the AvailableCharacters array (since there should only be one) and call it a day. But since I like to think that eventually I’ll be adding more characters, I would therefore like this part to be random instead of selecting the first one on the list (as that would always spawn one of the first four characters).
So what I have it doing is running a loop where it randomly selects a character from the AvailableCharacters array and checks if its value is true. I’ve given it 30 attempts to find the one value on the list that should be true. Once it finds a true value, it breaks out of the loop so it only runs as many times as it needs to. All of this happens in less an than a second. There’s a minuscule chance that in 30 tries it won’t roll that last available character and the last player will spawn into the floor and have to manually select their character, but it’s way unlikely.
DEVELOPER’S NOTE: A more optimized and surefire thing to do would be to separate the values in the AvailableCharacters array that are true and then select randomly from that, but I don’t know how to do that without making a separate array. This method works well enough since 30 is a relatively small number of times to loop, while still being high enough to be nigh impossible not to get the result you want. That possibility of failure only gets smaller as more characters are added.
One it gets its “random” available character, it follows the same process of enabling/disabling character buttons and assigning the character to the player.
And that’s Preferred Character Selection. From here, you just have to build a menu that lets your players change the integer values on the PlayerInfo struct, which is no big deal.