Improve My Game Jam 33 DEV LOG Shinobi Tennis UE5 Multiplayer
Shinobi Tennis: Improve My Game Jam 33 DEV LOG
My goal within this game jam was to get my game from local multiplayer to online multiplayer so that anyone can play matches online. Therefore, this is going to be what I will be going over in this devlog. I've split this up into a table of contents so that the information I share can be broken up and easily accessed. Thank you for reading!
Table of Contents
- Overview
- Widget Setup / Hosting and Joining sessions
- UE Game mode, Game State and Player Controller Replication
- Player Blueprint Replication
- Tennis Ball Replication
- Additional Replicated objects
- Conclusion
Overview
The notes I add here will be mainly for the Improve My Game Jam 33 with a bit of information I picked up about how to make your Unreal Engine game multiplayer. This is done in my game via the advanced sessions plugin utilizing a client-server model. There's quite a bit that goes into this but it becomes simple when you break it into pieces. I won't be going into detail about how the client-server model works but will explain how its done within my game. This will be broken up into pieces so it's a bit easier to digest and anyone interested can come back and look at specific points. I will also try to add as many screenshots as I can on how my blueprints were set up but I may miss something. If anyone is curious feel free to reach out with questions on how my blueprints were set up!
Shinobi Tennis is a simple action tennis game. The main blueprints the game has is one blueprint(BP) for the player and one blueprint for the Shuriken. For the sake of simplicity, I'll refer to these as PlayerBP and BallBP. These blueprints along with a few in each level is all that needed to be replicated for multiplayer to work. I originally built out the project to get it working with local co-op, then converted the BPs to work with multiplayer throughout the jam. This is what I will be going over in this log. I wills tart at how the widgets are set up because that is what holds the logic for creating and joining sessions.
Widget Setup / Hosting and Joining sessions
The crux of this section was heavily aided by this tutorial here. This tutorial series by Kekdot is fantastic and explains almost everything that goes into setting up a client-server multiplayer game within unreal engine.
The main menu setup I have is a level that shows the widgets for creating, finding, and joining matches.
Again I wont go into specifics here on how to create these as the tutorial goes over them but I modified it a bit to fit my game. Within each one of these buttons on click houses the logic for how to create and join a game. Here is the BP logic I made for creating and Joining sessions
Here we have a widget for creating the game, finding a game, and an item widget to show each game that's been created to allow you to join the game.
Tech Notes:
A couple of things to note here. In terms of widgets when using a client server model, Before joining, all players games will be the server. This means that you can use Get Player Controller to get the player controller at the index 0. There will be other cases (when the player joins a session) where you cannot use get player controller at index 0. In that case you will need to use Get Owning Widget and you will need to make sure wherever you are creating that widget you set the owner to the correct player. We'll take a look at an instance of this later on.
Additionally, you'll notice that I'm using advanced sessions instead of the default sessions that UE provides. This is to allow us to connect our game to steam so that we can use steam to have online multiplayer.
That's mainly the setup on the widget side. When things get tricky is converting your blueprints to handle replication from the server to the client. I'll try to go through it in as much detail as possible. I'll start with setting up your game mode and your game state as that helped me a lot with understanding how UE replication works and what's the best way to replicate data from your server to your client.
UE Game Mode, Game State and Player Controller Replication
The game mode, game state, and player controller are essential components to building games within unreal engine. Having good knowledge on how these components work, especially with replication, can really help make things easier for you when developing your games and save you from running into bugs and replication issues. I'd love to explain how they work in perfect detail but I'm still learning them as well. I would say the best way to learn is to try to make a multiplayer game as that will help you understand the concepts as you go. I'll start with the game mode.
For my Game Mode, I didn't use the event graph, however there is a lot of very useful functions within game mode that you can use to do things like, check if a player has logged in or logged out of the session and send that data to the Game State. It also holds all of the information about your classes as seen in the image above. Here, the main things I changed are, adding the custom Game State, adding a custom Player Controller, and removing the default pawn class as I wanted the players to be spawned within a character select widget(this was a real pain to figure out). With that being said next we'll go over the Game State.
My Game State was relatively simple as well. Here Initially used the event graph to check for the number of joined players so that I can set the game ready variable, indicating that the tennis match was ready to be played. However, I realized that if you are using a character select screen, The client player will join the session but they will not instantly be ready as they are picking their character. Therefore I had to move the logic for this check to when the character is selected. Even so, The Game State is an integral component a multiplayer game. This is by far the simplest way I've found to replicate and house data within the server that the client can also use.
There are a few different ways to pass data from server to client: replication, repnotifys, and using the game state to name a few. In my experience over this jam I feel that using the game state is the easiest way to hold this information. There may be other ways that more benefit your specific needs but this method worked for me. Each one of these variables holds data that I can then use for the server and the client. Training holds information for if we are in the training map or the main map. This controls which widget shows, the score board or the training module. The p1 and p2 score variables hold the scoring for the match. Game ready and player can attack hold information on when p1 can attack the ball, this waits on p2 to join the session and select a character. Theres a few other variable here but they all do pretty much the same thing. The game state stores this information and it can be used by the server or the client. BPs like the Game Mode do NOT have information that can be used by both the client and the server. I found that out the hard way. We'll see more uses of the game state as we move into the playerBP and the ballBP's event graphs. I hope that covers mostly how I used the game state, if not, feel free to leave a comment and I can assist further. Now I'll move on to the Player Controller.
The Player Controller is a very versatile blueprint. I've had a few iterations over the week with this controller but this is what I landed on. I wont go into each function used, but this Player Controller houses a cast to the game state so that we can get the information on both the client and the server, an event dispatcher(this is called within the character select widget and a bind to spawn the selected character), and the creation of the character select screen once the server creates the game or the client joins the session. I'll now go over why I put this logic in the player controller.
The main reason I put this logic here is to handle the character select screen. I really wanted to add multiple players to my game to give the game a bit of character and let the player have some choice in the game. Even though the characters handle the same. It's funny how my play testers said they felt as if each character felt different and each had preferred characters. It really added some character to the game. However, it was not that simple to implement. Inside my character select widget I have multiple buttons showing the character. Once those buttons were pressed I wanted you to be able to select that character and have them spawn at the p1 or p2 spawn point. This meant that I would have to dynamically spawn these characters. I first tried to spawn them from the widget but realized that I would need information from the server. This caused a problem as I was unable to get information from the server within the widget. The best way I could get that information from the server was through the game state, and the best way to access the game state was through the player controller. Coming back full circle, I added an event dispatcher on the player controller that could be called in the character select widget. Then I could bind to that call in the player controller and each time a character is selected, spawn that character. This worked out well! That's all I used the player controller for in this game but I'm sure there are a lot of use cases for this BP and I may use it again when I add more game modes to the game. We can now move on to the PlayerBP which holds most of the BP logic for replication between the server and the client.
Player Blueprint Replication
There are a lot of replication techniques that I learned during the process of creating and replicating the Player BP from server to client. I'll try to go over as much as I can but this will vary from project to project so I'll mainly go over examples of how I replicated certain features of the character within the event graph.
There's not much that goes into the playerBP but there are some specifics that I want to point out. Firstly, I made this game before starting to add multiplayer so a lot of the logic I had in place was not suited for replication. I think if you plan on making the game multiplayer, you may want to prototype with multiplayer in mind. Otherwise you may have to go back through and modify certain points within the BP. I ran into a lot of walls trying to get replication to work for the player controller the right way, some of those walls were due to lack of knowledge and some were due to the fact that the way I originally had the playerBP just didn't work with replication.
Tech Note:
One thing to point out right way is the replication on the actor itself. Each actor in UE has a replication section within the details. This will handle the main replication for the components. It is recommended to NOT check the component replicates checkbox within each component.
This will lead to bad things. For my case it lead to my player on the client side skipping around the screen when moving. It took me a while to figure out that it was due to me checking this box and not due to lag. Make sure only the actor and the replication tab is checked. Another thing to note is that checking always relevant within the details can also cause issues with movement so I'd recommend turning that off as well if the BP you're replicating is the player being controlled.
The playerBP has 3 event graphs, the default, one for movement, and one for combat. This is just to keep the graphs clean. in terms of replication the default event graph only handles the begin play function and the setting of the camera.
I attached two cameras to the playerBP. I then replicated the camera for P2 to be a multicast so that the when the the client is spawned, it uses the P2 camera. This is because my game uses 2d sprites and therefore the easiest way to see from the p2 side is to switch the cameras.
The next replication that's done in the default event graph for the playerBP is the updating of the score. This one is very simple.
All that's done here is setting the score that's passed in updated score to the gameplay Game State. This allows the Game State to hold information on the score so that both the server and the client can have access to them. Since this is a smaller game I'm just binding the score to the score board widget. It is advised that if you have a larger game you should use an event dispatcher instead of binding to set information on the widget as when you bind it calls every tick and can be very expensive. Next up is the Movement event graph.
The main replication logic within the movement graph is within the input move action function. To keep a long story short, the component get last input vector is not replicated by Unreal Engine. This is a real pain and it would be really nice if it was replicated! Unfortunately, it isn't, and I need to get the last input of the player so that I can handle logic on what direction the ball should be hit. Fortunately, we get the action value of the movement from the input move. All we have to do here is replicate it ourselves. This is a good example of how replication is done within UE graphs. Here I'm calling a custom event Sever_StoreLastInput. This event, in the details section, has Run on Server selected. This event then calls another custom event Client_StoreLastInput. You could also call this Multi_StoreLastInput. This event in the details does a multicast to both the server and the client to pass the information of the last input vector. This event then sets the last input vector variable. The last input vector is also set to replicated in its details panel. With all of that done we now have the last input vector before the ball is hit replicated! I then pass this into the combat event graph so we'll move there next.
The combat event graph handles the attack of the player. At the top, we handle the attacking input with logic for attacking. One thing to note here is a handy macro Unreal gives us for checking if what were calling is on the server or the client. In this case, I don't want the client to check if training is true because the client will never be in the training map. Therefore I do a switch and don't do this check on the client. I then do the same server to multicast for the attacking logic so that the attack animations play correctly on the server and the client.
Below, I'm checking if the hitbox of the player collides with the ballBP. This is toggled on and off via the animation notify. The logic is held here. The only thing to note here is that we are passing the last input vector that we set in our movement event graph so that we know what direction the ball is being hit. This ended up working out great and allowed the player to have smooth decisions on where they wanted to ball to be hit on the court. I've learned that giving players the benefit of the doubt, the cleanest movement, and the most choice I can possibly give them has helped the most in terms of player enjoyment. Especially in action games players do not want to feel like the game is the cause for their failures. With that being said that's pretty much everything replicated in the playerBP. Now we'll move onto the ballBP where we handle a lot of the physics calculations. I won't be going into those physics calculations here because they don't have much to do with replication. I will be touching on a few things that needed to be replicated within this actor like effects and sound.
Tennis Ball Replication
The tennis ball (Shuriken) is actually quite simple in terms of replication as well. I also had a bit of a better understanding on replication from my previous mistakes so this replication went a bit smoother.
Only a few things to note for the ballBP in terms of replication. First, before when we spoke about the player I noted that I turned always relevant in the details panel off. Since the shuriken is a physics-based object and constantly moving dynamically, setting it to always relevant helped the ball travel smoother on the client's side. Next is the replication for the sound FX, and visual FX. Since I was using 2d effects for some of the ball FX, I made them into actors to play a flipbook. Therefore, I did the same server to multicast logic but the spawned the actor with the effect. I may be missing something on the shuriken but I think that's pretty much most of what needed to be done on the shuriken side. A lot of the replication that I did have on the shuriken was no longer needed once I implemented the game state. All of these BPs have access to the game state so I was able to get the game state and get all of the data I needed to get a set from server to client.
Additional Replicated Objects
I wanted to add this chapter to touch on a few things I may have missed. For starters, I wanted to have spectators in the background watching the match and getting excited as the game gets more intense. I wasn't able to add that feature in time but I was able to add a feature in so that they could be hit by the shuriken and die in the background. I find that hilarious. This feature needs to be replicated so I will show how that was handled.
This is the same logic we used in our other BPs. We make sure that the details are set for replicates and replicates movement. It's possible only replicates is needed here. Next, we use our same server to multicast logic to set the flip book which plays the death animation for the spectators.
Conclusion
At the start of this Game Jam, I knew nothing about replication or even the difference between a dedicated server and a client-server model. I didn't know how replication was done at all in unreal engine. Through trial and error, I was able to take my game from an idea to completion and was able to make a fun game that I could play with my friends online. All without releasing the game or buying a dedicated server, it was completely free. Unreal Engine and Steam have amazing services that allow us as game creators to do things that would have been extremely difficult to near impossible a few years ago. I'm really happy that I took on this challenge and I hope that anyone who reads this can utilize the information I learned to make fun games for their friends as well! If I missed anything feel free to reach out to my email, twitter, or even just post in the comments section. Thank you!
Files
Get Shinobi Tennis
Shinobi Tennis
Deadly ninja action tennis game where the ball is a shuriken and you play for your life.
Status | In development |
Author | KyushaGames |
Genre | Action, Sports |
Tags | 2D, 3D, Casual, Fast-Paced, Multiplayer, Pixel Art, Retro, Tennis |
Leave a comment
Log in with itch.io to leave a comment.