Continued from the previous instructables! We just left off with...
Step 1: Populator: Populator Manager
Now that we have the four populators created and added to our Game Manager gameobject, we need a manger to execute the code inside each populator. Inside the populator is a set of commands that spawn different objects. For example...
- PopulateWorld(): This function uses every populator in the list to spawn their game objects. This is usually used at the start of the game isn't really used anywhere else.
- ResetDynamicObject(): This function resets every objects that are dubbed "Dynamic." Dynamic objects are objects that the player can interact with. This is usually needed when the game has to resupply the player.
- DestroyWorld(): This function does what it says on the tin, it destroys every game object that was spawned using the populators. This isn't really used but I included it just in case if I ever needed.
- ChangeDifficultyLevel(): The zombie populator and crate populator's stats are determined by a number called DifficultyLevel.
Every function simply uses the references we created early in the script. They call the populator's function to populate the world, and for the populators that need a list of randomly generated positions, we just give those functions their own functions that generate random positions.
And also notice how the doesn't do a lot of executing code. The only code it executes is PopulateWorld() at start to spawn game objects and then sets Difficultylevel at 1. (Picture 1) is the finished result.
Step 2: Day System: Goals and Solutions
Now that we're done with the populator system, some of you may asking how the DifficultyLevel. As the game goes on, we need the difficulty of the game to increase. And that brings up two problems we have to make solutions for.
- How do we increase difficulty
- How do we do that over time
The solutions I came up were created using the populator system.
- We'll increase difficulty by increasing the number of zombies and crates so that the player has more enemies but more supplies to use.
- We'll have a day system where the player can sleep after all the zombies are killed on the map, adding onto a number we'll create which will track the days. At certain days, we'll increase the difficulty of the game by changing the DifficultyLevel number.
First we'll start with the sleeping system.
Step 3: Day System: Homestead Clickable
So our first problem: Letting the player essentially "sleep" and pass the days. When they do this the game will increase the difficulty and reset the dynamic objects in the world. So we allow the player to sleep by having an object they can click on to reset the dynamic objects and reset the world!
- We make the script inherit from ClickableParent so we can the player can click on it
- We make a DayCountManager reference in the script. We'll cover this later, but for right, all you need to know is that we call it to go tell the populations to update.
- We fade the screen to black then call a function in the DayCountManager reference.
- We then fade the screen back.
The script is pretty filled with UI references and fading to black, but for right now, all you need to know is that the script, when clicked, calls on DayCountManager. I will touch on UI on a later section, but right now, I'll go on to the DayCount Manager.
Step 4: Day System: Day Count Manager
We also have to implement a increasing difficulty stem. We do this using our DayCountManager, which does...
- Adds to the current day
- Resets the crates and zombies in the world
- Checks if the current day is between a threshold and changes difficulty
The Day Count Manager doesn't actually execute any code. The code inside is called by the Sleep_Clickable script when the player clicks on it. Essentially, the script order goes like this
- Sleep Clickable calls on DayCountManager when clicked on
- DayCountManager calls the PopulatorManager to change the DifficultyLevel
- The PopulatorManager calls on each of the populations inside the script, using DifficultyLevel to change different numbers to spawn
And with that, every one of our initial design goals is complete! Now is finishing touches, starting with audio.
Step 5: Audio: Making Noise!
If you've played the game up to this point, you'll notice something. Or, more accurately, you won't notice anything, as there is no sound. Now, we need to add sound. Audio is made up of three components in Unity
- An Audio listener, which acts as a pair of ears that the player listens through
- Audio Clips are files that contain sounds. They are treated as assets like prefabs. All the audio in the game was pulled from Freesound.org, which provides free sounds for games.
- Audio Sources which use Audio Clips to act as an emitter of sound. Audio Sources contain the commands to actually play the sounds.
The way the sounds is implemented in the game is a bit more complicated but I'll go through the two main methods.
- Having an audio source on every object and playing clips from there. This makes sounds realistic as they became fainter and quieter as you move away from them.
- Having an audio source on the player and getting that component, playing audio through that. While this makes sounds less realistic, it allows us to play audio when the game object has to be immediately destroyed.
First we'll start with the first method, having the audio source on the game object.
Step 6: Audio: Audiosource on the Game Object
The first method is to have the AudioSource emit sound from the game objects. Because of the way audio components are built, this lets us have realistic sound out of the box. An example of gameobjects with audio sources on them would be zombies.
- Zombies snarling will be playing while they're still alive, so we don't have to worry about the audio being cut off
- Because of that, we can reliably use the first method.
- Look below at the zombie code. A majority of the code has been removed but I've left in the parts that matter to audio.
With the script below, all we would need to do is to attach an AudioSource component to the zombie game object, and then find audio clips and drag them in into the script in the editor (Picture 1).
Step 7: Audio: Audio Sources NOT on the Game Object
The second method is to have the game object find the audio source on the player and then use that audio source. This has the main advantage of not being tied down to a game object. Because Audio Components are deleted along with the rest of the GameObject, we can't use them. So, instead, we...
- Get told to proceed with input
- Use GameObject.find and find the Player GameObject so the
- Use that source to Play(OneShot)
An example of this method would be food items. Because food items are destroyed immediately afterwards, we need to use an external audio source. We get the Audio Source on the player, and play the audio through that source.
However, the audio clip is still assigned to the food object in the editor, like before. (Picture 1) Every object uses these two methods. So in summary...
- Every object that needs to make noise has a clip in their script
- If the object makes sound without being destroyed, it will have an AudioSource on the object
- If the objects makes sound and then is destroyed, it finds the AudioSource on the player and uses that
Now the audio is done, and for the final touch for the game, UI and Player Death!
Step 8: User Interface: Goals and Explanation
User Interface Goals
The game is fun, but now the issue is that the player doesn't have any information. The player can't see their health, the amount of ammo, etc. When we create our UI, we need to make sure to create...
- Gameplay UI showing Health, ammo, and other stat
- A main menu
Explanation of the UI
The UI system in Unity has its own separate "package" in the script, which means we'll have to use the "using" command to bring it in. The way it works in the editor is through a canvas system.
- The highest "layer" is the canvas object, which has the other individual UI elements inside it. By controlling the canvas, you can control things like the scale, visibility, etc of the UI elements inside it.
- The layer below the canvas object is where the individual UI elements reside. Elements like text, image, etc are here and can be controlled individually.
UI elements themselves can be treated like game objects, so the previous procedure to get game objects into scripts can be used for UI (Dragging them in using the editor, GetComponent<>)
In (Picture 1), MasterCanvas is the Canvas, which holds the EventSystem and another Canvas which itself holds the gameplay UI.
(Gif 1) is a demonstration of what the UI will look and act like.
(Picture 2) is what we'll be making in the next slide, making the gameplay UI.
Step 9: User Interface: Gameplay UI
The gameplay UI needs to include text that displays current health, water, hunger, and ammo. Because UI elements can be treated as game objects, we can create UI elements by right clicking on the hierarchy and going down to UI (Gif 1).
- We create four text elements under a single canvas, making sure to name them so we can easily use them later. We adjust their positions, sizes and scaling so that they're the appropriate size.
- We create the script above and attach it to our GameManager object. We drag in the text we just made and drag in the Player object into the script so the script has information.
Once the information and text has been dragged into the script, the text should start updating with the current numbers of Weapon_Parent and Player_Manager.
Now, we need to create our main menu.
Step 10: User Interface: Main Menu
Creating Main Menus
Unity game worlds are saved in the format of scenes. Scenes hold everything we've created so far (Player, populators, homestead, etc.) The first time saving in the editor, Unity would have prompted you to create one. Now there are two approaches to creating a main menu.
- Create a separate portion in the scene we already have and just teleport the camera.
- Create a new scene with the main menu.
While these two methods have advantages and disadvantages, the latter is useful in this case. In the first case, we would have to pause the populators and zombies from moving, and implement code. However, in the second method, we can use another package like UnityEngine.UI, UnityEngine.SceneManagement.
Before we get into the Main Menu, we need to understand how buttons work. Buttons themselves don't have any code in them. Buttons, in the editor, can use any public function in any script. So, in this case, we create a script that contains two functions (Picture 1).
Creating the Scene
We create a new scene, and then make a cube game object identical to the ground in the game scene. We drag in some prefabs, and then position the camera. From there, we create UI elements like the Buttons, editing them until we like how they look. We make sure to go into the editor and select the game object with the script below and assign the appropriate function. At the end, it should look like (Picture 2).
Step 11: Conclusion
And that's it! We have accomplished every goal in the game. To sum up...
- We created a top-down shooter using our weapon system and using recasting
- We created a randomly generated map using our popular system
- We create a day system where the player can sleep and increase difficulty level
- And we created a day a hunger and thirst system where the player has different things happen to them once they get below a certain threshold
Here I just wanna go over some software and credit some other places for different things that were really useful making the game.
Unity - The game engine the entire game is built in. Without Unity, the game wouldn't even exist.
Visual Code - The tool used to write the code. The brains of the project.
Blender - A 3D Modeling program. I didn't cover it in the project as the 3D modeling would fall more under art and not programming, which is what the instructables is primarily aimed toward.
Dafont.com - The website source for the 1942 font used in the game.
Freesound.org - The website which all the audio in the game is sourced from. Awesome resource for any game developer or any content creator in general.