From 6a0ae97e11c7bb9ba8d75dbb9beadbee4d4a733e Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Thu, 14 May 2026 15:16:19 +0100 Subject: [PATCH 1/8] reduce gaze tolerance setting --- projects/AstroBalance/Assets/Scenes/RocketLaunch.unity | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity b/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity index 53a05a0..85e5c32 100644 --- a/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity +++ b/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity @@ -21548,7 +21548,7 @@ PrefabInstance: objectReference: {fileID: 522649600} - target: {fileID: 8902890511493098178, guid: 00c1b36d25d21214eb8e6df02c079dea, type: 3} propertyPath: gazeTolerance - value: 300 + value: 3 objectReference: {fileID: 0} - target: {fileID: 8902890511493098178, guid: 00c1b36d25d21214eb8e6df02c079dea, type: 3} propertyPath: gazeStatusText From 7d2371970af1f1a43b94031b40441b258b861a82 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Thu, 14 May 2026 15:18:16 +0100 Subject: [PATCH 2/8] use world coordinates for mouse position --- .../Assets/Scripts/RocketLaunch/LaunchControl.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs index 35cba0a..7a2f33b 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs @@ -263,8 +263,9 @@ private GazeItem AddToBuffers() headPose.Rotation.RollDegrees = 0f; headPose.TimeStampMicroSeconds = (long)(Time.timeSinceLevelLoad * 1000000); - gazeItem.gazePoint.X = mousePos.x; - gazeItem.gazePoint.Y = mousePos.y; + Vector3 mousePoseWorld = Camera.main.ScreenToWorldPoint(mousePos); + gazeItem.gazePoint.X = mousePoseWorld.x; + gazeItem.gazePoint.Y = mousePoseWorld.y; gazeItem.gazePoint.TimeStampMicroSeconds = (long)(Time.timeSinceLevelLoad * 1000000); } else From 2e128bafeddd7c725769e8997796afaa8ca48c4b Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Thu, 14 May 2026 15:19:17 +0100 Subject: [PATCH 3/8] remove double adaptiveDifficulty multiplier to launchTime --- .../AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs index 7a2f33b..31db3bb 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs @@ -145,7 +145,7 @@ void Start() ? "Nod your head and repeat the code to launch the rocket!" : "Shake your head and repeat the code to launch the rocket!"; gameData = new RocketLaunchData(); - timeToLaunch = (float)launchTime * adaptiveDifficulty; + timeToLaunch = launchTime; gazeBuffer = new GazeBuffer(gazeBufferCapacity, minDataRequired); incrementCountDownCode(); } From 3043ef76f0b3a43b4b90d2550c595c7ef6b8e797 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Thu, 14 May 2026 15:23:44 +0100 Subject: [PATCH 4/8] have explicit variables for pitch and yaw minimum speed --- .../Scripts/RocketLaunch/LaunchControl.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs index 31db3bb..c3856e3 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs @@ -20,16 +20,16 @@ public class LaunchControl : MonoBehaviour [SerializeField, Tooltip("The time in seconds to measure head speed over.")] private float speedTime = 2.0f; - [SerializeField, Tooltip("The minimum head speed required to reduce the launch timer.")] - private float minimumSpeed = 20; + [SerializeField, Tooltip("The minimum head pitch speed required to reduce the launch timer.")] + private float minimumSpeedPitch = 20; [ SerializeField, Tooltip( - "A pitch/yaw scale factor, as in general I can shake my head faster than I can nod." + "The minimum head yaw speed required to reduce the launch timer. Usually set higher than pitch, as in I can shake my head faster than I can nod" ) ] - private float shakeSpeedReduction = 0.5f; + private float minimumSpeedYaw = 40; [Header("Steady Gaze Variables")] [SerializeField, Tooltip("Time between new random numbers in seconds.")] @@ -96,6 +96,7 @@ public class LaunchControl : MonoBehaviour // head speed parameters private HeadPoseBuffer headPoseBuffer; private bool usePitch; //true if we're using pitch speed, false if we're using yaw speed. + private float minimumSpeed; // minimum head speed required for this game private RocketLaunchData gameData; private float rocketSpeed; private int minDataRequired = 2; // we need at least 2 data points to calculate a speed or steadiness @@ -140,6 +141,8 @@ void Start() { usePitch = !lastGameData.Last().pitch; } + minimumSpeed = usePitch ? minimumSpeedPitch : minimumSpeedYaw; + headPoseBuffer = new HeadPoseBuffer(headPoseBufferCapacity, minDataRequired); instructionsText.text = usePitch ? "Nod your head and repeat the code to launch the rocket!" @@ -181,10 +184,8 @@ void Update() else { headSpeed = - ( - headPoseBuffer.getSpeed(speedTime, HeadPoseAxis.Yaw) - - headPoseBuffer.getSpeed(speedTime, HeadPoseAxis.Pitch) - ) * shakeSpeedReduction; + headPoseBuffer.getSpeed(speedTime, HeadPoseAxis.Yaw) + - headPoseBuffer.getSpeed(speedTime, HeadPoseAxis.Pitch); } headSpeed = Mathf.Max(0, headSpeed); // Clamp to zero to avoid negative speeds From f90da91e704c223b5427579ed8f5fba1ba96a223 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Thu, 14 May 2026 15:37:50 +0100 Subject: [PATCH 5/8] scale the target object to match the gaze tolerance --- .../Assets/Scenes/RocketLaunch.unity | 2 +- .../Scripts/RocketLaunch/LaunchControl.cs | 42 +++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity b/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity index 85e5c32..444043e 100644 --- a/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity +++ b/projects/AstroBalance/Assets/Scenes/RocketLaunch.unity @@ -21548,7 +21548,7 @@ PrefabInstance: objectReference: {fileID: 522649600} - target: {fileID: 8902890511493098178, guid: 00c1b36d25d21214eb8e6df02c079dea, type: 3} propertyPath: gazeTolerance - value: 3 + value: 2 objectReference: {fileID: 0} - target: {fileID: 8902890511493098178, guid: 00c1b36d25d21214eb8e6df02c079dea, type: 3} propertyPath: gazeStatusText diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs index c3856e3..22a9aff 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs @@ -41,7 +41,12 @@ public class LaunchControl : MonoBehaviour [SerializeField, Tooltip("The time in seconds that the gaze should be steady for.")] private float gazeTime = 3.0f; - [SerializeField, Tooltip("The tolerance in unity coordinates that gaze needs to stay within.")] + [ + SerializeField, + Tooltip( + "The tolerance in unity coordinates that gaze needs to stay within (the size of the targetObject is scaled to match)" + ) + ] private float gazeTolerance = 3.0f; [SerializeField, Tooltip("The game object the user is supposed to look at.")] @@ -129,7 +134,6 @@ void Start() adaptiveDifficulty *= ((float)maxPreviousGames + (float)lastGameData.Count()) / (float)maxPreviousGames; - targetObject.GetComponent().transform.localScale /= adaptiveDifficulty; gazeTolerance /= adaptiveDifficulty; launchTime *= adaptiveDifficulty; @@ -143,6 +147,8 @@ void Start() } minimumSpeed = usePitch ? minimumSpeedPitch : minimumSpeedYaw; + InitialiseTarget(); + headPoseBuffer = new HeadPoseBuffer(headPoseBufferCapacity, minDataRequired); instructionsText.text = usePitch ? "Nod your head and repeat the code to launch the rocket!" @@ -150,7 +156,27 @@ void Start() gameData = new RocketLaunchData(); timeToLaunch = launchTime; gazeBuffer = new GazeBuffer(gazeBufferCapacity, minDataRequired); + } + + /// + /// Initialise sprite of target, and scale size to match gaze tolerance + /// + private void InitialiseTarget() + { + targetObject.SetActive(false); incrementCountDownCode(); + + // Match width and height of target to gaze tolerance + Renderer targetRenderer = targetObject.transform.GetComponent(); + float targetObjectWidth = targetRenderer.bounds.extents.x; + float targetObjectHeight = targetRenderer.bounds.extents.y; + Vector3 targetScale = targetRenderer.transform.localScale; + targetScale.Scale( + new Vector3(gazeTolerance / targetObjectWidth, gazeTolerance / targetObjectWidth, 1) + ); + targetRenderer.transform.localScale = targetScale; + + targetObject.SetActive(true); } // Update is called once per frame @@ -197,16 +223,8 @@ void Update() // use centre of bounds in case the target object is not centred targetX = targetObject.transform.GetComponent().bounds.center.x; targetY = targetObject.transform.GetComponent().bounds.center.y; - Vector2 gazeTol = new Vector2( - targetObject.transform.GetComponent().bounds.extents.x, - targetObject.transform.GetComponent().bounds.extents.y - ); - gazeIsSteady = gazeBuffer.gazeSteady( - gazeTime, - gazeTolerance * gazeTol.magnitude, - targetX, - targetY - ); + + gazeIsSteady = gazeBuffer.gazeSteady(gazeTime, gazeTolerance, targetX, targetY); } else { From a7e28470ea9a2a88c152f7e2532bed700b6f6614 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Fri, 15 May 2026 10:00:15 +0100 Subject: [PATCH 6/8] scale the progress ring to match the target --- .../Scripts/RocketLaunch/LaunchControl.cs | 18 ++++++++--- .../RocketLaunch/LaunchProgressRing.cs | 31 +++++++++++++++++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs index 22a9aff..fc18e9e 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs @@ -44,7 +44,7 @@ public class LaunchControl : MonoBehaviour [ SerializeField, Tooltip( - "The tolerance in unity coordinates that gaze needs to stay within (the size of the targetObject is scaled to match)" + "The tolerance in unity coordinates that gaze needs to stay within (the targetObject is scaled to match)" ) ] private float gazeTolerance = 3.0f; @@ -117,8 +117,8 @@ public class LaunchControl : MonoBehaviour private TextMeshProUGUI winText; - // Start is called once before the first execution of Update after the MonoBehaviour is created - void Start() + // Awake is called once when the script instance is loaded + void Awake() { rocketSpeed = 0f; winText = winScreen.GetComponentInChildren(); @@ -153,11 +153,16 @@ void Start() instructionsText.text = usePitch ? "Nod your head and repeat the code to launch the rocket!" : "Shake your head and repeat the code to launch the rocket!"; - gameData = new RocketLaunchData(); timeToLaunch = launchTime; gazeBuffer = new GazeBuffer(gazeBufferCapacity, minDataRequired); } + // Start is called once before the first execution of Update after the MonoBehaviour is created + private void Start() + { + gameData = new RocketLaunchData(); + } + /// /// Initialise sprite of target, and scale size to match gaze tolerance /// @@ -264,6 +269,11 @@ public float HeadSpeed get => headSpeed; } + public GameObject TargetObject + { + get => targetObject; + } + /// /// Adds latest tracking data to buffers and returns latest gaze information /// diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchProgressRing.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchProgressRing.cs index 6426f2c..9bcd622 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchProgressRing.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchProgressRing.cs @@ -1,12 +1,10 @@ using System.Collections; -using TMPro; -using Tobii.GameIntegration.Net; using UnityEngine; using UnityEngine.UI; public class LaunchProgressRing : MonoBehaviour { - [SerializeField, Tooltip("Arrow fill colour")] + [SerializeField, Tooltip("Ring fill colour")] private Color fillColor = Color.red; LaunchControl countdownController; @@ -30,6 +28,33 @@ void Start() } fillImage.color = fillColor; + + FitToCountdown(); + } + + /// + /// Fit the progress ring position and size to the countdown target + /// + private void FitToCountdown() + { + GameObject targetObject = countdownController.TargetObject; + fillImage.transform.position = Camera.main.WorldToScreenPoint( + targetObject.transform.position + ); + + Renderer targetRenderer = targetObject.transform.GetComponent(); + float targetObjectWidth = 2 * targetRenderer.bounds.extents.x; + float targetObjectHeight = 2 * targetRenderer.bounds.extents.y; + + // length of 1 unity world unit in this screen space + float scalingFactor = Vector3.Distance( + Camera.main.WorldToScreenPoint(new Vector3(0, 0, 0)), + Camera.main.WorldToScreenPoint(new Vector3(1, 0, 0)) + ); + float requiredWidth = (targetObjectWidth * scalingFactor) / fillImage.canvas.scaleFactor; + float requiredHeight = (targetObjectHeight * scalingFactor) / fillImage.canvas.scaleFactor; + + fillImage.rectTransform.sizeDelta = new Vector2(requiredWidth, requiredHeight); } // Update is called once per frame From 0e31494399d2cd605625039c9a3bbcfe79b7b022 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Fri, 15 May 2026 10:27:22 +0100 Subject: [PATCH 7/8] update rocket launch docs to match changes --- docs/rocket-launch.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/rocket-launch.md b/docs/rocket-launch.md index 455683f..44a49e1 100644 --- a/docs/rocket-launch.md +++ b/docs/rocket-launch.md @@ -10,12 +10,12 @@ then a timer decrements until launch time is achieved. - Launch time: The starting launch time in seconds. May be increased by adaptive difficulty features below. - **Head Movement Variables**: Determine the amount of head movement required to decrement the timer. - Head Pose Buffer Capacity (n) and speed time (s): head speed is measured as the average change in pitch or yaw over the time period speed time. The buffer will need to be sufficiently large to support the time based on game frame rate. - - Shake Speed Reduction: Because it is possible (for me at least) to shake my head quicker than I can nod, there is a scaling factor between the head speeds required for shaking or nodding. Setting to 0.5 for example means that the player must shake their head twice as fast as nodding to achieve the same effect. + - Minimum head speed (pitch or yaw) required to reduce the launch timer. The yaw speed is set higher than pitch, because it is possible (for me at least) to shake my head quicker than I can nod. - **Steady Gaze Variables**: Determine how steady the gave must be to decrement the timer. - Timer Duration: How long (in seconds) the player must maintain a steady gaze to increment the count down code display. - Gaze Pose Buffer Capacity (n) and gaze time (s), gaze steadiness is measured as the standard deviation of gaze over gaze time seconds. The buffer will need to be sufficiently large to support the time based on game frame rate. - Gaze Tolerance - the allowable gaze standard deviation to be steady. Smaller number will require steadier gaze. This may be reduced by the adaptive difficulty settings below. - - Target Object if this is set you are required to look at that object, if not gaze can be anywhere on screen but must be steady. + - Target Object - if this is set you are required to look at that object, if not gaze can be anywhere on screen but must be steady. The size of the target object will be matched to the gaze tolerance. - **Adaptive difficulty variables** - Max previous games: The maximum number of previous games to retrieve to determine experience based difficulty @@ -43,13 +43,12 @@ then a timer decrements until launch time is achieved. ## Adaptive difficulty -Difficulty is increased between games by reducing the size of the gaze target, reducing the gaze tolerance, and increasing the overall launch time (explained below). The intention is that the gaze tolerance should always match the size of the gaze target, however this hasn't been verified through play testing yet. Note: all parameters mentioned below can be adjusted on `LaunchControl`. +Difficulty is increased between games by reducing the gaze tolerance, and increasing the overall launch time (explained below). Note: all parameters mentioned below can be adjusted on `LaunchControl`. At the start of each game, a scaling factor is calculated as: `adaptiveDifficulty` * ( (`maxPreviousGames` + `nGames`) / `maxPreviousGames`) `nGames` is the total number of rocket launch games completed by the player so far (up to a maximum of `maxPreviousGames`). The scaling factor is then applied: -- the size of the gaze target (the box displaying the launch code numbers) is divided by the scaling factor. This makes it smaller after more games have been played. -- the gaze tolerance (i.e. the tolerance in unity coordinates that gaze needs to stay within) is divided by the scaling factor. This means the player must keep their gaze closer to the target after more games have been played. +- the gaze tolerance (i.e. the tolerance in unity coordinates that gaze needs to stay within) is divided by the scaling factor. This will also scale the gaze target (the box displaying the launch code numbers) to match. This means the player must keep their gaze closer to the target after more games have been played. - the launch time is multiplied by the scaling factor. This means the player must move their head while looking at the target for longer to launch the rocket. From d240b561607cc6859e14e8302f5369f3f06bc607 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Fri, 15 May 2026 10:55:24 +0100 Subject: [PATCH 8/8] fix typo --- .../AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs index fc18e9e..02548a7 100644 --- a/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs +++ b/projects/AstroBalance/Assets/Scripts/RocketLaunch/LaunchControl.cs @@ -26,7 +26,7 @@ public class LaunchControl : MonoBehaviour [ SerializeField, Tooltip( - "The minimum head yaw speed required to reduce the launch timer. Usually set higher than pitch, as in I can shake my head faster than I can nod" + "The minimum head yaw speed required to reduce the launch timer. Usually set higher than pitch, as I can shake my head faster than I can nod" ) ] private float minimumSpeedYaw = 40;