Welcome back to day 25! We’re officially ¼ of our way to the goal!
Today is going to be relatively short, we’re going to:
- finish our Enemy Spawning system by adding a victory state
Let’s get started!
Step 1: Creating the Victory Panel
The first thing we need to do is create another panel that tells the user that they won the game.
Instead of going through the work of creating another UI and animation for our Victory Panel, we’re going to take the easy approach and make a duplicate of our existing GameOver game object and re-purpose it.
Currently, we can use the same script and animator, because they both do the same thing.
Duplicate GameOver
To do that, select GameOver in our hierarchy and then hit Ctrl + D to make a duplicate. Rename the duplicate to Victory. They can both just stay in the canvas.
Changing Victory Text
Now that we have our Victory panel, we need to change our text so that the players will know that they won.
Select Victory > Text (not Button > Text) and change the words from “Game Over” to “You win!”
Step 2: Writing the code to use our new Victory Panel
Now that we have a fully functioning Victory Panel, it’s time to use it!
We’re going to have to change 2 scripts to make this work:
- GameManager
- SpawnManager
Updating the GameManager Code
The first thing that we’re going to do is setup GameManager to use our Victory panel.
Here’s our code:
using UnityEngine;
public class GameManager : MonoBehaviour
{
public Animator GameOverAnimator;
public Animator VictoryAnimator;
private GameObject _player;
void Start()
{
_player = GameObject.FindGameObjectWithTag("Player");
}
public void GameOver()
{
GameOverAnimator.SetBool("IsGameOver", true);
DisableGame();
}
public void Victory()
{
VictoryAnimator.SetBool("IsGameOver", true);
DisableGame();
}
private void DisableGame()
{
_player.GetComponent<PlayerController>().enabled = false;
_player.GetComponentInChildren<MouseCameraContoller>().enabled = false;
_player.GetComponentInChildren<PlayerShootingController>().enabled = false;
Cursor.lockState = CursorLockMode.None;
}
}
New Variables
The only new code was that we added the VictoryAnimator, like GameOverAnimator, this is the animator for our victory panel.
Walking through the code
Here’s how our code works:
- I created a new public Victory() that our SpawnManager will call to trigger our Victory Panel animation.
- To keep our code clean, I moved the code that was previously in GameOver() into DisableGame() that way we don’t have to write the same code twice in both Victory() and GameOver()
Updating the SpawnManager Code
Now that our GameManager can play our victory animation, we need to call it when we win the game from our SpawnManager.
Here’s the code for this:
using System.Collections;
using UnityEngine;
[System.Serializable]
public class Wave
{
public int EnemiesPerWave;
public GameObject Enemy;
}
public class SpawnManager : MonoBehaviour
{
public Wave[] Waves; // class to hold information per wave
public Transform[] SpawnPoints;
public float TimeBetweenEnemies = 2f;
private GameManager _gameManager;
private int _totalEnemiesInCurrentWave;
private int _enemiesInWaveLeft;
private int _spawnedEnemies;
private int _currentWave;
private int _totalWaves;
void Start ()
{
_gameManager = GetComponentInParent<GameManager>();
_currentWave = -1; // avoid off by 1
_totalWaves = Waves.Length - 1; // adjust, because we're using 0 index
StartNextWave();
}
void StartNextWave()
{
_currentWave++;
// win
if (_currentWave > _totalWaves)
{
_gameManager.Victory();
return;
}
_totalEnemiesInCurrentWave = Waves[_currentWave].EnemiesPerWave;
_enemiesInWaveLeft = 0;
_spawnedEnemies = 0;
StartCoroutine(SpawnEnemies());
}
// Coroutine to spawn all of our enemies
IEnumerator SpawnEnemies()
{
GameObject enemy = Waves[_currentWave].Enemy;
while (_spawnedEnemies < _totalEnemiesInCurrentWave)
{
_spawnedEnemies++;
_enemiesInWaveLeft++;
int spawnPointIndex = Random.Range(0, SpawnPoints.Length);
// Create an instance of the enemy prefab at the randomly selected spawn point's position and rotation.
Instantiate(enemy, SpawnPoints[spawnPointIndex].position, SpawnPoints[spawnPointIndex].rotation);
yield return new WaitForSeconds(TimeBetweenEnemies);
}
yield return null;
}
// called by an enemy when they're defeated
public void EnemyDefeated()
{
_enemiesInWaveLeft--;
// We start the next wave once we have spawned and defeated them all
if (_enemiesInWaveLeft == 0 && _spawnedEnemies == _totalEnemiesInCurrentWave)
{
StartNextWave();
}
}
}
New Variables
In our code, we created a new private _gameManager which will be how we access our GameManager.
Walking through the code
The code is straightforward:
- In Start() we get an instance of our GameManager script by looking for SpawnManager’s parent, which in this case is the GameManager game object. Then we just take the script from there.
- We use _gameManager in StartNextWave(), when we have completed all the waves in the game.
Step 3: Setting up our script components in Unity
We have the script ready, the final thing for us to do is for us to add our new Victory game object to our script.
When selecting our GameManager in our Game Manager script drag our Victory game object into the Victory Animator slot. Unity will automatically pull the animator from the game object for our script.
Conclusion
Now that we have set our victory animation, if we were to play the game and win, we’ll have something happen!
Specifically, this!
This will be the end of our Spawning System (for now).
I’m hoping to introduce at least 2 more enemies into the game, so we’ll have to come back, but for this simple FPS, our spawning system is complete.
Tomorrow, my plan is to go and fix minor parts of the game that we glanced over and then move on to adding more units!
See you then!
Source: Day 25
Visit the 100 Days of Unity VR Development main page.
Visit our Homepage
Day 25 and you finally have something you can call a game.
These tutorials of yours is a fantastic way for beginners to see how games are made and why they take so long. Also good for you, when you reach day 100 you will be able to look back and see how you got there.
Keep up the good work, I enjoy reading your tutorials.