Battle Royale Prototype
- Adam House
- 23 hours ago
- 27 min read
Type: Practise project.
Genre: Third person shooter and Multiplayer.
Engine: Unity.
Key Roles: Programming, some 3D art, Level design, and Game design.
Released: 18/10/2025.
Last updated: 18/10/2025.
Learned from: Build & 3D Model Huge and Complete Unity® Games from Scratch by Mammoth Interactive from Udemy.
Made by: Only myself, though some 3d assets were provided to me by the instructor.
This was a very long and big project which took more than a year to complete. I had some delays such as getting a new computer, unknown bugs in Player movement code and had to rest for a week after I caught a bug when I attended game conferences in Melbourne like GCAP, in ACMI, and PAX AUS.
Normally working on network multiplayer code is one of my weaknesses since how difficult it is to execute the code flawlessly, but luckily: I found this course that teaches you more in-depth of network code with also some knowledge of game design, level design and mechanics for first person and third person shooters. So I did not hesitate to buy it since first person shooters are one of my ideal products to build for the gaming market.
I remember the first time I tried to work with multiplayer code in Unity was back in mid to late 2017 during my first half Diploma of interactive games at Holmesglen which was my 3rd game dev course. I noticed the game mechanics that I learned are similar to Fortnite, which if it goes well, I could make a multiplayer game rivalling Fortnite but to do it in its own way like in a survival horror theme or something.
As you can see, I have designed two multiplayer maps: the simple photorealistic prototype map “Tropic Base” and the low poly cartoony “Desert”.
At the start of the game, Players are dropped in the level from an energy ball into the map. Once they make it down, they need to find weapons, mine resources from trees, defend themselves from Enemy AI, build their base out of resources, find and kill each other while the Storm shrinks 4 times before it eventually covers the entire map. The last Player alive wins.
The sounds used were given to me by lecturer for this project.
The million-dollar question is: Is this course perfect for helping me build a multiplayer game like Fortnite or Pubg?
WHAT WENT WELL?:
Part of the tutorial is to make some 3D firearms, melee weapons, and a humanoid character on Blender which I learned various new tricks through 3D modelling, textures, and rigging. Though I haven't really noted what I learned from it, I am mostly focusing on writing about the game design, level and coding part of this project. I managed to import 4 of the 3D firearms, rocket and pickaxe I made from Blender.
Despite my weakness in making multiplayer games, I managed to hold on my own very well and created a near flawless game, though I still think there should be more improvements and accessibility to the game before it becomes a product.
I used more complex programming with complex methods, parameters, returns and learned new advanced code tricks thanks to the course which heavily reduced null reference errors in the console from the Enemy and Player scripts.
Part of the course I managed to edit the code of the default Unity third person character “Ethan” into a traditional third person player movement with the camera script (I coded myself) such as moving forwards, backwards, sidestep left or right and the camera following, moving and rotating along with the player.
–Game design–
Every new gameplay feature we add to the game; it increases its complexity with the game. Players will find new ways to strategically cheat, gain advantage and glitch through the game. They may place obstacles on windows to barricade themselves inside or destroy their own ramps after using them to get on top of houses.
Think about from a design perspective: which is suitable for Inputs to be sensitive, quick or slow from perspective? If it's too irritating to players, they won't play it.
For multiplayers, you don't want the Players to easily have shot accurate weapons otherwise they will easily overpower other players.
The building adds a lot of value to players since they can stretch their creative muscles and use it. It also adds unlimited possibilities.
It's not good to worry about realism, only making the game fun is what matters (e.g inaccurate ammo box sizes. Speaking of which…)
Ammo and gun pickup visibility is more important than making them their realistic size proportions.
Players love the freedom of creating structures like building blocks to get around. You could try to make it accessible for them so they can have creative freedom to do so.
It's important to test 3 scenarios in variable values: a random number, a big number and a small number to make sure the calculations are correct. It's important to do these tests early in development rather than later when you have more tasks to do.
When thinking about explosions, think if it covers a small area or a big area by range.
Different weapons should have strengths and weaknesses to make the game far, for e.g...
- Pistol does not deal much damage, it's pretty suitable to have a smaller cooldown/fire rate.
- Strong weapons like Shotgun, Sniper and Rocket launcher may need less ammo count for clip size and max ammunition. - Remember: A strong weapon requires either a long reload, smaller accuracy, or slow fire rate to make things balanced. They should have an advantage and disadvantage aka drawback.
For Shotguns advantage: shoot multiple bullets in 1 shot, but its disadvantage is the player may wait for a second or less before shooting again aka firerate/cooldown.
- Machine guns will need to hold a lot of max ammunition since the player will be shooting very fast until the clip is empty but may deal less damage each shot.
- The Sniper rifle needs to load one bullet per clip and a slow fire rate down due to how powerful the Sniper rifle is. This is the sort of weapon you should be far away and unseen since you can't easily fight players close up with a sniper rifle. Basically, it's designed for long range and unseen shooting.
- A Sniper rifles advantage can be the only weapon to zoom in, no recoil and devastating damage. But its disadvantage can only leave you one bullet each clip and have to reload each shot, this is same for Rocket launchers.
We need to prevent cheating by not letting the player switch weapons and shoot quickly, E.g. the Player shoots with a Sniper rifle then switches to Machine gun, so we add switch weapon time to each drawn weapon.
When making different things, we need to think and plan a hierarchy. Not from a gameobject perspective, but from a class definition perspective.
–Level design–
Strong weapons should be in hard places to reach, it is more rewarding to the Player.
Risky areas with less cover are a disadvantage, it should give players an advantage by laying more weapons in that area.
Having shotgun pickups close to the hill is good so when the Player is close or struggling to get up, they are an easy target for Players.
For more dangerous weapons like the shotgun, you may want to make them difficult to see on purpose, so Players don't find it easily and not power up too quickly.
Players may look for places with civilisation; they will go there to find weapons for survival and may bump into other Players.
You may want to leave empty spaces so Players can build their base with their resources.
If you see areas with empty spaces, it's always good to fill them with gameobjects like enemy's, items, etc. Players will be an easy target in empty areas, provide them cover.
HeightMap resolution (under Resolution) in settings (Terrain settings): the higher the value, the rounder the map is going to look like, small values will make it more pixelated and more triangle feeling.
The more weapons you spread on the map, the more places' players will be interested to go too.
Sniper rifles can be placed in strategic points so they're ready for Players to use them on site (for e.g watch towers or on top hills).
If it's something good like an RPG item, make sure not only is it hard or risky for players getting them, but easy to be spotted by other Players to add risk vs reward.
When designing levels for multiplayer games, make sure you give them objects to take cover behind and to climb around to reduce them getting cheap shot easily. This gives the Player a chance to fight back the attacker.
Make sure to cover the horizon with hills, otherwise it will ruin the illusion making the game seem fake rather than believable.
–Weapons and pickups–
Made an Item Box with a public enum of Pistol, Machine gun, Shotgun, Sniper and Rocket Launcher. The Player only picks up one of these depending on which game object carries it.
Made two getters of ammunition amount with a guntype that will tell the Player’s weapons script which weapon and ammo from the item box the Player gets and can use in game.
Made Item boxes hold a child object of a visual mesh to not only to rotate smoothly with delta time, but also using a new Vector 3 LocalPosition with Mathf.Cos to smoothly go up (Y:+1) and down (Y:-1).
Able to multiply the Explosion range by code on the X,Y,Z scale and drawing a Raycast Pyshics.SphereCastAll to execute an array of raycats inside the sphere to store information with a for loop of hits to damage Players, enemies, and trees as long as they have the IDamageable Interface if they touch the radius. It can hit none or multiple objects, so no need to worry about errors. It only executes once before it destroys itself through the network.
Created a weapon class that won't be used in hierarchy view, but in project view and determines which amount of data each weapon will inherit using getters and some setters..
- ClipSize:defines how many bullets you have in a clip ready to fire.
- MaxAmmunition: amount of ammo the player can carry in total before reloading.
- ReloadDuration: Time it takes to reload weapon clip.
- CooldownDuration: time it takes to shoot again, basically firerate.
- IsAutomatic: determines if it's automatic like a machine gun or semi-automatic like a pistol or rocket launcher.
- Name: what the weapon name will be displayed on UI.
- Aim variation: the spread of the weapon recoil when raycasted.
- Damage: damage inflicted to the Player, enemy or tree.
- Amount of bullets (shotgun class only): how many bullets it shoots each shot.
These variables are protected, This protects the values and only allows certain inherited classes like pistol to use these values. It is similar to private; it allows its children like pistol to inherit its variables. They cannot be accessed by other classes.
Using System.Math.Min to add ammo to the Player and loading clip. Basically, it calculates how many bullets are going to load in the clip depending how much ammunition you have, even if you have 2-5 ammo left or enough for the clip before reloading.
Not only can the Player press R to reload the weapon, but if he/she runs out of the clip, the weapon will start to reload automatically.
If you collect the pistol, it is added to a list ready for you to use and creates an object in code known as “weopon”. It does not matter which order of weapons you collect. For e.g, if you pick Pistol the 1st: you can press the ‘1’ key to equip it, if you collect a Rocket launcher after pistol, then press ‘2’, you will equip the Rocket launcher, then the Shotgun, then you press ‘3’ key to equip it.
Made the Sniper rifle the only weapon that can zoom in within a complex if statement, if the Player is zoomed in and changes to either another weapon or tool, it zooms out and the zoom-in UI does not come back until the Player equips a Sniper rifle and zooms in again.
When the Player gets a new weapon, the Player script checks to see if the Player has collected that certain weapon before. If not, it creates a new weapon object and saves a reference that the Player can use the weapon using each of the assigned number keys 1-5 so the/she can select and use the weapon in game, otherwise it will give the player more ammo of that particular weapon if the Player already has the weapon.
Able to pass Time.deltaTime values from Player script into the weapon script which is not a monobehaviour script. It passes Time.deltaTime to cooldown and reload time so the Player can cooldown and reload each of their weapons.
If the Shotgun is equipped, the Player script makes sure the Shotgun weapon gameobject is equipped before it can shoot pellets.
Able to make the gun fire spread (aka recoil) by randomizing on a Vector 3 while being normalized.
–Resources and obstacles–
Allowing each obstacle to have cost of resources and health so the Player gets data of them right when they spawn the chosen obstacle.
When selecting the obstacle to instantiate, it gives a renderer material rgb to 50% transparency and disables collider. It uses a material instead of shared material.
- Shared material affects all the game objects with the same material in the game.
- The material only changes on itself only since it is a copy.
- When placed, it enables its collider and changes its renderer material rgb to 100% opaque with no transparency. Though now while selecting obstacle it's no longer transparent,
Allows to check if the obstacle is Server, shrinks and destroys gameobject if its health is 0.
Made Tree prefabs that can be hit by the Player’s axe to mine resources, each tree has a certain amount of hits before being destroyed and a given amount of resources to the Player each hit. This is done by 2 getters: health value of the tree and resource amount.
Made an “ObstaclePlacementContainer” gameobject that whenever the Players instantiate obstacles, it will spawn in that gameobject parent as its children.
Made an array in the Player script with the obstacle prefabs that can be stored and ready for the Player to spawn in the game.
Made a cooldown for the Players axe tool so he/she does not mine resources so fast.
While the Player is selecting which obstacle to spawn on the map, it destroys the previous choice of the obstacle and instantiates a new one ready for him/her to make a choice to instantiate the real in-game obstacle while moving with the Players camera by its parent with its transform. First, we set its position and rotation to 0,0,0 then we are using the local rotation rather than world rotation so it can match the rotation of the players facing direction.
Can convert from an enum into an int when selecting from an array of obstacles to spawn in the world. Going from first to last, then repeat the process again unless the Player wants to switch back to weapons or instantiate an obstacle in the scene.
Made a complex equation between scripts of the Player and resource object that the Player can hit a tree with an axe until the tree has run out of resources and destroys itself. Once destroyed, all Players will see the result.
Able to keep the new placed obstacle's position and rotation in the world position consistently.
–Networking–
Not every network trick is going to work, there are many code communication messages that need to be shared with each other for the network to work.
Storm Manager will be a server networked object and will share data to all the Players in the network.
It's best to test locally before thinking about testing it with clients.
Remember: it's important to understand that some code runs locally and some code to inform other clients what has changed (e.g Player health has been damaged).
Host: Hosts the entire match while Clients connect with the Host.
Clients: People who join the Hosts server.
Remember: All clients need to see the same thing(explosions, gun fire, Player movement, current weapon equipped, resource trees, item boxes, etc) in multiplayer.
The Server does all the calculations in the game. E.g Score count, knowing where every game object is including the Players in scene, instantiations, and energy balls.
The Host (usually the first player) is also the client, but the main one, he/she holds the main server so remote clients can join in.
Network Authority is an interesting thing to understand in Unity.
- Local authority: Players have control over themselves to move around the map and tell the server where they are.
If you create objects that are synced, you cannot pass commands to that game object. This is how Unity is designed.
When spawning, you need the NETWORKSERVOR.SPAWN to spawn instances into the multiplayer scene so all clients can see
The rocket does not need to be in perfect sync (0 in Network Send rate) otherwise we would be sending too much network resources which could impact the game.
For the Network Transform You will have to really think how it's going to work in your game….
- The obstacles don't need a network transform because of how the code and network manager implemented them. It saves some valuable network and less data which is easier for performance and quicker for network data to pass to clients.
For Transform Sync rate….
- If low, the network of Player movement may stutter on the client's screen.
- If High, the network of Player movement will sync fluidly, but may send lots of network data frequently which may impact performance.
- It's the amount of time it takes to send instructions and network data to all clients. It also depends on the client's whereabouts like if he/she is in Brazil or Canada which may lag if too far from the Host. It will need to be tested thoroughly depending how far clients are from each other.
Network Identity: identifies the game object that is ready to be synced online with the host and clients. In other words, it can be seen, registered, etc.
It is fine to have multiple instances of the Player and to be recognisable on the network, but you need to keep in sync, that's why you need network transform on each Player.
In multiplayer games, we want the obstacles to be created on the server. Servers manage the instantiated obstacles properly and to destroy them too when called. It will not be executed in the local player method. This is when CMDs (commands) come in handy for the job.
Sync is key when talking about network and multiplayer development.
Networking requires a lot of testing for each of the clients and the Host on the Server.
Setting certain game objects as registered spawnable prefabs on the Network Manager are instantiated and be seen by all clients including the host. These gameobjects are Player characters, weapon pickups, resource objects, trees, bullet fx, explosions, rockets, etc.
Setting spawners for each weapon pickup and using a Vector 3 to offset position when it spawns above ground and through the network that all players can see. Remember, Network the weapon spawners to spawn 1 unit and half above ground So Players can access it.
Can Sync Player animations consistently through the network.
Made scripts to inherit from NetworkBehaviour instead of Monobehaviour. This allows the gameobjects to pass information and data like current position of Player character, current Player health, explosions, rockets, obstacle placements, current resources (like trees), Storm Manager, updating objects in size, item spawners, etc.
“If (is Servor)” allows the server to use this data to hit elements in the radius passing info across all clients.
Can Destroy gameobjects through all clients like Players, enemies, rockets, explosions, item boxes, resource trees, etc so all clients can see.
Using only Cmd in Functions with [Command] to pass information through the server and execute code on all clients. For e.g….
- Explosions to be seen and Players to take damage from them.
- To show Players current equipped weapon or tool like pickaxe or nothing.
- Players to hit trees with an axe damaging or destroying them.
- Placing obstacles in the scene and playing placement sounds whenever the Player instantiates obstacles.
- Collecting new weapons and then destroying the weapon item pickup on the server.
- Instantiating Rockets and making them fly from the Player's hand to the target where the Player has aimed at.
- To Show where bullets have been fired on walls.
Add bullet marks on walls shot from players weapons except for the Rocket launcher that are visible to clients.
Using NetworkServer.Spawn to spawn objects like explosions, rockets, and item boxes.
Player Health is the most important data that needs to be in sync with the Host and clients, so everyone knows if the player character dies or not.
Syncvar makes sure to execute a function when the value (player health) is synced. It hook syncs and passes the new updated data to clients informing what has changed.
Sync is key when talking about network development.
NetworkBehaviour is essentially the same as Monobehaviour but in an improved way, it has exclusive methods and parameters for networking.
Can call references for other game objects separately and locally from the Player so clients don't respond to the code with conditions like if (isLocalPlayer) or if (!isLocalPlayer).
Made a screen where hosts can start the game with no or more clients. It even finds the Players by gameobjects and counts the current Players who have joined the game.
Using only [Client Rpc] too….
- Allow Player movement to all client instances which is information passed from the server to the client, even in energy balls.
- Alert all Players that the storm is shrinking.
Some network code I use Commands and then the [Client Rpc] too..
- To play the appropriate weapon sound which can be heard by clients depending which weapon was shot by the Player. The sounds are listed under an array index.
- When the Player jumps, it makes a sound which can be heard from nearby Players.
- To play Player randomized footstep sounds when he/she is moving so other nearby Players can hear it.
- To show the Player's current equipped weapon connecting to a method with a string parameter that only one weapon can be shown at a time.
- Deactivating energy balls once the Player has reached contact on ground. This is seen by other Players too.
For the If (!isLocalPlayer)
- It will activate for the local Player, not remote clients.
- It will also block out the methods since they are connected to the Update function.
- Keep in mind, since Player audio runs through Updates, the gun audio is played on local clients' own computer rather than sharing the sound for all remote clients. Luckily this has been resolved.
Command communicates with the host server, so it is able to place an obstacle in the scene for the Player along with which object it is (by index), its position and rotation in the scene.
Authority is an important word for destroying game objects and other things like instantiation in multiplayer.
NetworkServer.Destroy Gives authority to destroy the gameobject and let the Host and clients know by Servor.
Vector3 is one of the values that can be passed in Commands.
Made weapon sounds only to be called at the Player game object so nearby Players will hear the sounds.
Remember, only certain parameters can be passed through commands, Game objects are one of them as long as they carry a network identifier.
Override void OnStartClient() will ONLY work on just the client, not on all clients in the server unlike OnStartLocalPlayer() which works on all clients including the Host. To find the Players we use the for each loop to find Players with a Player script to refresh the Player weapon models.
Network identity makes game objects spawn in the scene visible to all clients.
Network Manager manages Player prefabs to be networked in scene, and spawns them in a round robin when game starts, it registers which prefabs to be spawned and destroyed like weapon pickups, trees, rockets, different enemy types, explosions, obstacles, which Players, etc.
–Enemies–
Using Inheritance so the Static enemy (aka the targets) and Flying enemies (spheres) inherit from its parent script “Enemy” that will ensure they all act the same way when shot by players.
- When shot, it shrinks down 90% of its scale then back to its target scale of 1 using X, Y, Z Scale and Mathf.Lerp when multiplying with smoothness on Time.delta Time. This is a linear interpolation.
- When the enemy's health is 0, it will scale to 0% of its size and then destroy itself.
- The Enemy script inherits an Interface “IDamagable” so it is able to be damaged by Players.
- This is also done with obstacles but to 80% of its size when damaged by Players.
Used a script “StaticEnemy” with barely any code, except for inheriting from enemy script. But can still use public variables like health and hit smoothness.
Able to Pivot the Static enemy from the bottom making it easier to snap it to the ground when placing in the scene.
Allow the Flying enemy to check underneath with a raycast before moving up and then down (y position) to give a smooth bouncy movement seamlessly while Idle.
Made the Flying enemy move in all X, Y, Z direction multiplying with Time.deltaTime when chasing the Player without a NavMeshAgent. If it is out Player's reach, it stops and starts bouncing up and down again until the Player reaches its radius again.
Flying enemy checks if the Player has entered its PhysicsCastAll raycast radius, but first it checks to see it has no existing Player target first before chasing the current Player when entered in its radius.
Allows the Flying enemy to move in a normalized direction along with its Rigidbody, Vector 3 and Mathf.Lerp to move along a linear interpolation while smoothed in Time.delta time.
When Flying enemy collides with the player, not only the Player takes damage and the Flying enemy bounces back, but that enemy minus’s a value from the Players position with a normalized Vector 3 from its Rigidbody without using addforce.
–Code–
Think of code like instructions, you are giving the program instructions to follow like when a certain event is supposed to happen, then what should it do?
Fixed Updates can work on fast and slow devices to maintain its intended physics code.
Think carefully of which Update to use: Update or Fixed update, before you give it physics code, e.g jump or move. Fixed update is recommended for movement. It works with gravity too.
For damaging enemies, Players and resource objects. We use what is called an "interface"
- Interfaces start with an I due to its an Interface, it is a pattern used it C#, E.g "IDamagable".
- An Interface has a similar structure to class, since we are declaring one with a name, but doesn't implement any methods.
- It is more of a scripting C# solution rather than a Unity solution itself.
- With every gameobject that has IDamageable, it has to implement a method called Damage.
- It will return an int value and it will receive a certain amount of a float as a parameter.
- This allows Players not only to damage each other, but to damage enemies and resource objects on the map. Interfaces make references to code easier.
Using events to call and subscribe to any of the game objects that will listen to the caller and then execute the given calls. This is used for updating Player health, resources health and amount the Player gets, storm shrinking, camera zoom ins, rotation anchors, storm alerts, gun types, ammo type and amount the Player gets, Starting matches, UI of Players resources, number of Players at the start of the screen, turning on and off of Sniper visibility, Player footsteps and jump sounds, etc..
Remember, whenever we create a setter, it's like you're creating a method with 1 parameter of the bool type. The parameter is the "value"
Events call out to a script to execute code; they don't return any values or parameters. It passes the event to whichever script listens for the method call and subscribes to it and respects the void condition. This is an expensive method since it's going to search every game object in the hierarchy until it finds its target. Though it only runs once.
Mathf.Cos is used calculating angles and geometry details which is part of mathematics, it starts from 0, if the value is 1, it will go to 1 and back to -1, then back up to 1 repeating the process again. The cos sign and tangent require an angle; basically, it returns from 1 to -1 while also depending on V.range is given. This also smooths the movement.
RaycastHit[] hits = Physics.SphereCastAll is like a raycast, but instead of drawing a straight line, it draws from an imaginary sphere and whatever object is inside or touches the sphere will return info. This will also return an array of raycast hits as it stores it as a collection. It can hit none or multiple objects, so don't worry about errors.
Awake is the safest option for GetComponents including GetComponentInChildren due to it starting earlier than start, otherwise you get errors.
The weapon is an abstract class which helps the class expand and to exist off scene.
Each weapon (like Pistol and Rocketlauncher) inherits from a weapon class which uses a constructor (spelling ctor when hitting tab in visual script). You don't need to call this method; this is automatically called when this object is instantiated. This behaves like an awake function. It's really important to understand these data concepts.
Debug.logs only work on monobehaviour scripts.
Physics run in a different frame, and are more designed for Fixed Update function, they are not always called well in Update function.
- Update has a variable time between every call.
- Physics needs a fixed time when updating and calculating.
- We need the Flying enemy to fly on Fixed Update since it relies on physics, going from position to position and not moving stuttering.
- This allows the enemy to move smoother since it's moving in sync with physics.
- The camera will stutter as the player moves due to using updates.
- Fixed Update will move a little smoother due it moving around within physics.
- It Doesn't matter if the game slows down the camera will still move in a proper way
RegularAngles is basically doing a 360 turn from 0 to 360, or 180 if it needs to be more or less. Rotation X, Z, Y are represented in eular angles. Internally rotation represented from an object is structured into a Quaternion. It can be converted to Quaternions too!
Math.f has different unique methods to get the job done with values.
- Round: Rounds the float up or down to the closet int. for e.g 0.4 > 0 and 0.6 > 1.
- Floor: Rounds down the float to the closet int. For e.g 0.4 > 0 and 0.6 > 0.
- Ceil: Rounds up the float to the closet int. For e.g 0.4 > 1, 0.6 > 1. 0.0> 0.
Enums are not strings, they are shortcuts by whole numbers, they can be used to make written code easier to detect and readable.
Public keycode is an enum so you can select which key it will respond to in code.
The array is an abstract.
Cursor lockmode is an enum.
Raycasts return a bool since its bool physics. Hit saves information you hit with raycast which will be true. If it didn't hit anything, it's false and it's null.
Getnames retrieves an array of the names of the constants in a specified enumeration, in other words it will return an array with strings (names of enums)
E.g if (currentToolIndex == System.Enum.GetNames(typeof(PlayerTool)).Length)
{
//back to first selection
currentToolIndex = 0;
}
For zooming the camera: you can get an error due to float precision issues, to solve this: we use Math.round to round the value. Math.round rounds to the nearest int making it precise on point with decimals.
–UI–
The storm alert text is likely going to be the first thing Players see, so it should surprisingly catch players attention.
Some sub-text like "weapon" should have a style that catches people's eye for attention, except for the numbers (e.g shotgun ammo).
Made a UI tool selection with an enum that lerps on the vector 3 x axis when selecting tools.
Made text change colour for resource cost by code.
Created a function that compares two parameters of cost (how much the obstacle costs) and balance (how much resources do the Player have so far?). If Player's balance is greater than cost, the Player can create obstacles. Otherwise, don't spawn obstacles.
Made a complex code with a reload bar that shrinks from the left on a localScale vector3 on the rect transform when reloading a weapon.
Created a Method with a string parameter that will show only one UI screen at a time each on the client's screen depending on which one gets called by other scripts. These can be “regular”, “gameover”, “server”, “client” and “spawn”
Made a UI crosshair out of default rectangles and can scale them with 1 rect transform scale to make it more dynamic if the gun is in between high and low accuracy. However, the crosshair is not programmed to dynamically size with different weapons.
Used a Horizontal Layout group for tool and obstacle selection so it easily adjusts its selection if I decided to add more options for Players to use and it fits itself to different screen resolutions which requires no extra developer tweaks to do the job.
–Post FX and lighting–
Vignette post fx is good for cutscenes.
Antialiasing is good at making pixel resolution smooth but will make your game more resource hungry in other words expensive.
Fog is good for making it hard for snipers to see faraway Players.
–Storm Manager–
Made the storm objects calculate its distance to then shrink and normalize its transform position. It then lerps smoothly to its new target position.
Made the Storm Manager use an array with each element using a float timer to count how much time the 4 storm gameobjects shrink with a certain amount of distance towards the center map before alerting Players 4 times. This forces the Players to move to the center and potentially to kill each other, else the storm objects will damage the Players inside potentially killing them.
–Energy Ball–
Can change Players move speed in a Energyball speed using a getter and a setter. This turns the gravity false until the Player reaches the ground which will be true.
Can turn from the Energyball to Player character by checking its raycast collision at the bottom of the character when he/she hits the ground.
–Animation control–
For character Skinning in Blender...
- Blue: not affected by other bones.
- red: fully controlled by bone.
Animation mask override overrides the layer on top of the mask (e.g torso and arms respond within the layer while legs have their own layer).
Animation>Humanoid in animation helps convert humanoid animations to another humanoid rig. It changes how the file is imported in Unity.
In Animation, If the limb components are yellow. it means a certain limb is missing (e.g Jaw, chest, right fore arm).
Made animation 1 parameter “shoot” to fire every equipped weapon in the game rather than separate parameters like “pistolShoot” machinegunShoot” etc.
I made an Animation Control Reset so the Player’s firing animation does not play twice, only once.
Allow the Player to hold one weapon at a time or nothing at all if they choose thanks to a method with a string parameter.
Using PlayerNetworkAnimator to play and trigger animations across the network.
–Other–
For gameobject material: Smoothness = 1 makes the material shiny metallic and reflective of the sky. 0 makes it rough. Material transparency is an expensive operation because your computer's video card will have to compute the precise colour of pixels.
For audio source: The blue circle is the range that the sound can be heard only in 3D sound space. If the audio listener is at the border of the blue sphere of the audio source, you are going to hear its maximum volume. If the audio listener is outside the same blue sphere, you won't hear it.
A Vector is an arrow that starts at an origin and points to one direction depending on its axis.
In Blender: The option Mesh> Recalculate outside, makes all faces face outside.
Able to make very smooth and consistent doors that can be open and closed with a target angle if the Player presses “E” at the door which will rotate by an angle +90 or -90 degrees with each Player interaction.
The Door rotates smoothly each Quaternion lerp with a Euler local rotation multiplied by delta time along with an angle.
Learnt complex mathematicians using Quaternions, eulers for Camera rotations and offsets.
Can set up Players focal point and rotation in around the third person camera by code. The focal point changes its camera view from either left or right of the character model which smooths with a lerp at any time a key is pressed whether the focal point is currently moving or is already moved.
Local Position allows us to move and rotate within the parent of the object locally. It's important to understand the difference between local position and world position. World positions have no parent.
WHAT WENT WRONG AND WHAT COULD I HAVE DONE BETTER?:
I couldn't import any of the humanoid characters I made in Blender into Unity, so I used the default Mammoth Interactive character as a Player character that was provided by my lecturer instead. I will have to look at my notes from previous experience of how to import characters properly and make sure they have their Animation Controllers and Avatar to start with, which I haven't done much in my entire game dev journey.
I could not sync certain code across the network due to unknown means such as shrink in obstacles upon 0 health and show rockets flying after being fired. If I want to make a near flawless Multiplayer game, I need a better understanding of using multiplayer code before I incorporate it in my future games.
The Player movement script broke mysteriously and turned it into a janky tank-controlled character with limited mouse aim which really ruins the fun of fast paced movement. Luckily, I redid the code so Players can not only move forwards, backwards and turn around while aiming with the mouse freely, but also strafe left and right. Next time I should consider using version control so that way when mishaps happen, at least there's a version I can go back to and replace the broken code with the early clean code in seconds rather than spend days fixing code.
I could not sync the two maps separately in case each client wanted to play on different maps. Should this happen, it syncs all the Player's current position and shows them on two different screens with different maps chosen. This could be they share the same server ID, so I should generate a different ID so Players don't accidentally end up in someone else's screen, get shot easily and lose the game unfairly.
I could have added a snapping mechanics to obstacles built by Players so they can snap onto corners just like the game Fortnite, but it wasn't included in the course, and I didn't feel I needed to learn it since I want to focus more on creating first-person shooting games at this time.
Made a mechanic for the Storm trigger box warning if the Player is in the storm by UI, though it can get a little glitchy. I could have used an enumerator to ease it appearing on screen and not glitch flash, but I did not want to overcomplicate the project since this was already a challenging project to begin with.
I would have loved it if the Player character model aimed wherever the mouse points too like in traditional third person shooters, but it was not included in the course, so I decided to let it go for now.
When firing any weapon, then you collect a new weapon of the same type you used, it refills your clip. Next time I should code that it gives you more ammo amount rather than refilling your clip to prevent unfair advantages to Players.
The aiming around walls can be a little tricky to hit your precise targets, I will need to find out a better way for third person characters to raycast better, so Players don't think the game is broken if their raycasts ends up hitting the walls instead.
I could have done better with the clipping of the player camera, but I only realised it late in development, I'm letting it go for now.
I realised late in development that the doors don't move on all clients' screens, I should have added network code in advance, so it does not create unfair advantages to Players. I'm also letting it go for now
I couldn't get the Player to display their Axe model when they first hit the ground from an energy ball, I will need to think of a better way to show the Player's axe at the start of the game next time. It could be that refresh weapon command/rpc code that's causing it to do so, but I decided to let it go for now since I spend more than a year on this project already.
OVERALL:
This was a difficult course to learn and execute, but I am glad it has helped me gain a better understanding of how of network code works, but I am not 100% satisfied with what I learned, so I would need to learn more network code in order to create a new flawless multiplayer game for commercial purposes. However, the other things I learned such as game design, level design, gun mechanics and other advanced code I am very satisfied with and happy that I can utilise that knowledge for my first-person shooter projects.
I am probably going to stick to making first person shooters for single player for a while until my network code has increased or I may hire a programmer to integrate the network code for me in my future games.

Comments