Hi and welcome back to day 22 of the 100 days of VR!
Yesterday, we created our game over panel to show to the player when they lose, however in the current state of the game, the game over panel is being displayed at the start of the game.
Today, we’re going to:
- Create a new state controller for our animation so that we don’t instantly play our animation
- Play the animation when the player is defeated and all states related to that
- Restart the game when the player selects to play again
There’s a lot ahead of us today, so let’s get started!
Creating an Animation State Controller
Right now, our animation just plays whenever the game starts.
The reason for that is, because of our animator controller.
Go to our GameOver.controller
in the Animation folder and double click it to open it up in our Animator
tab.
Right now, Game Over
is the default state we transition into from Entry
.
As a result, we always play the Game Over
clip that’s attached to it be default when we start our game.
To fix this, we’re going to do a couple of things. We’re going to:
- create a new default state, called
Start
that is our default transition from Entry
that transitions into our Game Over
state - create a new boolean parameter
IsGameOver
- set a transition from
Start
to Game Over
- select the transition arrow from
Start
to Game Over
and create a new condition: IsGameOver
= true
After you’re done, you should have something like this:
Now if we’re to play our game again, nothing will show up!
Playing the Game Over Animation
Now that we have the correct game states set up, it’s time to use it.
All we need to do is play the animation when our player’s health drops to 0
.
Here are the changes we’re going to do:
- Create a new
GameManager
script that will take care of the logic of the ending - Change our
PlayerHealth
script to use the GameManager
to tell it when the game is over.
The first thing we’re going to do is create an empty game object that we’ll call GameManager
.
Then, create a new script called GameManager
and attach it to our new game object.
Here’s what our GameManager
script will look like:
using UnityEngine;
public class GameManager : MonoBehaviour
{
public Animator GameOverAnimator;
public void GameOver()
{
GameOverAnimator.SetBool("IsGameOver", true);
}
}
The code right now is straightforward:
- We get the
GameOverAnimator
from our Game Over
object and we take the Animator
from it. - We create a
public
GameOver()
that someone will call that will set our IsGameOver
parameter to be true
so that we’ll play the animation to show our game over panel.
When you’re done with the script, make sure to set our GameOver
UI GameObject
to our GameOverAnimator
slot in our GameManager
component.
Quick Note on Pushing vs Pulling for Updates
For those of you who saw Unity’s tutorial, I’m not actually a big fan of what Unity does with having all of these checks in the Update()
, where we’re always checking for something to happen.
Personally, I prefer to take a more push functionality where we only do something, if something else notifies us of it happening.
A perfect example of a push approach is our public GameOver()
. Currently, we have some other script call the function to indicated game over.
An example of pulling is that we have a script that checks for changes every frame. For example, we could have given GameManager
a reference the player Game Object
and in Update()
it could constantly check to see if the player is dead.
Both way works, I just prefer the way where we only do something when we’re told to do it and not check every frame.
Using our GameManager
After creating our GameManager
, we need to use it.
In this particular case, we’re going to use it in our PlayerHealth
script. We’re going to:
- Add our
GameManager
object - Call
GameOver()
when the player’s health is 0
or below
Here’s our code:
using UnityEngine;
using UnityEngine.UI;
public class PlayerHealth : MonoBehaviour
{
public Slider HealthBar;
public float Health = 100;
private float _currentHealth;
private GameManager _gameManager;
void Start ()
{
_currentHealth = Health;
_gameManager = Object.FindObjectOfType<GameManager>();
}
public void TakeDamage(float damage)
{
_currentHealth -= damage;
HealthBar.value = _currentHealth;
if (_currentHealth <= 0)
{
_gameManager.GameOver();
}
}
}
The code here is also straightforward:
- We create a
private
field for our GameManager
class - In
Start()
, we instantiate our GameManager
- In
TakeDamage()
, after our player takes damage and health falls to 0
, we would call GameOver()
which will show the Game Over
panel.
Restarting the Game
Now that we have our game over
panel showing up, it’s time for us to disable some functionality so that we can click on the restart button!
There’s a couple of things we need to:
- In
GameManager
, when GameOver()
is called, disable the player’s movements and re-enable our cursor to select a button - Create a
GameOverUIManager
that will deal with the logic of clicking a button - Change our
GameOver
game object’s Canvas
Group to ignore parent elements and check the Blocks Raycasts
option so we can click on the button
Updating GameManager to Disable the Player in Game Over
When the game is over, we want to:
- Disable all the scripts that are involved with the controls of the player. It would be weird that at game over, we can still move around and shoot.
- Re-enable our Cursor which we locked in the center of the game.
Here are the changes we made to GameManager
:
using UnityEngine;
public class GameManager : MonoBehaviour
{
public Animator GameOverAnimator;
private GameObject _player;
void Start()
{
_player = GameObject.FindGameObjectWithTag("Player");
}
public void GameOver()
{
GameOverAnimator.SetBool("IsGameOver", true);
_player.GetComponent<PlayerController>().enabled = false;
_player.GetComponentInChildren<MouseCameraContoller>().enabled = false;
_player.GetComponentInChildren<PlayerShootingController>().enabled = false;
Cursor.lockState = CursorLockMode.None;
}
}
As you can see, we:
- Created a reference to our player character in
Start()
- In
GameOver()
, we disabled the player movement script, our mouse script, and our shooting script. We also re-enabled our lock
With this, if you were to play the game right now and let our player die, we regain our mouse and we won’t be able to control our player anymore.
Creating the Code for our UI Button Click
Next, we need some code to take care of what happens when we click on our button.
To do that, we need to create an onClick event listener for our button.
For those of us that aren’t familiar with the concept of event listeners, you can think of it as code that will only execute when you take a certain action.
In this specific instance, our Button
has a onClick
event listener so it’ll wait for whenever the user clicks on the button.
When someone does click the button, they’ll execute any function that was passed to it. In this case, our restart code.
Let’s get started.
First, create a new script for our GameOver
game object in the hierarchy. We’re going to call it GameOverUIManager
. We’re going to use it to manage our play the game when the user clicks play again.
Here’s what it looks like:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameOverUIManager : MonoBehaviour
{
private Button _button;
void Start () {
_button = GetComponentInChildren<Button>();
_button.onClick.AddListener(ClickPlayAgain);
}
public void ClickPlayAgain()
{
SceneManager.LoadScene("Main");
}
}
Now let’s walk through the code:
- We have a
private
_button
that is the button from our Game Over
Panel. - In
Start()
, we instantiate our button and we set the OnClick Listener
to our button to run ClickPlayAgain()
whenever the user clicks the button - In
ClickPlayAgain()
, we use the SceneManager
to restart our scene so we can play again. As we might recall, everything in Unity runs in a scene, SceneManager
is what we use to help us transition from one scene to the next.
Note: using LoadLevel
is depreciated for SceneManager
Now with all of this, we’re almost done!
If we were to try and play the game now and let the knight beat us, you’ll realize a problem. We can’t click on the Restart button!
Let’s fix it.
Allow Clicking on the Button UI
The main reason why we can’t touch our button UI is because of our Group Canvas
component attached to HUD
. We disabled everything so that our UI will just be something the user sees.
We could enable Interactable
and Block Raycasts
so that our Graphics Raycaster
script will be able to detect the button being clicked, like explained here.
However, if we were to do that, the problem is that everything else in the game would become interactable, including our health bar!
We don’t want that, so instead we’re going to make a separate Canvas Group
component just for GameOver.
We need to do 2 things:
- Add a new
Group Canvas
component and check all settings so that we can interact with our game over panel and ignore the rules set by the parents. - Add a
<a href="https://docs.unity3d.com/Manual/script-GraphicRaycaster.html">Graphic Raycaster</a>
, which is used to detect if the user clicks on anything in the canvas
.
Once we have these setup, play the game again and you’ll see that we can restart the game!
Conclusion
We did a lot of work today!
We:
- created a new animation state for our
GameOver
animations - enabled our animation when our player is defeated
- allowed the user to restart the game when they lose
There are some more things that we can add to our Game Over
scene to make things more complete, however, tomorrow, we’ll jump into a new topic, specifically enemy spawning!
Until then!
Day 21 | 100 Days of VR | Day 23
Home
CodeProject
The post Day 22: Creating the Game End State and Game Over Animation appeared first on Coding Chronicles.