diff --git a/ColourMeOKGame/Assets/Scenes/GameScene.unity b/ColourMeOKGame/Assets/Scenes/GameScene.unity
index 486551b..1298f4d 100644
--- a/ColourMeOKGame/Assets/Scenes/GameScene.unity
+++ b/ColourMeOKGame/Assets/Scenes/GameScene.unity
@@ -132,6 +132,7 @@ GameObject:
m_Component:
- component: {fileID: 133964672}
- component: {fileID: 133964671}
+ - component: {fileID: 133964676}
- component: {fileID: 133964673}
- component: {fileID: 133964674}
- component: {fileID: 133964675}
@@ -213,6 +214,19 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 6351b7620d84e2d43bc4f59c5f3f8b5c, type: 3}
m_Name:
m_EditorClassIdentifier:
+--- !u!114 &133964676
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 133964670}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: ac64716d16f44bd596798277ddc5eaaf, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ state: 0
--- !u!1 &447905425
GameObject:
m_ObjectHideFlags: 0
@@ -459,6 +473,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 0cfc0b50e9003a0468ebdc186439c53b, type: 3}
m_Name:
m_EditorClassIdentifier:
+ ui: {fileID: 0}
--- !u!4 &1204483826
Transform:
m_ObjectHideFlags: 0
diff --git a/ColourMeOKGame/Assets/Scripts/AccountUI.cs b/ColourMeOKGame/Assets/Scripts/AccountUI.cs
index 977f0ff..7e28a50 100644
--- a/ColourMeOKGame/Assets/Scripts/AccountUI.cs
+++ b/ColourMeOKGame/Assets/Scripts/AccountUI.cs
@@ -116,6 +116,10 @@ public void OnEnable()
_secondaryActionButton.clicked += OnSecondaryActionButtonClick;
TransitionStateTo(State.NotSignedIn);
+ }
+
+ private void Awake()
+ {
GameManager.Instance.Backend.RegisterOnSignInCallback(OnSignInCallback);
}
@@ -216,12 +220,12 @@ private void TransitionStateTo(State newState, bool keepAccompanyingText = false
state = newState;
}
- private void ValidateUsername()
+ private void ValidateUsername(TextField usernameField)
{
// just has to be min. 5 characters
- _usernameField.style.color = _defaultInputFieldValueTextColour;
- if (_usernameField.value.Length >= 5) return;
- _usernameField.style.color = _errorInputFieldValueTextColour;
+ usernameField.style.color = _defaultInputFieldValueTextColour;
+ if (usernameField.value.Length >= 5) return;
+ usernameField.style.color = _errorInputFieldValueTextColour;
throw new Exception("Username must be at least 5 characters long.");
}
@@ -279,18 +283,18 @@ private void ValidateFields(TextField emailField, TextField passwordField)
try
{
- ValidateEmailField(_emailField);
+ ValidateEmailField(emailField);
}
- catch (Exception _)
+ catch (Exception)
{
invalidEmail = true;
}
try
{
- ValidatePasswordField(_passwordField);
+ ValidatePasswordField(passwordField);
}
- catch (Exception _)
+ catch (Exception)
{
invalidPassword = true;
}
@@ -321,27 +325,27 @@ private void ValidateFields(TextField emailField, TextField passwordField, TextF
try
{
- ValidateEmailField(_emailField);
+ ValidateEmailField(emailField);
}
- catch (Exception _)
+ catch (Exception)
{
invalidEmail = true;
}
try
{
- ValidatePasswordField(_passwordField);
+ ValidatePasswordField(passwordField);
}
- catch (Exception _)
+ catch (Exception)
{
invalidPassword = true;
}
try
{
- ValidateUsername();
+ ValidateUsername(usernameField);
}
- catch (Exception _)
+ catch (Exception)
{
invalidUsername = true;
}
@@ -369,7 +373,7 @@ private void OnUsernameUpdateButtonClick()
{
try
{
- ValidateUsername();
+ ValidateUsername(_usernameField);
}
catch (Exception e)
{
diff --git a/ColourMeOKGame/Assets/Scripts/Colorimetry.cs b/ColourMeOKGame/Assets/Scripts/Colorimetry.cs
index 72c98b6..bf5ce52 100644
--- a/ColourMeOKGame/Assets/Scripts/Colorimetry.cs
+++ b/ColourMeOKGame/Assets/Scripts/Colorimetry.cs
@@ -62,6 +62,7 @@ public static RGB gamut_clip_preserve_chroma(RGB rgb)
/// a and b must be normalized so a^2 + b^2 == 1
///
// https://bottosson.github.io/posts/gamutclipping/ (MIT)
+ // ReSharper disable once MemberCanBePrivate.Global
public static float find_gamut_intersection(
float a,
float b,
@@ -164,6 +165,7 @@ public static RGB gamut_clip_preserve_chroma(RGB rgb)
/// a and b must be normalized so a^2 + b^2 == 1
///
// https://bottosson.github.io/posts/gamutclipping/ (MIT)
+ // ReSharper disable once MemberCanBePrivate.Global
public static LC find_cusp(float a, float b)
{
// First, find the maximum saturation (saturation S = C/L)
@@ -178,7 +180,7 @@ public static LC find_cusp(float a, float b)
}
// https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab (public domain)
-
+ // ReSharper disable once MemberCanBePrivate.Global
public static Lab linear_srgb_to_oklab(RGB c)
{
var l = 0.4122214708f * c.r + 0.5363325363f * c.g + 0.0514459929f * c.b;
@@ -220,6 +222,7 @@ public static RGB oklab_to_linear_srgb(Lab c)
/// a and b must be normalized so a^2 + b^2 == 1
///
// https://bottosson.github.io/posts/gamutclipping/ (MIT)
+ // ReSharper disable once MemberCanBePrivate.Global
public static float compute_max_saturation(float a, float b)
{
// Max saturation will be when one of r, g or b goes below zero.
diff --git a/ColourMeOKGame/Assets/Scripts/GameManager.cs b/ColourMeOKGame/Assets/Scripts/GameManager.cs
index 6e4c080..c58f431 100644
--- a/ColourMeOKGame/Assets/Scripts/GameManager.cs
+++ b/ColourMeOKGame/Assets/Scripts/GameManager.cs
@@ -1,47 +1,29 @@
using UnityEngine;
-using UnityEngine.Serialization;
-using UnityEngine.UIElements;
///
/// singleton for a single source of truth game state and flow management
///
public class GameManager : MonoBehaviour
{
- ///
- /// enum for available menus in the game, for use with ShowMenu()
- ///
- public enum DisplayState
- {
- Nothing,
- PlayView,
- LeaderboardView,
- AccountView,
- }
-
///
/// singleton pattern: define instance field for accessing the singleton elsewhere
///
public static GameManager Instance;
-
- ///
- /// the current display state of the game
- ///
- [SerializeField] private DisplayState state = DisplayState.Nothing;
///
- /// the visual element object for game ui (hud/prompts/tooltips)
+ /// the local player data object for storing player data
///
- private VisualElement _ui;
+ private LocalPlayerData _localPlayerData;
///
/// backend object for handling communication with the firebase backend
///
public Backend Backend;
-
+
///
- /// the local player data object for storing player data
+ /// ui manager object for handling ui state and flow
///
- private LocalPlayerData _localPlayerData;
+ public UIManager ui;
///
/// enforces singleton behaviour; sets doesn't destroy on load and checks for multiple instances
@@ -61,30 +43,27 @@ private void Awake()
Debug.Log("awake as non-singleton instance, destroying self");
Destroy(gameObject);
}
- }
- private void Start()
- {
- SetDisplayState(DisplayState.PlayView);
-
- // load the local player data and refresh the ui
- _localPlayerData = new LocalPlayerData();
- _localPlayerData.LoadFromTheWorld();
-
- // register a callback to refresh the ui when the player signs in
- Backend.RegisterOnSignInCallback(_ =>
- {
- _localPlayerData.LoadFromTheWorld();
- });
}
///
- /// called when the game object is enabled
+ /// called when the game object is enabled, initialises variables
///
private void OnEnable()
{
Backend = new Backend();
Backend.Initialise();
+ ui = UIManager.Instance;
+ }
+
+ private void Start()
+ {
+ // load the local player data and refresh the ui
+ _localPlayerData = new LocalPlayerData();
+ _localPlayerData.LoadFromTheWorld();
+
+ // register a callback to refresh the ui when the player signs in
+ Backend.RegisterOnSignInCallback(_ => { _localPlayerData.LoadFromTheWorld(); });
}
///
@@ -94,13 +73,4 @@ private void OnDestroy()
{
Backend.Cleanup();
}
-
- ///
- /// function to show a menu based on the enum passed,
- /// and any other necessary actions
- ///
- /// the game menu to show
- public void SetDisplayState(DisplayState newDisplayState)
- {
- }
}
\ No newline at end of file
diff --git a/ColourMeOKGame/Assets/Scripts/GameManager.cs.meta b/ColourMeOKGame/Assets/Scripts/GameManager.cs.meta
index 100b3aa..04fbdcd 100644
--- a/ColourMeOKGame/Assets/Scripts/GameManager.cs.meta
+++ b/ColourMeOKGame/Assets/Scripts/GameManager.cs.meta
@@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
- executionOrder: 0
+ executionOrder: -10
icon: {instanceID: 0}
userData:
assetBundleName:
diff --git a/ColourMeOKGame/Assets/Scripts/LocalPlayerData.cs b/ColourMeOKGame/Assets/Scripts/LocalPlayerData.cs
index dc6a8e7..7d44cca 100644
--- a/ColourMeOKGame/Assets/Scripts/LocalPlayerData.cs
+++ b/ColourMeOKGame/Assets/Scripts/LocalPlayerData.cs
@@ -5,32 +5,32 @@
public class LocalPlayerData
{
+ ///
+ /// queue of the best online scores,
+ /// used in user rating calculation and accuracy display stats
+ ///
+ public Queue BestOnlineScores = new(30);
+
///
/// last known email used
///
public string LastKnownEmail = "";
-
+
///
/// last known username used
///
public string LastKnownUsername = "Guest";
-
+
///
/// queue of the 10 most recent local scores
///
public Queue RecentLocalScores = new(10);
-
+
///
/// queue of the 10 most recent online scores,
/// used in user rating calculation and accuracy display stats
///
public Queue RecentOnlineScores = new(10);
-
- ///
- /// queue of the best online scores,
- /// used in user rating calculation and accuracy display stats
- ///
- public Queue BestOnlineScores = new(30);
///
/// loads player data from player prefs and database
@@ -46,6 +46,7 @@ public void LoadFromTheWorld()
currentKnownEmail = possibleUser.Email;
currentKnownUsername = GameManager.Instance.Backend.GetUsername();
}
+
var lastStoredEmail = PlayerPrefs.GetString("LastKnownEmail", "");
var lastStoredUsername = PlayerPrefs.GetString("LastKnownUsername", "Guest");
LastKnownEmail = string.IsNullOrEmpty(currentKnownEmail) ? lastStoredEmail : currentKnownEmail;
@@ -78,27 +79,19 @@ public void LoadFromTheWorld()
RegisterLocalScore(new Score(timestamp, noOfRounds, l, c, h));
}
-
+
// load online scores
RecentOnlineScores.Clear();
- GameManager.Instance.Backend.GetRecentScores((dtr, recentOnlineScores) =>
+ GameManager.Instance.Backend.GetRecentScores((_, recentOnlineScores) =>
{
foreach (var onlineScore in recentOnlineScores)
{
if (RecentOnlineScores.Count > 10) RecentOnlineScores.Dequeue();
RecentOnlineScores.Enqueue(onlineScore);
}
- });
- }
- ///
- /// registers a score to the player's local data
- ///
- /// the score to register
- public void RegisterLocalScore(Score score)
- {
- if (RecentLocalScores.Count > 10) RecentLocalScores.Dequeue();
- RecentLocalScores.Enqueue(score);
+ Debug.Log("loaded online scores from backend");
+ });
}
///
@@ -121,9 +114,21 @@ public void SaveToTheWorld()
idx++;
}
+ Debug.Log("saved lpdata to playerprefs");
// online scores are already saved in the backend
}
+ ///
+ /// registers a score to the player's local data
+ ///
+ /// the score to register
+ public void RegisterLocalScore(Score score)
+ {
+ if (RecentLocalScores.Count > 10) RecentLocalScores.Dequeue();
+ RecentLocalScores.Enqueue(score);
+ }
+
+
public struct Score
{
///
diff --git a/ColourMeOKGame/Assets/Scripts/SideViewUI.cs b/ColourMeOKGame/Assets/Scripts/SideViewUI.cs
index 5e27f07..f662a40 100644
--- a/ColourMeOKGame/Assets/Scripts/SideViewUI.cs
+++ b/ColourMeOKGame/Assets/Scripts/SideViewUI.cs
@@ -74,7 +74,7 @@ private void OnEnable()
private void RenderFromPlayerData(LocalPlayerData localPlayerData)
{
// calculate averages from both recent local scores and online scores
- var totalLightessAcc = 0f;
+ var totalLightnessAcc = 0f;
var totalChromaAcc = 0f;
var totalHueAcc = 0f;
var totalRounds = 0;
@@ -83,7 +83,7 @@ private void RenderFromPlayerData(LocalPlayerData localPlayerData)
foreach (var localScore in localPlayerData.RecentLocalScores)
{
- totalLightessAcc += localScore.AvgLightnessAccuracy;
+ totalLightnessAcc += localScore.AvgLightnessAccuracy;
totalChromaAcc += localScore.AvgChromaAccuracy;
totalHueAcc += localScore.AvgHueAccuracy;
totalRounds += localScore.NoOfRounds;
@@ -91,26 +91,26 @@ private void RenderFromPlayerData(LocalPlayerData localPlayerData)
foreach (var onlineScore in localPlayerData.RecentOnlineScores)
{
- totalLightessAcc += onlineScore.AvgLightnessAccuracy;
+ totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
totalChromaAcc += onlineScore.AvgChromaAccuracy;
totalHueAcc += onlineScore.AvgHueAccuracy;
totalRounds += onlineScore.NoOfRounds;
}
-
+
foreach (var onlineScore in localPlayerData.BestOnlineScores)
{
- totalLightessAcc += onlineScore.AvgLightnessAccuracy;
+ totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
totalChromaAcc += onlineScore.AvgChromaAccuracy;
totalHueAcc += onlineScore.AvgHueAccuracy;
totalRounds += onlineScore.NoOfRounds;
}
-
+
// finally, set the labels
_playerNameText.text = GameManager.Instance.Backend.GetUsername();
- _lightnessAccuracyText.text = $"{(totalLightessAcc / totalRounds):F}";
- _hueAccuracyText.text = $"{(totalHueAcc / totalRounds):F}";
- _chromaAccuracyText.text = $"{(totalChromaAcc / totalRounds):F}";
-
+ _lightnessAccuracyText.text = $"{totalLightnessAcc / totalRounds:F}";
+ _hueAccuracyText.text = $"{totalHueAcc / totalRounds:F}";
+ _chromaAccuracyText.text = $"{totalChromaAcc / totalRounds: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))
GameManager.Instance.Backend.CalculateUserRating((dtr, rating) =>
@@ -125,7 +125,7 @@ private void RenderFromPlayerData(LocalPlayerData localPlayerData)
///
private static void OnPlayButtonClicked()
{
- GameManager.Instance.SetDisplayState(GameManager.DisplayState.PlayView);
+ GameManager.Instance.ui.SetDisplayState(UIManager.DisplayState.PlayView);
}
///
@@ -133,7 +133,7 @@ private static void OnPlayButtonClicked()
///
private static void OnLeaderboardButtonClicked()
{
- GameManager.Instance.SetDisplayState(GameManager.DisplayState.LeaderboardView);
+ GameManager.Instance.ui.SetDisplayState(UIManager.DisplayState.LeaderboardView);
}
///
@@ -141,6 +141,6 @@ private static void OnLeaderboardButtonClicked()
///
private static void OnAccountButtonClicked()
{
- GameManager.Instance.SetDisplayState(GameManager.DisplayState.AccountView);
+ GameManager.Instance.ui.SetDisplayState(UIManager.DisplayState.AccountView);
}
}
\ No newline at end of file
diff --git a/ColourMeOKGame/Assets/Scripts/UIManager.cs b/ColourMeOKGame/Assets/Scripts/UIManager.cs
new file mode 100644
index 0000000..a2e4d2b
--- /dev/null
+++ b/ColourMeOKGame/Assets/Scripts/UIManager.cs
@@ -0,0 +1,113 @@
+using System;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+public class UIManager : MonoBehaviour
+{
+ ///
+ /// singleton pattern: define instance field for accessing the singleton elsewhere
+ ///
+ public static UIManager Instance;
+
+ ///
+ /// enum for available menus in the game, for use with ShowMenu()
+ ///
+ public enum DisplayState
+ {
+ UnassociatedState,
+ Nothing,
+ PlayView,
+ LeaderboardView,
+ AccountView
+ }
+
+ ///
+ /// the current display state of the game
+ ///
+ [SerializeField] private DisplayState state = DisplayState.UnassociatedState;
+
+ ///
+ /// the visual element object for game ui
+ ///
+ public VisualElement UI;
+
+ ///
+ /// enforces singleton behaviour; sets doesn't destroy on load and checks for multiple instances
+ ///
+ 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);
+ }
+ }
+
+ private void OnEnable()
+ {
+ UI = GetComponent().rootVisualElement;
+ SetDisplayState(DisplayState.Nothing);
+ }
+
+ ///
+ /// function to show a menu based on the enum passed,
+ /// and any other necessary actions
+ ///
+ /// the game menu to show
+ public void SetDisplayState(DisplayState newDisplayState)
+ {
+ var currentDisplayState = state;
+
+ // if the new state is the same as the current state, do nothing
+ if (currentDisplayState == newDisplayState)
+ {
+ Debug.Log($"staying at {currentDisplayState} (illogical transition)");
+ return;
+ }
+
+ Debug.Log($"switching from {currentDisplayState} to {newDisplayState}");
+
+ var gameView = UI.Q("GameView");
+ var leaderboardView = UI.Q("LeaderboardView");
+ var accountView = UI.Q("AccountView");
+
+ switch (newDisplayState)
+ {
+ case DisplayState.Nothing:
+ gameView.style.display = DisplayStyle.None;
+ leaderboardView.style.display = DisplayStyle.None;
+ accountView.style.display = DisplayStyle.None;
+ break;
+
+ case DisplayState.PlayView:
+ gameView.style.display = DisplayStyle.Flex;
+ leaderboardView.style.display = DisplayStyle.None;
+ accountView.style.display = DisplayStyle.None;
+ break;
+
+ case DisplayState.LeaderboardView:
+ gameView.style.display = DisplayStyle.None;
+ leaderboardView.style.display = DisplayStyle.Flex;
+ accountView.style.display = DisplayStyle.None;
+ break;
+
+ case DisplayState.AccountView:
+ gameView.style.display = DisplayStyle.None;
+ leaderboardView.style.display = DisplayStyle.None;
+ accountView.style.display = DisplayStyle.Flex;
+ break;
+
+ case DisplayState.UnassociatedState:
+ default:
+ throw new ArgumentOutOfRangeException(nameof(newDisplayState), newDisplayState, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ColourMeOKGame/Assets/Scripts/UIManager.cs.meta b/ColourMeOKGame/Assets/Scripts/UIManager.cs.meta
new file mode 100644
index 0000000..b9d6172
--- /dev/null
+++ b/ColourMeOKGame/Assets/Scripts/UIManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ac64716d16f44bd596798277ddc5eaaf
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: -15
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/ColourMeOKGame/Assets/UI/GameUI.uxml b/ColourMeOKGame/Assets/UI/GameUI.uxml
index d080856..7245dbc 100644
--- a/ColourMeOKGame/Assets/UI/GameUI.uxml
+++ b/ColourMeOKGame/Assets/UI/GameUI.uxml
@@ -1,162 +1,92 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
-
-
+
+