This repository has been archived on 2024-11-20. You can view files and clone it, but cannot push or open issues or pull requests.
colourmeok/ColourMeOKGame/Assets/Scripts/GameManager.cs

165 lines
5.8 KiB
C#
Raw Normal View History

2024-11-17 23:17:24 +08:00
using System;
2024-11-15 07:54:43 +08:00
using UnityEngine;
2024-11-17 22:31:03 +08:00
using UnityEngine.UIElements;
2024-11-15 07:54:43 +08:00
/// <summary>
/// singleton for a single source of truth game state and flow management
/// </summary>
public class GameManager : MonoBehaviour
{
/// <summary>
/// singleton pattern: define instance field for accessing the singleton elsewhere
/// </summary>
public static GameManager Instance;
2024-11-17 22:31:03 +08:00
/// <summary>
/// ui manager object for handling ui state and flow
/// </summary>
public UIManager ui;
2024-11-17 07:29:22 +08:00
/// <summary>
2024-11-17 22:05:04 +08:00
/// the local player data object for storing player data
2024-11-17 21:32:14 +08:00
/// </summary>
2024-11-17 22:05:04 +08:00
private LocalPlayerData _localPlayerData;
2024-11-17 21:32:14 +08:00
/// <summary>
/// backend object for handling communication with the firebase backend
/// </summary>
public Backend Backend;
2024-11-17 22:05:04 +08:00
2024-11-15 07:54:43 +08:00
/// <summary>
/// enforces singleton behaviour; sets doesn't destroy on load and checks for multiple instances
/// </summary>
private void Awake()
{
// check if instance hasn't been set yet
if (Instance == null)
{
Debug.Log("awake as singleton instance, setting self as the forever-alive instance");
Instance = this;
DontDestroyOnLoad(gameObject);
}
// check if instance is already set and it's not this instance
else if (Instance != null && Instance != this)
{
Debug.Log("awake as non-singleton instance, destroying self");
Destroy(gameObject);
}
2024-11-17 22:31:03 +08:00
}
private void Start()
{
// load the local player data and refresh the ui
_localPlayerData = new LocalPlayerData();
_localPlayerData.LoadFromTheWorld();
PopulateFields();
2024-11-17 23:17:24 +08:00
try
{
RenderFromPlayerData();
}
catch (Exception)
{
// TODO: remove this once the bug is fixed
Debug.LogWarning("handling known exception, remove this once the bug is fixed");
}
2024-11-17 07:29:22 +08:00
2024-11-17 22:31:03 +08:00
// register a callback to refresh the ui when the player signs in
2024-11-17 23:17:24 +08:00
Backend.RegisterOnSignInCallback(_ =>
{
Debug.Log("sign in callback, refreshing GameManager-controlled SideView UI");
_localPlayerData.LoadFromTheWorld();
PopulateFields();
RenderFromPlayerData();
});
2024-11-17 19:10:01 +08:00
}
2024-11-17 07:29:22 +08:00
/// <summary>
2024-11-17 22:05:04 +08:00
/// called when the game object is enabled, initialises variables
2024-11-17 07:29:22 +08:00
/// </summary>
private void OnEnable()
2024-11-17 07:29:22 +08:00
{
Backend = new Backend();
Backend.Initialise();
2024-11-17 22:05:04 +08:00
ui = UIManager.Instance;
2024-11-17 07:29:22 +08:00
}
2024-11-17 22:31:03 +08:00
/// <summary>
/// called when the application is quitting, saves the local player data
/// </summary>
private void OnApplicationQuit()
2024-11-17 07:29:22 +08:00
{
2024-11-17 22:31:03 +08:00
Debug.Log("running deferred cleanup/save functions");
Backend.Cleanup();
_localPlayerData.SaveToTheWorld();
2024-11-17 07:29:22 +08:00
}
2024-11-17 19:10:01 +08:00
/// <summary>
2024-11-17 22:31:03 +08:00
/// populate the fields with the given username and email, used by GameManager after local player data is loaded
2024-11-17 19:10:01 +08:00
/// </summary>
2024-11-17 22:31:03 +08:00
public void PopulateFields()
2024-11-17 19:10:01 +08:00
{
2024-11-17 23:17:24 +08:00
Debug.Log(
$"populating AccountView fields with lkUsername={_localPlayerData.LastKnownUsername} and lkEmail={_localPlayerData.LastKnownEmail}");
2024-11-17 22:31:03 +08:00
ui.UI.Q<TextField>("UsernameField").value = _localPlayerData.LastKnownUsername;
ui.UI.Q<TextField>("EmailField").value = _localPlayerData.LastKnownEmail;
2024-11-17 19:10:01 +08:00
}
2024-11-17 23:17:24 +08:00
/// <summary>
/// function to update the ui with the latest data
/// </summary>
private void RenderFromPlayerData()
{
// calculate averages from both recent local scores and online scores
var totalLightnessAcc = 0f;
var totalChromaAcc = 0f;
var totalHueAcc = 0f;
var totalRounds = 0;
// average out all the scores we have to get a stable-ish average
foreach (var localScore in _localPlayerData.RecentLocalScores)
{
totalLightnessAcc += localScore.AvgLightnessAccuracy;
totalChromaAcc += localScore.AvgChromaAccuracy;
totalHueAcc += localScore.AvgHueAccuracy;
totalRounds += localScore.NoOfRounds;
}
foreach (var onlineScore in _localPlayerData.RecentOnlineScores)
{
totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
totalChromaAcc += onlineScore.AvgChromaAccuracy;
totalHueAcc += onlineScore.AvgHueAccuracy;
totalRounds += onlineScore.NoOfRounds;
}
foreach (var onlineScore in _localPlayerData.BestOnlineScores)
{
totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
totalChromaAcc += onlineScore.AvgChromaAccuracy;
totalHueAcc += onlineScore.AvgHueAccuracy;
totalRounds += onlineScore.NoOfRounds;
}
Debug.Log($"tL={totalLightnessAcc} tC={totalChromaAcc} tH={totalHueAcc} tR={totalRounds}");
if (totalRounds == 0) totalRounds = 1;
var lightnessAcc = totalLightnessAcc / totalRounds;
var chromaAcc = totalChromaAcc / totalRounds;
var hueAcc = totalHueAcc / totalRounds;
var playerText = Backend.IsSignedIn ? _localPlayerData.LastKnownUsername : $"{_localPlayerData.LastKnownUsername} (Not Signed In)";
// finally, set the labels
ui.UI.Q<Label>("PlayerText").text = playerText;
ui.UI.Q<Label>("LightnessAccuracyText").text = $"{lightnessAcc:F}";
ui.UI.Q<Label>("ChromaAccuracyText").text = $"{chromaAcc:F}";
ui.UI.Q<Label>("HueAccuracyText").text = $"{hueAcc:F}";
// and set the player rating, but after we get it from the backend
// (god I LOVE async (I am LYING out of my teeth))
Backend.CalculateUserRating((dtr, rating) =>
{
if (dtr != Backend.DatabaseTransactionResult.Ok) return;
ui.UI.Q<Label>("RatingText").text = $"{rating:F}";
});
}
2024-11-15 07:54:43 +08:00
}