In this post we’re exploring how we can ‘log into’ a game using a custom server.
This is continuation for character creation/selection screen covered here.
Specifically, it’s about the implementation of the ‘Login’ button and having the character enter the game world.
This will be split into few posts, and this will be part 1, so stay tuned for more!
The server used in this post can be found here.
Getting started – Login button implementation
First of all, design your ‘select character widget’ as you like and have a Login
button, that we will keep disabled initially.
It’s disabled initially as we don’t have a character available to ‘login’ with.
Now let’s look into the blueprints for this button.
What does it do?
- Create loading screen and add it to viewport
- Get the character motion, to know WHERE to load the character (map and co-ordinates)
- Propagate account character, to know appearance info to draw and the motion
- Open map that we want to load
Let’s go through all of this in order then.
Creating basic loading screen
I cannot stress how ‘basic’ this loading screen is – so design it as per your own requirements. In this case it will be a simple widget component which has a text ‘loading’ and a ‘circular throbber’ component.
Usually, it will consist of a large 2D image to display.
There are no additional blueprints for this widget.
So in above blueprints for ‘Login button implementation’ the first part was simply loading this widget.
Getting character motion
Depending on your server design this part will be different. Basically, you will want to find the APIs that you need to call in order to evaluate what map your character is in as well as the co-ordinates to spawn the character in.
For this purpose, I created an API on the server to ‘Get character motion’ which will return both, the map and co-ordinates of the character.
Let’s check how we can get this data via API. The endpoint for this in my server is:
http://localhost:8081/player-motion/<character_name>
I updated the create character flow to setup updated values for map name and co-ordinates.
These values will be updated through motion socket
implementation, which will be constantly updating characters motion in the game. This will be covered in next post as it’s a relatively complicated piece.
Ok great – we already load the character name and appearance as part of select character
screen and now we’ve also got the map to load as well as the co-ordinates to put the character into.
Propagating variables to next map
Ok so we’ve got the character appearance information, map to load and position we want to put the character to on the map.
What we’ll do now is put these variables essentially as ‘global variables’, so they’ll be accessible in the other map(s).
In order to do this, create a Game Instance
blueprint.
Once you’ve created this game instance blueprint class, we will want to set this up to your game.
To set it, click Edit -> Project settings
In the project settings window, you can quickly find it by using the search
functionality, just type in instance
and it should be one of the first options available.
Just set the Game instance class
to your newly created blueprint.
Ok now that you have the game instance configured, let’s add some parameters to this blueprint.
First, let’s define the two parameters that we haven’t created yet, Motion
and PlayerMotion
.
The above motion is what we’ll need when synchronising character motion in-game. For now we just need the map
, and the co-ordinates of where the character is at.
Next, we will have a structure for the PlayerMotion
.
Notice that the player motion structure references the motion
struct that we just looked at. The main addition is the inclusion of the player name
, but we also have the information of whether player is online. We may use this information to throw an error, but we will skip this for now.
Again, notice that these structures are directly mimicking the response object from the API:
{
"playerName": "character2",
"motion": {
"map": "dreamscape",
"x": 34723,
"y": -69026,
"z": -20121,
"pitch": 0,
"roll": 0,
"yaw": 0,
"vx": 0,
"vy": 0,
"vz": 0,
"isFalling": false
},
"isOnline": false,
"updatedAt": "2022-10-19T15:43:10.038Z"
}
From above, we can see that we reference all the relevant pieces of data that we care about.
Ok with the structures created, let’s add them as variables to your Game instance.
You can see I created two variables in my game instance:
- AccountCharacter
- PlayerMotionSnapshot
Notice that I’ve left them as private params. You can either make them public variables, or keep them private as I have and create basic functions for the Getters
and Setters
. It’s better practice to have the explicit getters/setters, but it will not have a functional difference.
Example for the setter:
Example for getter:
Get character motion in blueprints
In this part we’re just making the GET request to obtain the characters motion – this is the same request which was displayed in the POSTMAN request.
With the response, you want to parse it into the structure, (optionally) promote it to variable and importantly set it within the Game Mode instance.
And the helper method to create the motion
can be found here:
Now we have both, the selected character object, with appearance data as well as the player motion, indicating where to spawn the character.
Opening map
In order to open the map, you want, it’s very simple. We use the function Open Level (by name)
.
In my case, the motion structure contains the map name – so I can use that to specify the level to open.
If you have just 1 map, you can open it using static entry.
Enable the login button
Ok now that all the pieces are in place, let’s enable the button when a user has a valid character selected.
In our case it’s pretty simple – it’s when we render a character, which already does the checks to make sure a character is available to render.
Test loading the map
So now we have a character that we have selected:
When I click the login button, I will have a brief Loading screen pop up:
I’m also able to verify that the response from API is received as expected.
After short delay, my character is loaded in the map.
In the post we will look at how we can change the character from the default one to the custom character that we have.
Setting character
In the above screenshot we can see that the character loaded is not the same as the one from character selection.
We need to modify the selected character using the Game Mode
. To do this, create a new blueprint class with parent Game Mode Base
.
I called mine MainGameMode
. It’s very likely this game mode will be used throughout many maps.
In this Game Mode blueprint, we can configure the player controller and other settings which will be applied to the map.
So, first thing, let’s prepare the character blueprint that we will be using. I will assume you have a character asset prepared, which perhaps you downloaded from the marketplace store.
I have a collection of them available:
Let’s copy one of them, in which you will make it the main blueprint for the character.
Ok now you can go back to your Game Mode
blueprint and set this up as the default pawn class.
The player controller class can be third person or top down – or whatever you want it to be. These steps are agnostic to the methods of you controlling the character.
Let’s now link this game mode to your map – open up your map and find world settings
menu. If you don’t see it, click Window -> World settings
from the top menu bar.
If you click play now – you should load the desired character.
For quick experimentation, you may want to alter the camera on your character blueprint.
Later we can configure a better, more flexible camera option, for now we just want to get something working.
Dynamic spawn and appearance
In the above, we spawn the character, but its still static. We need to:
- Make the character appear based off where the server tells it to
- Apply the appearance mesh from select character screen
We can do this by obtaining the information from Game Instance
that we prepared earlier.
These changes will be easier and better to apply in the construction script for the character.
Spawning at location
The location obtained here is the one that was covered in screenshot titled Parse the data and send it to MainGameInstance (promote to Global Variable)
.
We can click start and try the game to see if the changes are applied:
This looks great – we now have dynamically set location based on last recorded position.
Changing appearance dynamically
We’re now going to be re-using the blueprints we created for create character
component. Unfortunately, the other blueprint had to be skeletal mesh
class, so we’re not able to re-use the components right now – there is a way, but I will go with the dirty copy and paste method.
The way for reference, is to create another base class, which will have this functionality, and have the two blueprints inherit them. Perhaps this is an improvement I will make in near future, but for now I just want to get something working quickly.
Inside that blueprint, we had code on the constructor:
As well as the resolvers:
On the bright side the resolvers are separated in a graph, so I can copy the whole thing over. Note that this is not good practice. It’s better to create a class which both can inherit and use, as in this way, every time a new component is introduced, we may need to add code in two places.
If you don’t have these resolvers built yet, they were covered in this post.
After copying the pieces in place, adding the variables in and potentially dealing with some component renaming, this is what we come to:
The main additions is to pull the game instance again and get the character info from which we obtain appearance structure. Then we call the method to resolve all appearance.
Also, I did have to modify my refresh animation
function to this:
This now updates the animation blueprint to use either male or female animation class.
Entering the world as the character
Now if we go into the world as character 1:
After clicking Login, this character will enter:
Next if I log into the world with another character:
Then the second character will appear as expected.
And that’s it for this post!
In the next one we’ll look at synchronizing motion.
As always, best of luck with your projects!
Pingback: 26. Unreal Engine – synchronize motion with a custom server – The web tech journal