The course is really showing its value since I’ve been able to refactor all of this and run it in my first attempt without errors
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using UnityEngine;
public class ScoreKeeper : MonoBehaviour
{
private static ScoreKeeper Instance;
private UIDisplay uiDisplay;
private int score = 0;
private int time = 0;
private int wave = 0;
private void Awake() {
uiDisplay = FindObjectOfType<UIDisplay>();
ManageInstance();
}
private void ManageInstance() {
if (Instance != null) {
gameObject.SetActive(false);
Destroy(gameObject);
} else {
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
public int GetScore() {
return score;
}
public void ModifyScore(int amount) {
score += amount;
Mathf.Clamp(score, 0, int.MaxValue);
uiDisplay.UpdateScore(score);
}
public void ResetScore() {
score = 0;
}
public void ResetWaves() {
wave = 0;
}
public int GetWave() {
return wave;
}
public void ModifyWave(int amount) {
wave += amount;
Mathf.Clamp(wave, 0, int.MaxValue);
}
public int GetTimePlayed() {
return time;
}
public void SetTimePlayed(float timePlayed) {
time = (int)timePlayed;
}
}
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class UIGameOver : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI scoreText;
[SerializeField] private TextMeshProUGUI waveText;
[SerializeField] private TextMeshProUGUI timeText;
ScoreKeeper scoreKeeper;
private void Awake() {
scoreKeeper = FindObjectOfType<ScoreKeeper>();
}
private void Start() {
scoreText.text = "score:\n" + scoreKeeper.GetScore().ToString("000000000");
waveText.text = "wave: " + scoreKeeper.GetWave().ToString("0000");
timeText.text = "time: " + scoreKeeper.GetTimePlayed().ToString("0000");
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
public class Health : MonoBehaviour
{
[Header("General")]
[SerializeField] private int healthMax = 50;
[SerializeField] private ParticleSystem explosionFX;
private int health;
[Header("Camera Shake")]
[SerializeField] private bool applyCameraShake = false;
CameraShake cameraShake;
[Header("Slow Motion")]
[SerializeField] private bool applySlowMotion = false;
[SerializeField] private float slowMotionDuration = 2f;
[SerializeField] private float slowMotionTimeScale = 0.5f;
private float sloMoTimer = 0f;
private bool gotHit = false;
[Header("Score Points per Death")]
[SerializeField] bool isPlayer = false;
[SerializeField] private int scorePerDeath = 10;
private AudioPlayer audioPlayer;
private ScoreKeeper scoreKeeper;
private UIDisplay uiDisplay;
LevelManager levelManager;
private void Awake() {
health = healthMax;
levelManager = FindObjectOfType<LevelManager>();
uiDisplay = FindObjectOfType<UIDisplay>();
audioPlayer = FindObjectOfType<AudioPlayer>();
cameraShake = Camera.main.GetComponent<CameraShake>();
scoreKeeper = FindObjectOfType<ScoreKeeper>();
}
private void OnTriggerEnter2D(Collider2D collision) {
DamageDealer damageDealer = collision.GetComponent<DamageDealer>();
if(damageDealer != null) {
TakeDamage(damageDealer.GetDamageValue());
PlayExplosionFX();
damageDealer.Hit();
ShakeCamera();
gotHit = true;
audioPlayer.PlayDamageTakenClip();
UpdateUI();
}
}
private void UpdateUI() {
if (isPlayer) {
uiDisplay.UpdateHealth(healthMax, health);
}
}
private void Update() {
if (applySlowMotion && gotHit) {
SlowMotion();
}
}
private void TakeDamage(int damageValue) {
health -= damageValue;
if(health <= 0) {
Die();
}
}
private void Die() {
if (!isPlayer) {
scoreKeeper.ModifyScore(scorePerDeath);
} else if (isPlayer) {
scoreKeeper.SetTimePlayed(Time.timeSinceLevelLoad);
levelManager.LoadDeathScene();
}
Destroy(gameObject);
}
private void PlayExplosionFX() {
if (explosionFX != null) {
ParticleSystem instance = Instantiate(explosionFX, transform.position, Quaternion.identity);
Destroy(instance.gameObject, instance.main.duration + instance.main.startLifetime.constantMax);
}
}
private void ShakeCamera() {
if (cameraShake != null && applyCameraShake) {
cameraShake.Play();
}
}
private void SlowMotion() {
Time.timeScale = slowMotionTimeScale + ((1 - slowMotionTimeScale) * (sloMoTimer / slowMotionDuration));
sloMoTimer += Time.deltaTime;
if (Time.timeScale >= 1) {
Time.timeScale = 1;
gotHit = false;
sloMoTimer = 0f;
}
}
public int GetHealth() {
return health;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
[SerializeField] private List<WaveConfigurationSO> waveConfigurationSOs;
[SerializeField] private float timeBetweenWaves = 0f;
[SerializeField] private bool isLooping = true;
private WaveConfigurationSO currentWave;
private int waveCount = 0;
private UIDisplay uiDisplay;
private ScoreKeeper scoreKeeper;
private void Awake() {
uiDisplay = FindObjectOfType<UIDisplay>();
scoreKeeper = FindObjectOfType<ScoreKeeper>();
}
private void Start() {
StartCoroutine(SpawnEnemyWaves());
}
public WaveConfigurationSO GetCurrentWaveSO() {
return currentWave;
}
private IEnumerator SpawnEnemyWaves() {
do {
foreach (WaveConfigurationSO waveConfigurationSO in waveConfigurationSOs) {
currentWave = waveConfigurationSO;
waveCount++;
uiDisplay.UpdateWave(waveCount);
scoreKeeper.ModifyWave(1);
for (int i = 0; i < currentWave.GetEnemyCount(); i++) {
Instantiate(currentWave.GetEnemyPrefab(i),
currentWave.GetStartingWaypoint().position,
Quaternion.Euler(0, 0, 180),
transform);
yield return new WaitForSeconds(currentWave.GetRandomSpawnTime());
}
yield return new WaitForSeconds(timeBetweenWaves);
}
} while (isLooping);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor.SearchService;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelManager : MonoBehaviour
{
[SerializeField] private float deathLoadDelay = 2f;
private ScoreKeeper scoreKeeper;
private void Awake() {
scoreKeeper = FindObjectOfType<ScoreKeeper>();
}
public void LoadGameScene() {
if (SceneManager.GetActiveScene().buildIndex == 2) {
ResetWavesAndScore();
}
SceneManager.LoadScene(1);
}
public void LoadMainMenu() {
ResetWavesAndScore();
SceneManager.LoadScene(0);
}
public void LoadDeathScene() {
StartCoroutine(WaitAndLoad(2, deathLoadDelay));
}
public void QuitGame() {
Application.Quit();
}
private IEnumerator WaitAndLoad(int sceneIndex, float delay) {
yield return new WaitForSeconds(delay);
SceneManager.LoadScene(sceneIndex);
}
private void ResetWavesAndScore() {
scoreKeeper.ResetScore();
scoreKeeper.ResetWaves();
}
}