Well done so far. You have added basic functionality like jumping, physics, and running to the PlayerController
object. We are definitely going in the right direction here. The next important step is writing a neat GameManager
class to help us control the game events like:
StartGame
GameOver
Restart
For basic games like Jake on the mysterious planet, it is a good practice to have one instance of the GameManager
running and controlling all main events in the game. The gameplay
loop is simply a journey from the gameplay start to the gameplay phase and the game over phase. Time to write some code!
Let's create a new C# script and call it GameManager
, and write the following code:
As you can see, nothing is very complicated. We wrote very simple methods to help us control the main game events. This script does nothing yet; however, please add it to the Unity Scene. Create a new game object call it GameManager
, and add the GameManager
component to it. We will use it in the future...
By implementing the singleton pattern for GameManager
, we can easily access it from anywhere using one single point of access. I guess you will feel really confused about this now. A simple example will help you get your head around it.
"In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system." | ||
--Wikipedia |
Let's add the following code to the GameManager
class. Declare a new public static variable. This code should be written right next to other public variables:
public static GameManager instance;
Then, add an Awake
method with the following line.
void Awake() { instance = this; }
That's it! This is all the code you need for a simple access to the GameManager
instance from anywhere in your code. It is important to remember that only one instance of this component can be present in the whole Unity Scene. To access any...
At the moment, our gameplay starts automatically after pressing the Play button in Unity. This was convenient for testing running and jumping. If you look into the Start
method in GameManager
, you will notice we are calling the start game there. Let's remove that line and keep the Start
method empty for now.
Further in the development of this game, we will have a nice Graphic User Interface (GUI) to control the game states by pressing buttons like Start Game, Restart, and so on. For now, we should focus on functionality only and leave the GUI for later. However, we do need an easy way to call the events at runtime. Why not use the keyboard for now? You probably remember using Input.GetKeyDown
. If you don't remember much, dive into Unity Scripting Reference again and search for Input.GetKeyDown
.
Let's say when each time user presses S on the keyboard, we will fire up the StartGame
method on GameManager
. Before we start adding code, we need to make sure that currentGameState...
One more thing that's missing now is adding s
into Unity's build in InputManager
. To do that, follow these simple steps.
Open InputManager by going to Edit | ProjectSettings | Input.
Increase input size of Axis by 1.
Select the bottom Axis and change its settings.
We have a new input button set up as well as the code executed each time the button is pressed. Time to test that. Press Play in Unity and, after Jake drops on the platform, press S on the keyboard. The StartGame()
method will be called by Unity just after you pressed the key. The StartGame()
method changes currentGameState
to inGame
so our gameplay starts.
So, we completed the first part of the simple gameplay
loop. The user can start the game by pressing the button and the game will start. As we are calling it a loop, it will have to be a closed chain of events. To close the gameplay, we will need to add the GameOver
event.
In our simple game, the game over event will be called when the player dies. There will...
We can easily configure any collider in Unity to work like a trigger. Triggers are very useful. In this case, we will use them to detect whether our character has fallen into the hole. I have already prepared another useful prefab for you, so we won't waste any time setting it up. The steps are as follows:
Import KillTrigger.unitypackage
into your project.
Drag Kill
trigger into your project.
Position the KillTrigger
game object so the red area is below the ground.
This is all we need in the Scene view. Once Jake drops down from the end of the platform, he will most certainly fall through the red trigger zone. Now, we need to write some code to describe this behavior. It will be a very simple component added to the KillTrigger
game object.
Create new a C# script, call it KillTrigger
, and write the code so it looks like this:
As you can see, there is nothing complicated here. We use the OnTriggerEnter2D
method. It is called automatically by Unity whenever another 2D collider enters...
At this moment, we have a very simple gameplay. We can ask the game to start and we know when the player is finished. All that's missing to complete the game loop is the ability to restart the game.
Restarting the game should be done by the user by pressing the button on the screen or by pressing the button on the keyboard. Let's use the same input event we already have to start the game. The main difference between starting and restarting the game is that actual conditions in the game might be much different. For example, the player's position in the game will be different. In fact, this is a good starting point. Let's make sure every time the game starts, the player's initial position is the same.
Every time our game starts, we should reset all its conditions to the same state. We already mentioned that resetting the starting position of the
Player game object would be a good start. Positions in the 3D world in Unity are described using Vector3 struct
. Go ahead and type Vector3
in the Scripting Reference for a better understanding. This is complex stuff, so don't worry if you can't get it. All you need to know now is that Vector3
is made up of three floats describing x, y, and z positions in the space.
Let's go forward and perform some code changes to set up the Player position. In PlayerController
, we will:
Add private Vector3
type variable and call it startingPosition
in PlayerController
.
Assign the startingPosition
value taken from the Player game object world space position in the Awake
method. This way, we will always store the initial position of the Player game object just after Unity starts executing the game.
Rename the Start
method to...
using UnityEngine; using System.Collections; public enum GameState { menu, inGame, gameOver } public class GameManager : MonoBehaviour { public static GameManager instance; public GameState currentGameState = GameState.menu; void Awake() { instance = this; } void Start() { currentGameState = GameState.menu; } //called to start the game public void StartGame() { PlayerController.instance.StartGame(); SetGameState(GameState.inGame); } //called when player die public void GameOver() { SetGameState(GameState.gameOver); } //called when player decide to go back to the menu public void BackToMenu() { SetGameState(GameState.menu); } void SetGameState (GameState newGameState) { if (newGameState == GameState.menu) { //setup Unity scene for menu state } else if (newGameState == GameState.inGame) { //setup Unity scene for inGame state } else if...