Game Overview: "Chain Reaction is a top-down shooter, battle royal style game with limited weapon upgrades. Start the game in a prison chained to a teammate and scavenge the map for healing kits and weapon upgrades. Prepare yourself for enemy team encounters and cooperate with your teammate to stay alive until the end, after all you are chained together so your movement is dependent on each other. Be careful of the storm closing in on you it is deadly. Last team alive gets to escape the prison!"
An attempt at creating a multiplayer battle-royale style top-down shooter game. In a team fo 6, we used Unity to create the game, C# .Net Framework to create a server that hosts multiple players and runs game Logic and also used Autodesk Maya for the creation of 3D assets used in our level. I will overview technical aspects of the process and at the end also explain my role and the tasks I undertook as a lead programmer.
At the very early stages of implementation, we decided to split the work into 3 pairs and therefore have a simple separation of workload between people. The first group was the Graphics group, responsible for the creation of 3D assets, level design, and aesthetics. The second was the Gameplay group, responsible for the client-side game-related content, such as implementing movement, upgrades, and other gameplay features. Lastly, the third group was the Server group responsible for creating a server to host multiple client communications and allow for the multiplayer experience that a battle-royale game needs to offer. As I was part of mostly the gameplay and server team I will discuss those parts in detail in the following 2 sections and I will also add a third section discussing my contributions to the project.
Our game is a top-down, battle-royale style shooter aimed for massive multiplayer play. Despite the genre of our game, there is a small back-story that explains the setting of our arena. Our game takes place inside a prison, where the inmates were used as lab rats in scientific experiments designed to evolve the human race. The experiments were not leading to anywhere and the prisoners had to be exterminated after the failure so that no one could ever know what was happening. This small back-story sets the design of the arena such that there is a prison like map around the outskirts that eventually leads to a laboratory filled with surgery tables, to Liquid tanks with humans inside and even big boiling tanks of acid. In order to eliminate all the prisoners, a huge gas attack was unleashed on the prison surrounding it and rushing towards the middle.
The controls for the players were very simple, use "WASD" for moving around, use the mouse to aim, left click to fire and right-click to use the ability dodge. As a design choice, we decided to have the bullets move slower than usual so that players could potentially dodge them and with an added ability, "dodge", that made them invulnerable for a fraction of a second. In addition, the game was designed to be played in pairs. We wanted to keep the controls of the player simple, in order to add a layer of complexity to the game in the interaction between the two players. Making use of the prison theme of our game, we created a chain that binds the two players together.
Implementing a chain between two players was one of the more challenging tasks we tackled as a team. Unity's built-in functionality was not sufficient as we aimed for a very customizable solution and one that would allow us to port it onto the server-side later for the multiplayer aspect. After some research, I learned that many people attempting to simulate a rope would do it using spring physics and after reading some spring mechanics, I designed a simple system shown in Figure 1.
The chain works by instantiating chain nodes (white boxes in Figure 1) that act as intermediate points in a chain that simulate forces between one another. A chain can be instantiated with as many chain nodes as needed (the more nodes, the more realistic the chain) and each chain node pulls on to its predecessor using spring forces. If a chain node gets far apart from its linked nodes, it is pulled back towards them. The equation for spring is shown in Figure 2, and is coded with an added dampening constant that counters that force. (Code => float force = −tensionConstant ∗ displacement − dampeningConstant ∗ handle1.velocity.magnitude;)
Another fundamental aspect of the gameplay is the Fog of War. This implements a limited vision system such that players can only view what their actual character and their teammate's character is able to view. This enabled players to hide from enemies or even ambush enemies without being noticed when they enter the screen range of them. This is a simple mechanic but very powerful that adds depth to the game and more interactions between teams.
The fog of war was done by casting multiple rays in a circle from the player, which detect whether or not they hit an object. The edge detection of the rays becomes more accurate as the density of the rays increases. In order to improve the performance of the edge detection, an optimisation was applied. If a ray cast detects an object and the next one doesn’t, this is normally seen as the end of the object, but the actual edge is in-between them. In order to get closer to the actual edge, a method similar to binary search was used, which casts another ray at the mid point between them and checks on which side the actual edge is. This is done for a couple of iterations to increase the precision of the edge detection. This means that the field of view doesn’t need to have a really high density in order to accurately detect objects.
The ray casts are used to draw a mesh around the player (Figure 3), which is then drawn onto a texture file from the perspective of an orthographic camera that sees the whole map. The texture is blurred and then projected onto the map by a projector put in the same place as the camera. The shader of the projector makes it so that only the area within the field of view mesh is lighted, while the rest of the map is in a fog of war. The projector also blends any new textures, which results in a smooth transition.
Every player starts with a basic pistol that could later upgrade to one of three options, a rifle that has a high fire rate, medium-range, and medium-damage, a shotgun that has low fire rate, low-range, high-damage, and 3 bullets spread and lastly a sniper that has low fire rate, high-range, and high damage. Players have to find upgrade tokens that are randomly scattered around the map and use the upgrade menu to upgrade their weapons as shown in Figure 4. In addition, other than upgrade tokens there are health packs scattered as well that help the player regain some health.
In the early stages of planning, deciding which technology to use for the development of the multiplayer aspect of the game was difficult. Nobody in the team had prior knowledge of how multiplayer is done in games. It was clear that since we were building a battle-royale style game that we needed a client-server style of communication. Initially, we discussed the possibility of using Unity's built-in UNet functionality but soon realized that it didn't support the client-server model.
Then discovered Photon, which is a framework, that is easy to use and fast to implement. It has support for Unity and also its own cloud (Photon cloud) which supports very easy deployment. We started implementing connecting players in a server, then implemented movement in multiplayer together with movement prediction and smoothing. As the game progressed and needed more and more specific server-side functionality, we ran into many problems. Photon was a very easy solution but with a significant limitation in customizability.
Lastly, after more research, we decided to build our own server implementation, as a C# console application and using .NET Framework WebSockets which is further expanded upon here.
The server is based on a singleton class called "network". "Network" is a layer that controls all traffic for the server both inbound and outbound. Inbound traffic gets processed using the ServerHandlePackets and outbound using another ServerSendPackets. Each different client connecting to the server is stored as an instance of the Client class which keeps data of the connected clients and is used for identification and broadcasting of data. The state of the game is also stored in the server through many classes such as Player, GameHandler, and RoomHandler. Storing player's data such as location, health, and weapon allows the game to have a consistent state throughout all the clients.
Improving the server in order to allow it to host multiple clients smoothly meant that we needed to think ahead and implement efficient ways of communication between server and clients. Working with WebSockets in .NET Framework meant that we had a lot of control over the communication methods. Our main efficiency of the server was the inclusion of different types of communication protocols. Transmission Control Protocol (TCP) is a way of communicating that includes and handshake and a validation step, which meant that there was a consistency when communicating through this protocol and the sender of a packed is notified if the communication was successful. In contrast, User Datagram Protocol (UDP) is a method of communication that simply sends data without any verification or "callback", which simply put, a sender sends information without caring whether the receiver has received them. Therefore, TCP is reliable but has a time overhead, whereas UDP is unreliable but fast. TCP was used in communicating important player data such as health and coins that were necessary for players to keep consistent. UDP was mainly used for player and bullet positioning as this kind of data was very rapidly changing and are sent at a very fast rate which means that validating a packet doesn't really matter if the next packet arrives before the validation of the previous one is done.
Within the client side code, we tried to have simple but effective handling of networking. Core networking functionality is encapsulated in a Network class which is responsible for sending relevant data to the server and any responses or messages sent by the server are handle in a ClientHandlePackets class. Figure 6 illustrates this relationship between the core game and the network. Similar to the server, low-level networking is managed via the .NET framework which handles the implementation of the TCP and UDP protocols. We aimed to make any server communication on the client side to be as simple as possible, as shown by the simplicity of the diagram. This allowed to develop code that could be incremental in which any data which we wanted to communicate client side could be handled through simple functions that send data in an easy to replicate format.
We have run our server in Amazon Web Services (AWS) and have at one instance managed to play with 40 players at the same time in a single game instance with no communication lag and smooth player and bullet movement.
(I will record and upload a video of actual multiplayer gameplay and put it here)
Having previous experience and knowledge with Unity, I became the Lead Programmer.Initially, prior to the creation of the three development teams, I started working with some basic playermovement and bullet firing. This was appreciated by the other members of the team and we decidedto make it our base and build every new feature on top of that. Therefore I set up that Unity projectin git and prepared the necessary gitignore and gitconfig files.
First iterations of Photon Network integration into the game were my attempts, in addition to helping other members of the Server-side development team how to use it.
Then as our attempts at Photon Network did not work out, I initiated the fully custom server development, while I programmed the core server and at the same time worked with other member helping them learn the framework and follow my code, I then had to leave the server development team and help out the Gameplay team.
Working on the chain between the players, the Gameplay team had some trouble conceptualizing it and bringing it to life. I then attempted to create a small example of what my idea of the chain would look like and after some coding, I managed to create the basic prototype. I explained and worked with the Gameplay team to help them understand and continue the development of the chain but more difficulties presented and therefore I decided to finish the chain implementation my self while I let the Gameplay teamwork on the rest of the Gameplay features. In addition, I also worked on the task of implementing a revival system. It needed a parallel development of both server and client-side features, which me having worked on both, I could complete the task.
I also worked a very minimal amount with the Graphics team, I help add some small touches around the game that made the experience feel more alive, such as particles on the bullet explode and a trail behind them, or even small sound effects together with the background music (which was created by another team member).
As a lead programmer of the project, I decided very early on to use Trello boards as a means of keeping track of progress and pending tasks. In the beginning, I create a single board page and assigned different people tasks. This method fell apart very quickly and it was then that I realized that I needed a clear separation between people's tasks and a clear way of communicating their end goals. This was when I introduced the three-team strategy of Gameplay, Server, and Graphics. This strategy improved the team's efficiency and with three separate Trello boards, tasks were clearer and were completed faster.
One thing I would definitely do better in the future would be to integrate the work between the teams consistently and frequently. We sometimes took even a whole month before merging everything together and having a workable product which meant that the merging was usually difficult and time-consuming. Another important lesson I learned for managing big projects is to put deadlines and clear goals. Having deadlines pushes people in putting work into the project and achieving tasks much faster and if the goals set are clear then the members will have very little trouble in implementing them. This project was a massive undertaking that improved my knowledge of game design, coding, server infrastructure, and architecture and also how people and teams work within bigger projects.