Engine: Unity | Genre: Puzzle Platformer | Platform: PC | Timeframe: 3 months
Overview
Interstellar Moving Company a game made in Unity, was a bit of an ambitious project that me and other classmates had decided to tackle over the summer break away from school (We did not know what we were getting into haha...).The game was very much inspired from the hit game Lethal Company, so we wanted to include online multiplayer into the project. Before this project I expressed my interest in learning how to incorporate networking into games, so I was tasked with everything related to online multiplayer.
This was my very first experience with implementing online netcode, but I was passionate and ready to learn and implement as I went along throughout the whole project. Let's run through a bit of the design of the game, because I would like to give you an idea of what I was working with and the challenges that would come in trying to make online multiplayer work with the design that I was given.
Interstellar Moving Company was a game where up to four players would go from different alien based locations to help a client move their possessions out from that area using a grapple, since the client is in the processes of moving to a new location. Great we have a simple idea so far, we move junk out of a specific area (level) and once we have reached a certain quota of moving the objects to their designated spot (or moving all the objects to the designated spot) we would be able to clear out our tasks and potentially move on to the next level.
Let's now talk about how the players interact with the world, because this is where a lot of problems come from when trying to implement the gameplay design into an online multiplayer format. The objects in the world that the players have to move to a designated spot are physic based using Unity's built in physics system. The players are physics based using Unity's built in physics system. Now here is the interesting part of the design, each player has a grapple, which they would use to grapple to specific areas to reach certain spots that wouldn't be possible to reach otherwise and how would they do this they would pull themselves there using the grapple, yes I said pull. Along with pulling themselves they could swing with the grapple by just attaching the head piece to a wall for example and the grapple would stick to that position and the player would then be able to swing back and forth with their grapple. Not only that the grapple would be able to extend and detract, So the length of the grapple can be changed on the fly... ok. Remember the objects we have to move to a designated spot? we would use the grapple to move around these objects in the world by connecting the head piece of the grapple to the object and with that you can then pull/move that object within the world. The grapple is also using Unity's physics by the way. How would we extend and detract the grapple in this design? We would use joints that would be connected to the head piece of the grapple and guess what all the joints are also using Unity's physics!
Now that we have cemented that everything that is interactable in this game uses Unity's physics system, we can move on to the breaking point of the design, basically where everything falls apart. There are a few things I would like to go over before I talk about what broke the "camel's back" one could say, basically things I got working surprisingly even though everything that was interactable in the world used Unity's physics system. This is where I talk about ownership and how we move objects across the network so that they are synced up properly with the host. Since the host holds the true state of the game, we need to make sure that all of the clients are synced up properly with what the host sees on their screen, so that there aren't any discrepancies between all clients.
Syncing up movement of the players over the network, worked as intended and this is because only one client owned that particular object. The client would own their own player object, so wherever they moved that movement data would then be sent to the host and then it could easily be synchronized properly across all clients. Great, we are happy campers now we can see our friends move in our game world and all of their positions are synced up properly!
Now Syncing up the grapple state, oh boy this was a challenge... Though the grapple state did end up getting synced up properly across all clients, which In all honestly is an achievement in itself. Let's go over why it was difficult, the grapple has many different states attached to it and speaking of attachments the grapple has all those joints attached to it that we also had to worry about... The grapple and all the joints connected to the grapple head piece were owned by the specific client that was using the grapple, since each player could instantiate one into the game world. The grapple would have different applications attached to it, pulling the player to specific position, allowing the player to swing around while the grapple was attached to something for example a wall, moving around a moveable object that the grapple was attached to, and extending and detracting the length of the grapple. Oh boy I don't know if you see the possible issues that we will have in syncing up everything properly across all clients. Though to keep it in simple terms we need to make sure that all the joints and head piece of the grapple are instantiated properly in the correct order, so we needed to make sure that we wait for each piece to be created and synced up properly across the network, in hindsight... we should have used object pooling for this, so we didn't just instantiate the grapple and its order of joints every single time. It probably would have been much easier to manage to order of things in terms of the grapple... Though moving on we also had to make sure that extending and detracting was synced up properly and making sure that was also done in order, this also required for us to wait until everything was resolved, so that everything would be synced up properly across all clients. You probably get the point by now, the grapple and everything to do with the grapple had to be carefully done, so that there was no discrepancies of how it functioned across all clients.
Now let's talk about what broke the "camel's back". So as I mentioned above in this game you are able to attach your grapple to a moveable object in the world and with that you are able pull the object around, so that you are able to move it to the designated spot. Now here is a question what if you have two or more grapples attached to that moveable object, who owns the object? We were able to sync up movement of that object properly when only one grapple was attached to that object, since we could easily specify ownership of that particular object. For example If client one attaches their grapple to the moveable object, the ownership of that moveable object would change to client one, so that we could easily sync up the position and how that object moves across the network. We do this, so that the player doesn't feel delay to the point that it feels unplayable. If only one client owns a object and moves it around the world, we are able to sync it up correctly across all clients with minimal delay, so that the player has a good playable experience.
Though back to our question... What if two or more players have their grapple attached to the moveable object, who owns the object? You might say "oh why can't each player just own the object?", You can't do this! Unity has it set up like this for a reason where only one client can own a object at a time. They do this so you can sync up the object properly in the game world. Imagine two or more players are pulling a physics based object, using physics based grapples, while using Unity's physics system. This is a recipe for disaster. How do you calculate everything that is happening in terms of physics (while using Unity's physics system) when two or more players are interacting with the moveable object? You can't and this is partially due to how Unity's physics system works. There is no easy way to access what is going on under the hood within Unity's physics system. Since we have no easy way to access that information we can't properly sync up what is happening in terms of two or more players trying to move a particular object in the world at the same time and if we try to everything just falls apart and synchronization across all clients breaks.
I tried various methods of how I could get around this ownership dilemma for example I tried to only have the host own all the moveable objects in the world and the other players would only apply some forces to these objects, while this worked the delay was substantial and it just felt unplayable and the forces that I was sending out just didn't feel right since it wasn't naturally just coming from what Unity's physics system does on it's own. I tried changing ownership on the fly based on distance of player to the moveable object, basically a first come first serves approach where if a player is within the distance of the object they wouldn't lose ownership of that object even if another player came within that distance. I tried to then fake physics if a player that didn't own the object interacted with it. Though again everything I tried just felt unnatural and in terms of the player experience it just wasn't good.
So what is the solution to get around all these issues? Don't use Unity's physics system in this manner! You will only go crazy... trying to make it all work. Using Unity's physics system in this manner, just isn't worth it. If you build your own physics system and have complete control of what is going on, I see that being a ton easier to manage and you should be able to sync up everything properly as long as you have complete control of your own physics system. That being said should you even try to design a game like this and even try to incorporate a physics based experience like this across the network? sure as long as you are prepared for the challenges that you will encounter along the way and as long as you create your own physics system from the ground up, so that you have complete control of what is going on within your game world.
I said "Unity's physics" a lot... haha!
Comments