diff --git a/docs/star-collector.md b/docs/star-collector.md index c376bcd0..7632642f 100644 --- a/docs/star-collector.md +++ b/docs/star-collector.md @@ -6,14 +6,16 @@ top of the screen. ## Main objects / values to edit during play testing - **StarCollectorManager**: values related to the overall win condition of the game - - Min / max time limit - - The % of stars that must be collected to increase speed or time limit + - Min / max time limit in seconds + - Time limit increment in seconds (if time limit upgrade % is met) + - Number of games in a row that must meet the upgrade % to increase the time limit - The length of the time window used to evaluate player performance - + - The % of stars that must be collected to increase speed or time limit + - **StarGenerator**: values related to generation of the wave of stars - - Min / max star speed + - Min, max and base star speed - The amount the star speed increases per upgrade - - Shape of the wave (e.g. width, distance between stars...) + - Shape of the wave (e.g. width, swerve, star sampling) - **Ship**: values related to ship movement - The amount the ship moves per degree of head movement (X By Degrees) \ No newline at end of file diff --git a/projects/AstroBalance/Assets/Scenes/StarCollector.unity b/projects/AstroBalance/Assets/Scenes/StarCollector.unity index 04cf1690..54458524 100644 --- a/projects/AstroBalance/Assets/Scenes/StarCollector.unity +++ b/projects/AstroBalance/Assets/Scenes/StarCollector.unity @@ -370,6 +370,8 @@ MonoBehaviour: starGenerator: {fileID: 1755869804} minTimeLimit: 60 maxTimeLimit: 180 + timeLimitIncrement: 60 + nGamesToUpgrade: 3 difficultyWindowSeconds: 10 speedUpgradePercent: 60 timeLimitUpgradePercent: 60 @@ -463,6 +465,107 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1034761066} m_CullTransparentMesh: 1 +--- !u!1001 &1178398765 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 2095903232} + m_Modifications: + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_SizeDelta.x + value: 200 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_SizeDelta.y + value: 50 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_AnchoredPosition.x + value: 145 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_AnchoredPosition.y + value: 222 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3060515120221018932, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3963520631102135163, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_Name + value: Head Pose Debugger + objectReference: {fileID: 0} + - target: {fileID: 3963520631102135163, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 61125f32186bebb4aadc71f1810d8ebd, type: 3} --- !u!1001 &1260672149 PrefabInstance: m_ObjectHideFlags: 0 @@ -664,12 +767,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a7165a8b1c6e77848a390216111a1fab, type: 3} m_Name: m_EditorClassIdentifier: - baseStarSpeed: 3 + baseStarSpeed: 4 maxStarSpeed: 10 minStarSpeed: 2 - speedIncrement: 1 - starCreationDistance: 2.5 - swerve: 0.1 + speedIncrement: 0.5 + starSampling: 8 + swerve: 0.8 waveWidth: 3 starPrefab: {fileID: 7594402928058972626, guid: f672f33e77ac96d40a106fe9e6adae33, type: 3} --- !u!4 &1755869805 @@ -1012,7 +1115,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8540260659054522905, guid: 0bd45bf01b9169247abd68f16dd9a6ea, type: 3} propertyPath: m_AnchoredPosition.y - value: 59.609314 + value: 59.609375 objectReference: {fileID: 0} - target: {fileID: 8540260659054522905, guid: 0bd45bf01b9169247abd68f16dd9a6ea, type: 3} propertyPath: m_LocalEulerAnglesHint.x diff --git a/projects/AstroBalance/Assets/Scripts/StarCollector/Star.cs b/projects/AstroBalance/Assets/Scripts/StarCollector/Star.cs index 1acd9740..0dde7501 100644 --- a/projects/AstroBalance/Assets/Scripts/StarCollector/Star.cs +++ b/projects/AstroBalance/Assets/Scripts/StarCollector/Star.cs @@ -22,7 +22,7 @@ void Update() var pos = transform.position; transform.position = new Vector3( pos.x, - pos.y - starGenerator.baseStarSpeed * Time.deltaTime, + pos.y - starGenerator.GetStarSpeed() * Time.deltaTime, pos.z ); diff --git a/projects/AstroBalance/Assets/Scripts/StarCollector/StarCollectorManager.cs b/projects/AstroBalance/Assets/Scripts/StarCollector/StarCollectorManager.cs index 89083f85..3972c86b 100644 --- a/projects/AstroBalance/Assets/Scripts/StarCollector/StarCollectorManager.cs +++ b/projects/AstroBalance/Assets/Scripts/StarCollector/StarCollectorManager.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using TMPro; using UnityEngine; @@ -21,6 +23,17 @@ public class StarCollectorManager : MonoBehaviour [SerializeField, Tooltip("Maximum game time limit in seconds")] private int maxTimeLimit = 180; + [SerializeField, Tooltip("Time limit increase if timeLimitUpgradePercent is met")] + private int timeLimitIncrement = 60; + + [ + SerializeField, + Tooltip( + "Number of games in a row that must meet timeLimitUpgradePercent to increase the time limit" + ) + ] + private int nGamesToUpgrade = 3; + [SerializeField, Tooltip("Length of time window (in seconds) to evaluate player perfomance")] private int difficultyWindowSeconds = 10; @@ -51,32 +64,63 @@ public class StarCollectorManager : MonoBehaviour // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { + ChooseGameTimeLimit(); + winText = winScreen.GetComponentInChildren(); + gameData = new StarCollectorData(); + score = 0; + scoreText.text = score.ToString(); + timer.StartCountdown(timeLimit); - // Load last game data (if any) from file + choose time limit for this game + windowStart = Time.time; + } + + /// + /// Load previous game data (if any), and choose time limit for this game based + /// on prior perfomance. + /// + private void ChooseGameTimeLimit() + { SaveData saveData = new(saveFilename); - StarCollectorData lastGameData = saveData.GetLastCompleteGameData(); + IEnumerable lastNGamesData = saveData.GetLastNCompleteGamesData( + nGamesToUpgrade + ); - if (lastGameData == null) + if (lastNGamesData.Count() < nGamesToUpgrade) { SetTimeLimit(minTimeLimit); + return; } - else if (lastGameData.percentStarsCollected > timeLimitUpgradePercent) + + // Upgrade if all the last n games have the same time limit + meet the upgrade + // percent. If it's a mix of time limits, then we haven't played enough games at + // this level yet to progress. + int nGamesAtUpgradePercent = 0; + bool allSameTimeLimit = true; + int lastTimeLimit = lastNGamesData.Last().timeLimitSeconds; + + foreach (StarCollectorData data in lastNGamesData) + { + if (data.timeLimitSeconds != lastTimeLimit) + { + allSameTimeLimit = false; + break; + } + + if (data.percentStarsCollected > timeLimitUpgradePercent) + { + nGamesAtUpgradePercent++; + } + } + + if (allSameTimeLimit && nGamesAtUpgradePercent >= nGamesToUpgrade) { - // Increase time limit by 30 seconds vs last game - SetTimeLimit(lastGameData.timeLimitSeconds + 30); + SetTimeLimit(lastTimeLimit + timeLimitIncrement); } else { - SetTimeLimit(lastGameData.timeLimitSeconds); + SetTimeLimit(lastTimeLimit); } - - gameData = new StarCollectorData(); - score = 0; - scoreText.text = score.ToString(); - timer.StartCountdown(timeLimit); - - windowStart = Time.time; } // Update is called once per frame @@ -115,12 +159,10 @@ private void UpdateDifficulty() if (percentCollected > speedUpgradePercent) { - Debug.Log("Increasing difficulty"); starGenerator.IncreaseSpeed(); } else { - Debug.Log("Decreasing difficulty"); starGenerator.DecreaseSpeed(); } diff --git a/projects/AstroBalance/Assets/Scripts/StarCollector/StarGenerator.cs b/projects/AstroBalance/Assets/Scripts/StarCollector/StarGenerator.cs index 91495668..3a0807a2 100644 --- a/projects/AstroBalance/Assets/Scripts/StarCollector/StarGenerator.cs +++ b/projects/AstroBalance/Assets/Scripts/StarCollector/StarGenerator.cs @@ -2,29 +2,31 @@ public class StarGenerator : MonoBehaviour { - [SerializeField, Tooltip("Default speed of generated stars")] - public float baseStarSpeed = 3f; + [SerializeField, Tooltip("Default speed of generated stars (unity units / second)")] + public float baseStarSpeed = 4f; - [SerializeField, Tooltip("Maximum speed of generated stars")] + [SerializeField, Tooltip("Maximum speed of generated stars (unity units / second)")] private float maxStarSpeed = 10f; - [SerializeField, Tooltip("Minimum speed of generated stars")] + [SerializeField, Tooltip("Minimum speed of generated stars (unity units / second)")] private float minStarSpeed = 2f; [ SerializeField, - Tooltip("Speed increment used when dynamically increasing or decreasing star speed") + Tooltip( + "Speed increment used when dynamically increasing or decreasing star speed (unity units / second)" + ) ] - private float speedIncrement = 1f; + private float speedIncrement = 0.5f; - [SerializeField, Tooltip("Distance between generated stars on the y axis")] - private float starCreationDistance = 2.5f; + [SerializeField, Tooltip("Number of stars to spawn per cycle of the wave")] + private float starSampling = 8f; [ SerializeField, Tooltip("Higher swerve generates a wave that oscillates from left to right more often") ] - private float swerve = 0.1f; + private float swerve = 0.8f; [SerializeField, Tooltip("Width of the generated wave of stars on the x axis")] private float waveWidth = 3f; @@ -35,11 +37,16 @@ public class StarGenerator : MonoBehaviour private float pathDistance = 15f; private float frontier = 0; private float d_eff; + private float starCreationDistance; // y distance between spawned stars private bool isGenerating = true; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { + // Calculate y distance between stars so there are 'starSampling' stars per cycle + float yWavelength = (2 * Mathf.PI) / swerve; + starCreationDistance = yWavelength / starSampling; + InitStars(); } @@ -75,6 +82,11 @@ public void DecreaseSpeed() UpdateSpeed(-speedIncrement); } + public float GetStarSpeed() + { + return baseStarSpeed; + } + private void UpdateSpeed(float increment) { float nextSpeed = baseStarSpeed + increment; @@ -90,6 +102,8 @@ private void UpdateSpeed(float increment) { baseStarSpeed = nextSpeed; } + + Debug.Log($"Updated star speed to {nextSpeed}"); } public void StopGeneration()