Submission time is almost here. Two and a half months into this project and I'm quite satisfied with the results, even though I wanted to do a lot more. Setting up dedicated servers took a while. I also wrote a blog tutorial on this process. I set up a client P2P system as well, where the game uses Steam's "Spacewar" port(480) to host lobbies. The game uses Steam to get your username which is displayed in-game, and is also used to display your server's name.
So since the last blog, one of the designers provided the 2nd level, and after a few discussions with her, the final iterated version was added to the game.
Preview of the 2nd level, pardon the quality
It has different traps and obstacles. For starters, some fairies shoot at you which makes your controls reversed for a brief period, and then there is a river where you can't drown, but it slows you down. Then we have some simple rock obstacles which you can't jump over but your horse can. That's right, there are horses which you can mount on and play rush through obstacles riding them!
I added a spectating mode for when you reach the finish line, and that was pretty simple to implement. But going into the next level, keeping track of the unqualified players who would directly go into spectating mode, was a painful process to implement. I created a boolean to do that, and since the players disconnect to reconnect and travel to the new level, I use Unreal's Player state class to fetch the old values after reconnecting.
This is the code that does it. My Player State blueprint is derived from this C++ class.
And for some reason, it did not seem to work. So I spent hours trying to fix this issue, debugging, and logging, and nothing seemed to work. Then I tried adding some delays, and (I'm not 100% sure about this) it worked. I didn't sleep much so I don't really remember what else I did but it worked and I wasn't going to touch it again. Classic programming right; If it works don't touch it.
Finally, I use this boolean at the beginning of the game to see if they did qualify to play the level, otherwise, they go into spectator mode. The bool is true by default and is set to false when you are one of the losers.
Then when spectating, I loop through the players and check if they have finished(reached the finish line), and if they haven't I add them to the spectate-able(there is no word for that) players list.
Some of the other things I did:
knockout/stun players when falling from a distance
shooting fairies
horse riding
handling logic of getting hit by fairies and boulders when riding a horse
end screen displaying the winner
updated all the UIs
added a glowing effect to the pickup items
lots and lots of bug fixing
A little bit about the horse riding mechanic: I created the horse class deriving from the ThirdPerson class which is also used for the actual player, and where I was doing most of my player logic.
The Horse Header file
I also overrode the Jump and Move functions to cater to the horse movement. Basically the horse cannot air maneuver and can only jump when sprinting, and there is a small delay before jumping which is like the horse planting its feet and doing an explosive jump with a forward push.
The overridden functions
When the player is near a horse and they press the interaction key, they mount the horse and in doing so get attached to the sitting socket of the horse skeleton(which is defined outside).
The controller of the player possesses the horse and before doing that, the OldPawn is saved which is the player's pawn, to repossess it after unmounting the horse.
Since the horse is a child of the ThirdPerson class, it inherits the movement functions so I don't have to do the movement code again. But I do modify the speed of the horse in the child blueprint which is used in-game:
And I also set different colours on spawn, because why not.
The horse asset came with a few animations with which I created an animation blueprint, but it didn’t have any jump animation so I just used the gallop animation and slowed it down, and it actually looked decent!
This was by no means, a perfect horse controller implementation, but it's somewhat good enough for our game. I would love to make a horse controller, if I can find all the required animations, and implement them according to the movement direction(like strafing or turning around, adding slowing down like a natural horse and not coming to an immediate stop), like how it is in games like RDR2 or The Witcher 3. I think I will work on it after submitting this project, I really enjoyed it.
For the river, I used the experimental "Water" plugin from Unreal, which works great in simulating fluids, along with player interaction(player moving through the water, creating ripple effects). There are different water bodies, among which is the "WaterBodyRiver" which I used. I made some custom logic for the player and the horse, that if they are touching the water, their movement speed is slowed down.
The plugin has a spline structure, and you can modify the spline points to create your river. For our level, I made a simple rectangle-shaped river.
Then we have floating and moving rock-shaped platforms, which help the player reach the finish line. I just used my old platform blueprint which I created for the 1st level, and changed the mesh.
Level 1 Platform
Level 2 Platform
This was a simple blueprint I created which has two transform positions it oscillates to and from.
Finally, I did some database-sided things I had to do. We don't have fixed values for player's winning, losing and playing XP just yet, so I implemented the functions required to update these values with some default values for now.
PlayFab offers cloud scripting where you can define your own functions to trigger your implementation and it is a great way to update player statistics.
One of the functions I defined to get player experience
Then, over at Unreal, I created a custom event to call this function. It receives the result and sets the XP.
This was also done for tracking the number of wins and rewarding XP whenever desired.
For example, after a round is over, the following logic is run, and XP is rewarded based on whether the player qualified or not.
1000XP for winners and 500 for losers
We initially had planned for 3 levels, but the 3rd level was never provided, and I delegated the implementation of the 3rd level mechanics to my other programmer, so I have no idea if you'll ever see those. But we have 2 playable and complete levels now. All that's left is to playtest and fix bugs.
After submission, I will try to complete the game and upload it to my itch, and hopefully, you can try it out!
Creating my first Unreal multiplayer game was an incredible experience. I learned a lot, encountered struggles, but most importantly, had a lot of fun along the way. I have a very much better grasp of multiplayer programming now, and this is definitely something I would like to do more of in the future.
Sure, there were moments of frustration, like setting up those dedicated servers and wrestling with Steam for lobby creation. But hey, that's all part of the fun, right? From tweaking traps and obstacles to tinkering with horse riding mechanics, every step taught me something new. And let's not forget the late-night debugging sessions – because who needs sleep when you've got code to conquer?
As we near submission, I'm feeling a mix of excitement and relief. Sure, there are bugs to squash and tweaks to make, but seeing this project come together has been a blast. Can't wait to polish it up post-submission and share it with the world.
Cheers to the journey, and here's to many more multiplayer adventures ahead!
Comments