From 87705849376758bc2604ba42a62679d012b3ad8c Mon Sep 17 00:00:00 2001 From: max-lovell Date: Tue, 19 Nov 2024 16:58:44 +0000 Subject: [PATCH] Big refactor to separate out level1 concerns and switch to event system --- .idea/.idea.Doggo-Nogo/.idea/workspace.xml | 39 +++++- .../UI/Components.meta => Resources.meta} | 2 +- Assets/Resources/Prefabs.meta | 8 ++ Assets/Resources/Prefabs/GameManager.prefab | 61 ++++++++ .../Resources/Prefabs/GameManager.prefab.meta | 7 + Assets/Scenes/Simple RT.unity | 130 +----------------- .../Controllers/EndGame/EndGameController.cs | 5 +- Assets/Scripts/Controllers/GameController.cs | 111 ++++----------- .../Controllers/Level1/Level1Controller.cs | 116 +++++++++++++--- .../Level1/Level1TrialController.cs | 79 +++++++++-- .../Controllers/Level1/Level1UIController.cs | 43 ++++++ .../Level1/Level1UIController.cs.meta | 3 + Assets/Scripts/Controllers/UIController.cs | 84 ----------- .../Scripts/Controllers/UIController.cs.meta | 11 -- Assets/Scripts/Core/Events/GameEvents.cs | 31 +++-- Assets/Scripts/Core/Events/Level1Events.cs | 48 +++++++ .../Scripts/Core/Events/Level1Events.cs.meta | 3 + .../Core/Processing/ScoreCalculator.cs | 1 - Assets/Scripts/Models/Data/DataPipeBody.cs | 1 + Assets/Scripts/Models/Data/ExperimentData.cs | 6 + .../Models/Data/ExperimentData.cs.meta | 3 + .../Scripts/Models/Data/Level1/Level1Data.cs | 1 + .../Models/Data/Level1/Level1StageData.cs | 56 ++++++++ .../Data/Level1/Level1StageData.cs.meta | 3 + .../Scripts/Models/Data/{ => Level1}/Trial.cs | 0 .../Models/Data/{ => Level1}/Trial.cs.meta | 0 .../Models/Data/{ => Level1}/TrialResult.cs | 0 .../Data/{ => Level1}/TrialResult.cs.meta | 0 Assets/Scripts/Services/DataService.cs | 8 +- .../Scripts/Views/Game/Components/DogView.cs | 8 +- .../Views/Game/Components/FeedbackView.cs | 12 +- Assets/Scripts/Views/Game/GameplayCanvas.cs | 0 .../Scripts/Views/Game/GameplayCanvas.cs.meta | 11 -- .../Views/UI/Components/ScoreDisplay.cs | 22 --- .../Views/UI/Components/ScoreDisplay.cs.meta | 11 -- .../UI/Screens/IntroStory/IntroStoryView.cs | 2 +- .../Views/UI/Screens/Level1Screen.meta | 3 + .../Level1IntroductionView.cs} | 6 +- .../Level1IntroductionView.cs.meta} | 0 .../Views/UI/Screens/Level1Screen/Level1UI.cs | 28 ++++ .../Level1UI.cs.meta} | 0 Assets/Scripts/Views/UI/Screens/MainGameUI.cs | 19 --- 42 files changed, 539 insertions(+), 443 deletions(-) rename Assets/{Scripts/Views/UI/Components.meta => Resources.meta} (77%) create mode 100644 Assets/Resources/Prefabs.meta create mode 100644 Assets/Resources/Prefabs/GameManager.prefab create mode 100644 Assets/Resources/Prefabs/GameManager.prefab.meta create mode 100644 Assets/Scripts/Controllers/Level1/Level1UIController.cs create mode 100644 Assets/Scripts/Controllers/Level1/Level1UIController.cs.meta delete mode 100644 Assets/Scripts/Controllers/UIController.cs delete mode 100644 Assets/Scripts/Controllers/UIController.cs.meta create mode 100644 Assets/Scripts/Core/Events/Level1Events.cs create mode 100644 Assets/Scripts/Core/Events/Level1Events.cs.meta create mode 100644 Assets/Scripts/Models/Data/ExperimentData.cs create mode 100644 Assets/Scripts/Models/Data/ExperimentData.cs.meta create mode 100644 Assets/Scripts/Models/Data/Level1/Level1StageData.cs create mode 100644 Assets/Scripts/Models/Data/Level1/Level1StageData.cs.meta rename Assets/Scripts/Models/Data/{ => Level1}/Trial.cs (100%) rename Assets/Scripts/Models/Data/{ => Level1}/Trial.cs.meta (100%) rename Assets/Scripts/Models/Data/{ => Level1}/TrialResult.cs (100%) rename Assets/Scripts/Models/Data/{ => Level1}/TrialResult.cs.meta (100%) delete mode 100644 Assets/Scripts/Views/Game/GameplayCanvas.cs delete mode 100644 Assets/Scripts/Views/Game/GameplayCanvas.cs.meta delete mode 100644 Assets/Scripts/Views/UI/Components/ScoreDisplay.cs delete mode 100644 Assets/Scripts/Views/UI/Components/ScoreDisplay.cs.meta create mode 100644 Assets/Scripts/Views/UI/Screens/Level1Screen.meta rename Assets/Scripts/Views/UI/Screens/{IntroScreen.cs => Level1Screen/Level1IntroductionView.cs} (94%) rename Assets/Scripts/Views/UI/Screens/{IntroScreen.cs.meta => Level1Screen/Level1IntroductionView.cs.meta} (100%) create mode 100644 Assets/Scripts/Views/UI/Screens/Level1Screen/Level1UI.cs rename Assets/Scripts/Views/UI/Screens/{MainGameUI.cs.meta => Level1Screen/Level1UI.cs.meta} (100%) delete mode 100644 Assets/Scripts/Views/UI/Screens/MainGameUI.cs diff --git a/.idea/.idea.Doggo-Nogo/.idea/workspace.xml b/.idea/.idea.Doggo-Nogo/.idea/workspace.xml index 4a2b1fc..ef5a0a4 100644 --- a/.idea/.idea.Doggo-Nogo/.idea/workspace.xml +++ b/.idea/.idea.Doggo-Nogo/.idea/workspace.xml @@ -5,7 +5,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -148,6 +184,7 @@ + diff --git a/Assets/Scripts/Views/UI/Components.meta b/Assets/Resources.meta similarity index 77% rename from Assets/Scripts/Views/UI/Components.meta rename to Assets/Resources.meta index e179d09..48adeb2 100644 --- a/Assets/Scripts/Views/UI/Components.meta +++ b/Assets/Resources.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d67afc2489ddb4afab8589a5b5af7bfc +guid: 6f53b810d470642cfb7566c0175acdb3 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Resources/Prefabs.meta b/Assets/Resources/Prefabs.meta new file mode 100644 index 0000000..0629f8b --- /dev/null +++ b/Assets/Resources/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 158e086c334b54e40a78a2d7411df501 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/GameManager.prefab b/Assets/Resources/Prefabs/GameManager.prefab new file mode 100644 index 0000000..db27a8d --- /dev/null +++ b/Assets/Resources/Prefabs/GameManager.prefab @@ -0,0 +1,61 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7945155197457443849 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7331681004479383633} + - component: {fileID: 3325636454564189589} + - component: {fileID: 6425351595915927503} + m_Layer: 0 + m_Name: GameManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7331681004479383633 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7945155197457443849} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3325636454564189589 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7945155197457443849} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 500e3127d31364597971dab85a38df4c, type: 3} + m_Name: + m_EditorClassIdentifier: + gameConfig: {fileID: 11400000, guid: db0760b0c4e5b468f8881330a088a884, type: 2} +--- !u!114 &6425351595915927503 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7945155197457443849} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34353bc8d77e24ebdb2833bb2187eb7e, type: 3} + m_Name: + m_EditorClassIdentifier: + gameConfig: {fileID: 11400000, guid: db0760b0c4e5b468f8881330a088a884, type: 2} diff --git a/Assets/Resources/Prefabs/GameManager.prefab.meta b/Assets/Resources/Prefabs/GameManager.prefab.meta new file mode 100644 index 0000000..782942d --- /dev/null +++ b/Assets/Resources/Prefabs/GameManager.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c13e346eed48142f4b01bdb9f1774afa +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Simple RT.unity b/Assets/Scenes/Simple RT.unity index 3d2ed97..f2cdd20 100644 --- a/Assets/Scenes/Simple RT.unity +++ b/Assets/Scenes/Simple RT.unity @@ -198,101 +198,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 27311026} m_CullTransparentMesh: 1 ---- !u!1 &60437125 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 60437130} - - component: {fileID: 60437129} - - component: {fileID: 60437128} - - component: {fileID: 60437127} - - component: {fileID: 60437126} - m_Layer: 0 - m_Name: GameManager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &60437126 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 60437125} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7a478841ba5ae4b13a37f1061e5e65df, type: 3} - m_Name: - m_EditorClassIdentifier: - mainGameUI: {fileID: 0} - gameOverUI: {fileID: 0} - animationController: {fileID: 0} - scoreDisplay: {fileID: 0} - gameConfig: {fileID: 11400000, guid: db0760b0c4e5b468f8881330a088a884, type: 2} - introScreen: {fileID: 0} ---- !u!114 &60437127 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 60437125} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 34353bc8d77e24ebdb2833bb2187eb7e, type: 3} - m_Name: - m_EditorClassIdentifier: - gameConfig: {fileID: 11400000, guid: db0760b0c4e5b468f8881330a088a884, type: 2} ---- !u!114 &60437128 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 60437125} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 64c1dadaddd042178e017e8fb41d34c6, type: 3} - m_Name: - m_EditorClassIdentifier: - gameConfig: {fileID: 11400000, guid: db0760b0c4e5b468f8881330a088a884, type: 2} - feedbackView: {fileID: 0} - boneView: {fileID: 0} ---- !u!114 &60437129 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 60437125} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 500e3127d31364597971dab85a38df4c, type: 3} - m_Name: - m_EditorClassIdentifier: - gameConfig: {fileID: 11400000, guid: db0760b0c4e5b468f8881330a088a884, type: 2} - uiController: {fileID: 0} ---- !u!4 &60437130 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 60437125} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &85999983 GameObject: m_ObjectHideFlags: 0 @@ -1462,7 +1367,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} + m_AnchoredPosition: {x: 447.81503, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1026645577 @@ -2214,37 +2119,6 @@ MonoBehaviour: m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 1 ---- !u!1 &1478532415 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1478532416} - m_Layer: 0 - m_Name: UI - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1478532416 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1478532415} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1479691775 GameObject: m_ObjectHideFlags: 0 @@ -8503,5 +8377,3 @@ SceneRoots: m_ObjectHideFlags: 0 m_Roots: - {fileID: 519420032} - - {fileID: 60437130} - - {fileID: 1478532416} diff --git a/Assets/Scripts/Controllers/EndGame/EndGameController.cs b/Assets/Scripts/Controllers/EndGame/EndGameController.cs index 68f5a6c..c4eb7ca 100644 --- a/Assets/Scripts/Controllers/EndGame/EndGameController.cs +++ b/Assets/Scripts/Controllers/EndGame/EndGameController.cs @@ -9,7 +9,7 @@ public class EndGameController : MonoBehaviour private void Awake() { - if (Instance != null) + if (Instance) { Destroy(gameObject); return; @@ -22,12 +22,11 @@ private void Awake() private void InitializeEndGame() { _scoreData = new EndGameScoreData(); - GameController.Instance.OnLevelComplete(); } public float CalculatePercentileScore() { - double threshold = GameController.Instance.GetCurrentThreshold(); + double threshold = DataController.Instance.GetCurrentThreshold(); return (float)MathUtils.CalculatePercentileNormCDF(threshold); } } \ No newline at end of file diff --git a/Assets/Scripts/Controllers/GameController.cs b/Assets/Scripts/Controllers/GameController.cs index ccd75bd..f6e6d6b 100644 --- a/Assets/Scripts/Controllers/GameController.cs +++ b/Assets/Scripts/Controllers/GameController.cs @@ -1,43 +1,20 @@ using UnityEngine; +using UnityEngine.SceneManagement; // Overall game state and flow: Coordinates between other controllers, and manages game phases (start, end) // Generally, controllers manage game logic and connect Models with Views -public class GameController : MonoBehaviour, IGameState { //Singleton instance for global access + +public class GameController : MonoBehaviour +{ public static GameController Instance { get; private set; } [SerializeField] private GameConfig gameConfig; - [SerializeField] private UIController uiController; private GameData _gameData; private IDataService _dataService; private bool _isGameActive; - // IGameState properties - public int CurrentTrialNumber => _gameData?.level1.Count ?? 0; - public int TotalTrials => gameConfig.DefaultTrialCount; - public int CurrentScore => _gameData?.gameStats.CurrentScore ?? 0; - public GamePhase CurrentPhase { get; private set; } - - // IGameState methods - public void StartNewTrial() - { - if (CurrentTrialNumber >= TotalTrials) - { - EndGame(); - return; - } - - double isi = CalculateIsi(); - _gameData.AddNewTrial(isi); - GameEvents.GamePhaseChanged(GamePhase.TrialInProgress); - } - - public void EndTrial(TrialResult result) - { - HandleTrialCompleted(result); - } - - private void Awake() + private void Awake() { if (Instance != null) { @@ -51,90 +28,52 @@ private void Awake() SubscribeToEvents(); } - // ReSharper disable Unity.PerformanceAnalysis - public void StartGame() + private void InitializeServices() { - _isGameActive = true; - _gameData = new GameData(); - _gameData.metadata.InitializeWebVariables(); - - Level1Controller.Instance.StartLevel(); - UIController.Instance.ShowGameScreen(); - - GameEvents.GamePhaseChanged(GamePhase.Level1); - } - private void InitializeServices() { var webService = new WebService(); _dataService = new DataService(webService); _gameData = new GameData(); } - private void SubscribeToEvents() { - GameEvents.OnTrialCompleted += HandleTrialCompleted; - GameEvents.OnGamePhaseChanged += HandleGamePhaseChanged; - } - - public double GetCurrentThreshold() + private void SubscribeToEvents() { - return _gameData?.level1.Count > 0 - ? _gameData.level1[^1].threshold - : gameConfig.InitialMedianRT; + GameEvents.OnExperimentComplete += HandleExperimentComplete; + GameEvents.OnGamePhaseChanged += HandleGamePhaseChanged; } - public void OnLevelComplete() + public void StartExperiment() { - EndGame(); - } - - private double CalculateIsi() - { - return UnityEngine.Random.Range(gameConfig.ISIRange.x, gameConfig.ISIRange.y); + _isGameActive = true; + _gameData = new GameData(); + _gameData.metadata.InitializeWebVariables(); } - private async void EndGame() { - CurrentPhase = GamePhase.GameOver; - GameEvents.GamePhaseChanged(GamePhase.GameOver); - await _dataService.SaveData(_gameData); - } - - // ReSharper disable Unity.PerformanceAnalysis - private void HandleTrialCompleted(TrialResult result) + private async void HandleExperimentComplete(ExperimentData experimentData) { if (!_isGameActive) return; - - DataController.Instance.SaveTrial(result); - UIController.Instance.UpdateScore(result.TotalScore); - if (result.ValidTrialCount >= gameConfig.DefaultTrialCount) - { - EndGame(); - return; - } - - if (!result.ValidTrial) - { - Level1Controller.Instance.StartNewTrial(); - } + _isGameActive = false; + await _dataService.SaveData(_gameData); + SceneManager.LoadScene("End"); + GameEvents.GamePhaseChanged(GamePhase.GameOver); } - + private void HandleGamePhaseChanged(GamePhase phase) { - CurrentPhase = phase; - _isGameActive = phase == GamePhase.Level1 || phase == GamePhase.TrialInProgress; - switch (phase) { case GamePhase.Level1: - DataController.Instance.Level1Started(); + _gameData.metadata.startL1 = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); break; case GamePhase.GameOver: - DataController.Instance.Level1Ended(); + _gameData.metadata.endL1 = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); break; } } - - private void OnDestroy() { - GameEvents.OnTrialCompleted -= HandleTrialCompleted; + + private void OnDestroy() + { + GameEvents.OnExperimentComplete -= HandleExperimentComplete; GameEvents.OnGamePhaseChanged -= HandleGamePhaseChanged; } } \ No newline at end of file diff --git a/Assets/Scripts/Controllers/Level1/Level1Controller.cs b/Assets/Scripts/Controllers/Level1/Level1Controller.cs index 6a17d63..de807d0 100644 --- a/Assets/Scripts/Controllers/Level1/Level1Controller.cs +++ b/Assets/Scripts/Controllers/Level1/Level1Controller.cs @@ -5,17 +5,22 @@ public class Level1Controller : MonoBehaviour { public static Level1Controller Instance { get; private set; } + [Header("Configuration")] [SerializeField] private GameConfig gameConfig; - [SerializeField] private FeedbackView feedbackView; + + [Header("View References")] + [SerializeField] private Level1UIController uiController; [SerializeField] private BoneView boneView; + private GameData _gameData; private Level1Data _levelData; + private Level1StageData _stageData; private Level1TrialController _trialController; private ReactionTimeProcessor _rtProcessor; private ScoreCalculator _scoreCalculator; - private DataController _dataController; + private bool _isLevelActive; - private void Awake() + private void Awake() // initialised this controller and related processes { if (Instance != null) { @@ -23,44 +28,99 @@ private void Awake() return; } Instance = this; - + InitializeComponents(); } + private void Start() + { + if (!GameController.Instance) // Check GameController has been initialised + { + Debug.LogError("GameController not found - ensure GameManager is initialized"); + } + } + private void InitializeComponents() { _rtProcessor = new ReactionTimeProcessor(gameConfig); _scoreCalculator = new ScoreCalculator(gameConfig); _trialController = GetComponent(); - _dataController = DataController.Instance; _levelData = new Level1Data(gameConfig); + _stageData = new Level1StageData(_gameData.metadata, gameConfig); // Pass metadata to grab l1n + _isLevelActive = true; + GameEvents.GamePhaseChanged(GamePhase.Level1); } - // Add this method public void StartLevel() { _levelData = new Level1Data(gameConfig); - _trialController.StartNewTrial(); - } - - public void StartNewTrial() - { + Level1Events.LevelStarted(); // Guess nothing happens if nothing attached? _trialController.StartNewTrial(); } public void ProcessTrialResult(double reactionTime) { + if (!_isLevelActive) return; + string responseType = _rtProcessor.DetermineResponseType(reactionTime); int score = _scoreCalculator.CalculateScore(responseType, reactionTime); bool isValidTrial = responseType is "slow" or "fast"; + + if (!isValidTrial) + { + Level1Events.InvalidResponse(responseType); + } + + UpdateLevelData(isValidTrial, reactionTime); + _levelData.currentScore += score; + Level1Events.ScoreUpdated(_levelData.currentScore); + + var result = CreateTrialResult(reactionTime, responseType, score, isValidTrial); + Level1Events.TrialCompleted(result); + + if (ShouldEndLevel()) + { + EndLevel(); + return; + } - if (isValidTrial) _levelData.validTrialCount++; - if (isValidTrial || responseType == "missed") + CheckStageProgress(result); + + if (!result.ValidTrial) { - _rtProcessor.UpdateMedianRT(reactionTime); + _trialController.StartNewTrial(); } + } + + // ReSharper disable Unity.PerformanceAnalysis + private void CheckStageProgress(TrialResult result) + { + if (result.TotalScore < _stageData.CurrentTargetScore || !_stageData.AdvanceStage()) return; + int newTargetScore = _stageData.CalculateTargetScore( + _levelData.validTrialCount, + gameConfig.MinScore + ); + + Level1Events.StageChanged(_stageData.CurrentStage, newTargetScore); + _stageData.CurrentTargetScore = newTargetScore; + } + + private void UpdateLevelData(bool isValidTrial, double reactionTime) + { + if (isValidTrial) + { + _levelData.validTrialCount++; + } + + if (isValidTrial || reactionTime > gameConfig.MaxReactionTime) + { + _levelData.UpdateMedianRT(reactionTime); + } + } - var result = new TrialResult + private TrialResult CreateTrialResult(double reactionTime, string responseType, int score, bool isValidTrial) + { + return new TrialResult { ReactionTime = reactionTime, ResponseType = responseType, @@ -70,16 +130,32 @@ public void ProcessTrialResult(double reactionTime) ValidTrial = isValidTrial, ValidTrialCount = _levelData.validTrialCount }; + } - _dataController.SaveTrial(result); - feedbackView.GiveFeedback(result); + private bool ShouldEndLevel() + { + return _stageData.CurrentStage == _stageData.TotalStages && _levelData.currentScore >= _stageData.CurrentTargetScore; + } - if (!result.ValidTrial) + private void EndLevel() + { + _isLevelActive = false; + var experimentData = new ExperimentData { - _trialController.StartNewTrial(); - } + FinalScore = _levelData.currentScore, + ValidTrials = _levelData.validTrialCount, + FinalThreshold = _levelData.currentMedianRT + }; + + Level1Events.LevelComplete(); + GameEvents.ExperimentComplete(experimentData); } public int CurrentTrialNumber => _levelData.validTrialCount; public int TotalTrials => gameConfig.DefaultTrialCount; + + private void OnDestroy() + { + _isLevelActive = false; + } } \ No newline at end of file diff --git a/Assets/Scripts/Controllers/Level1/Level1TrialController.cs b/Assets/Scripts/Controllers/Level1/Level1TrialController.cs index 4a40d4a..274e33f 100644 --- a/Assets/Scripts/Controllers/Level1/Level1TrialController.cs +++ b/Assets/Scripts/Controllers/Level1/Level1TrialController.cs @@ -2,32 +2,72 @@ using UnityEngine; // Defines trials in controller: Manages trial flow, Controls stimulus timing, Handles input detection, Manages ISI +// Essentially TrialManager from before... public class Level1TrialController : MonoBehaviour { + [Header("Configuration")] [SerializeField] private GameConfig gameConfig; + + [Header("View References")] [SerializeField] private BoneView boneView; + private readonly Stopwatch _timer = new(); private double _currentTrialIsi; + private bool _isTrialActive; + private bool _isStimulusShown; public void StartNewTrial() { + ResetTrial(); + _currentTrialIsi = GenerateIsi(); + Level1Events.NewTrialStarted(_currentTrialIsi); + Level1Events.TrialStateChanged(TrialState.WaitingForStimulus); + StartTimer(); + } + + private void Update() + { + if (!_isTrialActive) return; + + HandleStimulusPresentation(); + HandleInput(); + } + + private void ResetTrial() + { + _isTrialActive = true; + _isStimulusShown = false; boneView.Hide(); - _currentTrialIsi = UnityEngine.Random.Range(gameConfig.ISIRange.x, gameConfig.ISIRange.y); - DataController.Instance.NewTrial(_currentTrialIsi); - RestartTimer(); } - public void Update() + private double GenerateIsi() { - if (!_timer.IsRunning) return; + return Random.Range(gameConfig.ISIRange.x, gameConfig.ISIRange.y); + } - if (_timer.Elapsed.TotalSeconds > _currentTrialIsi && boneView.Hidden()) + private void HandleStimulusPresentation() + { + if (_timer.IsRunning && !_isStimulusShown && + _timer.Elapsed.TotalSeconds > _currentTrialIsi) { - var stimSpec = boneView.Show(); - DataController.Instance.StimuliShown(stimSpec); + ShowStimulus(); } + } - if (Input.GetKeyDown(KeyCode.DownArrow) || _timer.Elapsed.TotalSeconds > (_currentTrialIsi + gameConfig.MaxReactionTime)) + private void ShowStimulus() + { + var stimSpec = boneView.Show(); + _isStimulusShown = true; + Level1Events.StimulusShown(stimSpec); + Level1Events.TrialStateChanged(TrialState.WaitingForResponse); + } + + private void HandleInput() + { + bool shouldEndTrial = Input.GetKeyDown(KeyCode.DownArrow) || + _timer.Elapsed.TotalSeconds > (_currentTrialIsi + gameConfig.MaxReactionTime); + + if (shouldEndTrial) { EndTrial(); } @@ -35,14 +75,29 @@ public void Update() private void EndTrial() { + if (!_isTrialActive) return; + + _isTrialActive = false; _timer.Stop(); - double rt = _timer.Elapsed.TotalSeconds - _currentTrialIsi; - Level1Controller.Instance.ProcessTrialResult(rt); + double reactionTime = CalculateReactionTime(); + Level1Events.ReactionTimeRecorded(reactionTime); + Level1Events.TrialStateChanged(TrialState.Complete); + Level1Controller.Instance.ProcessTrialResult(reactionTime); + } + private double CalculateReactionTime() + { + return _timer.Elapsed.TotalSeconds - _currentTrialIsi; } - private void RestartTimer() + private void StartTimer() { _timer.Reset(); _timer.Start(); } + + private void OnDisable() + { + _timer.Stop(); + _isTrialActive = false; + } } \ No newline at end of file diff --git a/Assets/Scripts/Controllers/Level1/Level1UIController.cs b/Assets/Scripts/Controllers/Level1/Level1UIController.cs new file mode 100644 index 0000000..898f08f --- /dev/null +++ b/Assets/Scripts/Controllers/Level1/Level1UIController.cs @@ -0,0 +1,43 @@ +using UnityEngine; + +public class Level1UIController : MonoBehaviour +{ + [SerializeField] private FeedbackView feedbackView; + + private void OnEnable() + { + Level1Events.OnTrialCompleted += HandleTrialCompleted; + Level1Events.OnLevelStarted += HandleLevelStarted; + Level1Events.OnTrialStateChanged += HandleTrialStateChanged; + Level1Events.OnInvalidResponse += HandleInvalidResponse; + } + + private void OnDisable() + { + Level1Events.OnTrialCompleted -= HandleTrialCompleted; + Level1Events.OnLevelStarted -= HandleLevelStarted; + Level1Events.OnTrialStateChanged -= HandleTrialStateChanged; + Level1Events.OnInvalidResponse -= HandleInvalidResponse; + } + + private void HandleLevelStarted() + { + // Maybe show elements here? like feedback view + } + private void HandleTrialStateChanged(TrialState state) + { + // Maybe handle pausing and stuff here? + } + private void HandleTrialCompleted(TrialResult result) + { + // Not sure this feels right - handle response recorded here maybe. + feedbackView.GiveFeedback(result); + } + + private void HandleInvalidResponse(string reason) + { + // Probably no need for this event - that's extracted elsewhere. + //feedbackView.ShowInvalidResponse(reason); + } + +} \ No newline at end of file diff --git a/Assets/Scripts/Controllers/Level1/Level1UIController.cs.meta b/Assets/Scripts/Controllers/Level1/Level1UIController.cs.meta new file mode 100644 index 0000000..3dda933 --- /dev/null +++ b/Assets/Scripts/Controllers/Level1/Level1UIController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bb7389c5bff54cb2afa59dc310cd7fa2 +timeCreated: 1732014046 \ No newline at end of file diff --git a/Assets/Scripts/Controllers/UIController.cs b/Assets/Scripts/Controllers/UIController.cs deleted file mode 100644 index abfb49e..0000000 --- a/Assets/Scripts/Controllers/UIController.cs +++ /dev/null @@ -1,84 +0,0 @@ -using UnityEngine; - -// Manages UI state: Controls screen transitions, Updates UI elements, Handles UI events -public class UIController : MonoBehaviour -{ - public static UIController Instance { get; private set; } - - [SerializeField] private MainGameUI mainGameUI; - [SerializeField] private GameOverUI gameOverUI; - [SerializeField] private UIAnimationController animationController; - [SerializeField] private ScoreDisplay scoreDisplay; - [SerializeField] private GameConfig gameConfig; - [SerializeField] private GameObject introScreen; - private void Awake() - { - if (Instance != null) - { - Destroy(gameObject); - return; - } - Instance = this; - DontDestroyOnLoad(gameObject); - } - - private void OnEnable() - { - GameEvents.OnGamePhaseChanged += HandleGamePhaseChanged; - GameEvents.OnScoreUpdated += HandleScoreUpdated; - } - - private void OnDisable() - { - GameEvents.OnGamePhaseChanged -= HandleGamePhaseChanged; - GameEvents.OnScoreUpdated -= HandleScoreUpdated; - } - - public void UpdateScore(int newScore) - { - scoreDisplay.UpdateScore(newScore); - GameEvents.ScoreUpdated(newScore); - } - - private void HandleGamePhaseChanged(GamePhase phase) - { - switch (phase) - { - case GamePhase.GameOver: - ShowGameOver(); - break; - case GamePhase.TrialInProgress: - UpdateTrialUI(); - break; - } - } - - private void UpdateTrialUI() - { - if (mainGameUI != null) - { - mainGameUI.UpdateTrial( - Level1Controller.Instance.CurrentTrialNumber, - Level1Controller.Instance.TotalTrials - ); - } - } - - public void ShowGameScreen() - { - introScreen?.SetActive(false); - mainGameUI.gameObject.SetActive(true); - } - - private async void ShowGameOver() - { - await animationController.FadeOut(mainGameUI.gameObject); - gameOverUI.gameObject.SetActive(true); - await animationController.FadeIn(gameOverUI.gameObject); - } - - private void HandleScoreUpdated(int score) - { - scoreDisplay.UpdateScore(score); - } -} \ No newline at end of file diff --git a/Assets/Scripts/Controllers/UIController.cs.meta b/Assets/Scripts/Controllers/UIController.cs.meta deleted file mode 100644 index e29f801..0000000 --- a/Assets/Scripts/Controllers/UIController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7a478841ba5ae4b13a37f1061e5e65df -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/Core/Events/GameEvents.cs b/Assets/Scripts/Core/Events/GameEvents.cs index 5eb9d0c..3215cc7 100644 --- a/Assets/Scripts/Core/Events/GameEvents.cs +++ b/Assets/Scripts/Core/Events/GameEvents.cs @@ -1,25 +1,26 @@ using System; -// Central event system for communication +// Core game flow events: Central event system for communication // This is added to in other scripts, so they register to the event system and things get updated automatically. public static class GameEvents { // Events: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/event // Object triggers event that triggers handlers which are attached in other scripts // Actions: https://learn.microsoft.com/en-us/dotnet/api/system.action-1?view=net-8.0 // single param function with no return - public static event Action OnTrialCompleted; - public static event Action OnGamePhaseChanged; - public static event Action OnScoreUpdated; + + // Core game flow events only + public static event Action OnGamePhaseChanged; + public static event Action OnExperimentComplete; - public static void TrialCompleted(TrialResult result) { - OnTrialCompleted?.Invoke(result); - } - - public static void GamePhaseChanged(GamePhase phase) { - OnGamePhaseChanged?.Invoke(phase); - } - - public static void ScoreUpdated(int newScore) { - OnScoreUpdated?.Invoke(newScore); - } + // ReSharper disable Unity.PerformanceAnalysis + public static void GamePhaseChanged(GamePhase phase) + { + OnGamePhaseChanged?.Invoke(phase); + } + + // ReSharper disable Unity.PerformanceAnalysis + public static void ExperimentComplete(ExperimentData data) + { + OnExperimentComplete?.Invoke(data); + } } \ No newline at end of file diff --git a/Assets/Scripts/Core/Events/Level1Events.cs b/Assets/Scripts/Core/Events/Level1Events.cs new file mode 100644 index 0000000..85070dc --- /dev/null +++ b/Assets/Scripts/Core/Events/Level1Events.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; + +public static class Level1Events +{ + // Trial events + public static event Action OnNewTrialStarted; + public static event Action OnTrialCompleted; + public static event Action> OnStimulusShown; + + // Level flow events + public static event Action OnLevelStarted; + public static event Action OnStageChanged; // (newStage, targetScore) + public static event Action OnLevelComplete; + + // UI events + public static event Action OnScoreUpdated; + + public static event Action OnTrialStateChanged; + public static event Action OnReactionTimeRecorded; + public static event Action OnMedianRTUpdated; + public static event Action OnInvalidResponse; + + + public static void LevelStarted() => OnLevelStarted?.Invoke(); + public static void NewTrialStarted(double isi) => OnNewTrialStarted?.Invoke(isi); + public static void StimulusShown(Dictionary stimSpec) => OnStimulusShown?.Invoke(stimSpec); + public static void TrialCompleted(TrialResult result) => OnTrialCompleted?.Invoke(result); + public static void LevelComplete() => OnLevelComplete?.Invoke(); + public static void ScoreUpdated(int score) => OnScoreUpdated?.Invoke(score); + + public static void StageChanged(int stage, int targetScore) => + OnStageChanged?.Invoke(stage, targetScore); + + public static void TrialStateChanged(TrialState state) => OnTrialStateChanged?.Invoke(state); + public static void ReactionTimeRecorded(double rt) => OnReactionTimeRecorded?.Invoke(rt); + public static void MedianRTUpdated(float medianRT) => OnMedianRTUpdated?.Invoke(medianRT); + public static void InvalidResponse(string reason) => OnInvalidResponse?.Invoke(reason); +} + +public enum TrialState +{ + Ready, + WaitingForStimulus, + StimulusShown, + WaitingForResponse, + Complete +} \ No newline at end of file diff --git a/Assets/Scripts/Core/Events/Level1Events.cs.meta b/Assets/Scripts/Core/Events/Level1Events.cs.meta new file mode 100644 index 0000000..3cc8d4a --- /dev/null +++ b/Assets/Scripts/Core/Events/Level1Events.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2be256fd64fc46059b6428429cc16932 +timeCreated: 1732013291 \ No newline at end of file diff --git a/Assets/Scripts/Core/Processing/ScoreCalculator.cs b/Assets/Scripts/Core/Processing/ScoreCalculator.cs index cb288f1..d9b3668 100644 --- a/Assets/Scripts/Core/Processing/ScoreCalculator.cs +++ b/Assets/Scripts/Core/Processing/ScoreCalculator.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; // Calculates scores based on reaction times, Manages scoring rules, Handles score updates public class ScoreCalculator diff --git a/Assets/Scripts/Models/Data/DataPipeBody.cs b/Assets/Scripts/Models/Data/DataPipeBody.cs index c546ad6..e497e1a 100644 --- a/Assets/Scripts/Models/Data/DataPipeBody.cs +++ b/Assets/Scripts/Models/Data/DataPipeBody.cs @@ -16,5 +16,6 @@ public DataPipeBody(GameData dataObject, string experimentID, string participant : participantName + "_"; filename = $"DoggoNogo_{pName}{StringUtils.GenerateRandomId(10)}.json"; data = JsonUtility.ToJson(dataObject); + // is this returning properly? } } \ No newline at end of file diff --git a/Assets/Scripts/Models/Data/ExperimentData.cs b/Assets/Scripts/Models/Data/ExperimentData.cs new file mode 100644 index 0000000..1b7baaa --- /dev/null +++ b/Assets/Scripts/Models/Data/ExperimentData.cs @@ -0,0 +1,6 @@ +public class ExperimentData +{ + public int FinalScore { get; set; } + public int ValidTrials { get; set; } + public double FinalThreshold { get; set; } +} \ No newline at end of file diff --git a/Assets/Scripts/Models/Data/ExperimentData.cs.meta b/Assets/Scripts/Models/Data/ExperimentData.cs.meta new file mode 100644 index 0000000..e0d61d9 --- /dev/null +++ b/Assets/Scripts/Models/Data/ExperimentData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: af34559508904397acba569cb4e0d237 +timeCreated: 1732013454 \ No newline at end of file diff --git a/Assets/Scripts/Models/Data/Level1/Level1Data.cs b/Assets/Scripts/Models/Data/Level1/Level1Data.cs index 4cc8cfb..2f0242a 100644 --- a/Assets/Scripts/Models/Data/Level1/Level1Data.cs +++ b/Assets/Scripts/Models/Data/Level1/Level1Data.cs @@ -24,5 +24,6 @@ public void UpdateMedianRT(double newRT) currentMedianRT = SortedRTs.Count % 2 == 0 ? (float)((SortedRTs[mid] + SortedRTs[mid - 1]) / 2) : (float)SortedRTs[mid]; + Level1Events.MedianRTUpdated(currentMedianRT); } } \ No newline at end of file diff --git a/Assets/Scripts/Models/Data/Level1/Level1StageData.cs b/Assets/Scripts/Models/Data/Level1/Level1StageData.cs new file mode 100644 index 0000000..33e925e --- /dev/null +++ b/Assets/Scripts/Models/Data/Level1/Level1StageData.cs @@ -0,0 +1,56 @@ +using UnityEngine; + +public class Level1StageData: MonoBehaviour +{ + + // Public + public int CurrentStage { get; private set; } = 1; + public int TotalStages { get; } = 3; + public int CurrentTargetScore { get; set; } + // Private + private static Level1StageData Instance { get; set; } + private int MinTrialsPerStage { get; } = 10; + private int NTrials { get; } + + // Construct + private void Awake() + { + if (Instance != null) + { + Destroy(gameObject); + return; + } + Instance = this; + } + public Level1StageData(Metadata metadata, GameConfig gameConfig) + { + NTrials = int.TryParse(metadata.l1n, out int trials) ? trials : 60; + CurrentTargetScore = CalculateTargetScore(0, gameConfig.MinScore); + } + + public int CalculateTargetScore(int validTrialsCompleted, int minScore) + { + int trialsRemaining = NTrials - validTrialsCompleted; + int stagesRemaining = TotalStages + 1 - CurrentStage; + int trialsPerStage = trialsRemaining / stagesRemaining; + + // Calculate target + int expectedFastTrials = trialsPerStage / 2; + int targetScore = minScore * expectedFastTrials; + + // Apply minimum + int minimumTargetScore = (MinTrialsPerStage / 2) * minScore; + targetScore = Mathf.Max(targetScore, minimumTargetScore); + + Debug.Log($"New Target Score for Stage {CurrentStage}: {targetScore}"); + CurrentTargetScore = targetScore; + return targetScore; + } + + public bool AdvanceStage() + { + if (CurrentStage >= TotalStages) return false; + CurrentStage++; + return true; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Models/Data/Level1/Level1StageData.cs.meta b/Assets/Scripts/Models/Data/Level1/Level1StageData.cs.meta new file mode 100644 index 0000000..f586ab8 --- /dev/null +++ b/Assets/Scripts/Models/Data/Level1/Level1StageData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a21aefe6d3954e4285843b6f676c2eb3 +timeCreated: 1732025434 \ No newline at end of file diff --git a/Assets/Scripts/Models/Data/Trial.cs b/Assets/Scripts/Models/Data/Level1/Trial.cs similarity index 100% rename from Assets/Scripts/Models/Data/Trial.cs rename to Assets/Scripts/Models/Data/Level1/Trial.cs diff --git a/Assets/Scripts/Models/Data/Trial.cs.meta b/Assets/Scripts/Models/Data/Level1/Trial.cs.meta similarity index 100% rename from Assets/Scripts/Models/Data/Trial.cs.meta rename to Assets/Scripts/Models/Data/Level1/Trial.cs.meta diff --git a/Assets/Scripts/Models/Data/TrialResult.cs b/Assets/Scripts/Models/Data/Level1/TrialResult.cs similarity index 100% rename from Assets/Scripts/Models/Data/TrialResult.cs rename to Assets/Scripts/Models/Data/Level1/TrialResult.cs diff --git a/Assets/Scripts/Models/Data/TrialResult.cs.meta b/Assets/Scripts/Models/Data/Level1/TrialResult.cs.meta similarity index 100% rename from Assets/Scripts/Models/Data/TrialResult.cs.meta rename to Assets/Scripts/Models/Data/Level1/TrialResult.cs.meta diff --git a/Assets/Scripts/Services/DataService.cs b/Assets/Scripts/Services/DataService.cs index 648f7cf..e51eae0 100644 --- a/Assets/Scripts/Services/DataService.cs +++ b/Assets/Scripts/Services/DataService.cs @@ -4,11 +4,11 @@ // Manages data operations - unsure is properly distinguished from WebService? public class DataService : IDataService { - private readonly string apiUrl = "https://pipe.jspsych.org/api/data/"; - private readonly WebService webService; + private readonly string _apiUrl = "https://pipe.jspsych.org/api/data/"; + private readonly WebService _webService; public DataService(WebService webService) { - this.webService = webService; + this._webService = webService; } public async Task SaveData(GameData data) { @@ -18,7 +18,7 @@ public async Task SaveData(GameData data) { data.metadata.participantName); string json = JsonUtility.ToJson(dataPipeBody); - return await webService.PostData(apiUrl, json); + return await _webService.PostData(_apiUrl, json); } catch (Exception ex) { Debug.LogError($"Failed to save data: {ex.Message}"); diff --git a/Assets/Scripts/Views/Game/Components/DogView.cs b/Assets/Scripts/Views/Game/Components/DogView.cs index fe833f5..bc92063 100644 --- a/Assets/Scripts/Views/Game/Components/DogView.cs +++ b/Assets/Scripts/Views/Game/Components/DogView.cs @@ -57,11 +57,9 @@ public void TakeDamage() public void StartJump(int height) { - if (!_isJumping) - { - maxJumpHeight = height; - StartCoroutine(JumpAnimation()); - } + if (_isJumping) return; + maxJumpHeight = height; + StartCoroutine(JumpAnimation()); } // Audio methods diff --git a/Assets/Scripts/Views/Game/Components/FeedbackView.cs b/Assets/Scripts/Views/Game/Components/FeedbackView.cs index 370b556..c5de46b 100644 --- a/Assets/Scripts/Views/Game/Components/FeedbackView.cs +++ b/Assets/Scripts/Views/Game/Components/FeedbackView.cs @@ -114,11 +114,13 @@ public IEnumerator ChangeLevel(int level, int targetScore) healthBar.SetNewTarget(targetScore); scoreText.text = "Score: 0"; - if (level == 2) - backgroundMusic.pitch = 1.15f; - else if (level == 3) - backgroundMusic.pitch = 1.3f; - + backgroundMusic.pitch = level switch + { + 2 => 1.15f, + 3 => 1.3f, + _ => backgroundMusic.pitch + }; + changingLevel = false; } diff --git a/Assets/Scripts/Views/Game/GameplayCanvas.cs b/Assets/Scripts/Views/Game/GameplayCanvas.cs deleted file mode 100644 index e69de29..0000000 diff --git a/Assets/Scripts/Views/Game/GameplayCanvas.cs.meta b/Assets/Scripts/Views/Game/GameplayCanvas.cs.meta deleted file mode 100644 index 134b236..0000000 --- a/Assets/Scripts/Views/Game/GameplayCanvas.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dcf3fcfa9d50e4fafa033f17d447b85c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/Views/UI/Components/ScoreDisplay.cs b/Assets/Scripts/Views/UI/Components/ScoreDisplay.cs deleted file mode 100644 index d7dae4f..0000000 --- a/Assets/Scripts/Views/UI/Components/ScoreDisplay.cs +++ /dev/null @@ -1,22 +0,0 @@ -using TMPro; -using UnityEngine; - -// Shows current score -// This is probably the text on screen for score in L1. -// not sure it really needs the onenable/disable stuff? Event shouldn't be firing anyway. -public class ScoreDisplay : MonoBehaviour { - [SerializeField] private TextMeshProUGUI scoreText; - [SerializeField] private TextMeshProUGUI totalScoreText; - - private void OnEnable() { - GameEvents.OnScoreUpdated += UpdateScore; - } - - private void OnDisable() { - GameEvents.OnScoreUpdated -= UpdateScore; - } - - public void UpdateScore(int newScore) { - scoreText.text = $"Score: {newScore}"; - } -} \ No newline at end of file diff --git a/Assets/Scripts/Views/UI/Components/ScoreDisplay.cs.meta b/Assets/Scripts/Views/UI/Components/ScoreDisplay.cs.meta deleted file mode 100644 index 7314638..0000000 --- a/Assets/Scripts/Views/UI/Components/ScoreDisplay.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a35824287d42c42f39b8e0800efd7a01 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/Views/UI/Screens/IntroStory/IntroStoryView.cs b/Assets/Scripts/Views/UI/Screens/IntroStory/IntroStoryView.cs index 1df982f..4281222 100644 --- a/Assets/Scripts/Views/UI/Screens/IntroStory/IntroStoryView.cs +++ b/Assets/Scripts/Views/UI/Screens/IntroStory/IntroStoryView.cs @@ -141,7 +141,7 @@ private async void AdvanceChapter() } } - private void LoadGameScene() + private static void LoadGameScene() { SceneManager.LoadScene("Simple RT"); } diff --git a/Assets/Scripts/Views/UI/Screens/Level1Screen.meta b/Assets/Scripts/Views/UI/Screens/Level1Screen.meta new file mode 100644 index 0000000..c2c25af --- /dev/null +++ b/Assets/Scripts/Views/UI/Screens/Level1Screen.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d95c4a79e1ee441f912b0467f176bcff +timeCreated: 1732014646 \ No newline at end of file diff --git a/Assets/Scripts/Views/UI/Screens/IntroScreen.cs b/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1IntroductionView.cs similarity index 94% rename from Assets/Scripts/Views/UI/Screens/IntroScreen.cs rename to Assets/Scripts/Views/UI/Screens/Level1Screen/Level1IntroductionView.cs index f555155..79ce1a0 100644 --- a/Assets/Scripts/Views/UI/Screens/IntroScreen.cs +++ b/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1IntroductionView.cs @@ -5,7 +5,7 @@ // Intro to Level1 // do I need dog image or just dogView reference? -public class IntroScreen : MonoBehaviour +public class Level1IntroductionView : MonoBehaviour { [Header("UI References")] [SerializeField] private GameObject instructions; @@ -20,8 +20,10 @@ public class IntroScreen : MonoBehaviour [SerializeField] private float swingFrequency = 3f; [SerializeField] private float swingDampening = 3f; + private UIAnimationController _animationController; private bool _viewingInstructions = true; private bool _allowContinue = false; + private void Start() { @@ -51,7 +53,7 @@ private void StartGame() instructions.SetActive(false); scoreCard.SetActive(true); _viewingInstructions = false; - GameController.Instance.StartGame(); + Level1Controller.Instance.StartLevel(); } private IEnumerator FadeIn(float duration, Graphic graphic) diff --git a/Assets/Scripts/Views/UI/Screens/IntroScreen.cs.meta b/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1IntroductionView.cs.meta similarity index 100% rename from Assets/Scripts/Views/UI/Screens/IntroScreen.cs.meta rename to Assets/Scripts/Views/UI/Screens/Level1Screen/Level1IntroductionView.cs.meta diff --git a/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1UI.cs b/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1UI.cs new file mode 100644 index 0000000..27c9eac --- /dev/null +++ b/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1UI.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +// Main game screen - I think this is Level1 UI and needs to be updated with dog and bone views, and other methods +public class Level1UI : MonoBehaviour +{ + [SerializeField] private FeedbackView feedbackView; + + private void OnEnable() + { + Level1Events.OnStageChanged += HandleStageChange; + } + + private void HandleStageChange(int newStage, int targetScore) + { + // Play evolution animation + StartCoroutine(feedbackView.ChangeLevel(newStage, targetScore)); + } + + public void Feedback(TrialResult result) + { + feedbackView.GiveFeedback(result); + } + + private void OnDisable() + { + Level1Events.OnStageChanged -= HandleStageChange; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Views/UI/Screens/MainGameUI.cs.meta b/Assets/Scripts/Views/UI/Screens/Level1Screen/Level1UI.cs.meta similarity index 100% rename from Assets/Scripts/Views/UI/Screens/MainGameUI.cs.meta rename to Assets/Scripts/Views/UI/Screens/Level1Screen/Level1UI.cs.meta diff --git a/Assets/Scripts/Views/UI/Screens/MainGameUI.cs b/Assets/Scripts/Views/UI/Screens/MainGameUI.cs deleted file mode 100644 index 52be70d..0000000 --- a/Assets/Scripts/Views/UI/Screens/MainGameUI.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UnityEngine; - -// Main game screen - I think this is Level1 UI and needs to be updated with dog and bone views, and other methods -public class MainGameUI : MonoBehaviour -{ - [SerializeField] private FeedbackView feedbackView; - [SerializeField] private ScoreDisplay scoreDisplay; - [SerializeField] private HealthBarView healthBar; - - public void UpdateScore(int score) - { - scoreDisplay.UpdateScore(score); - } - - public void UpdateTrial(int currentTrial, int totalTrials) - { - // Update trial progress if needed - } -} \ No newline at end of file