Skip to content

Commit b1d1c18

Browse files
authored
Merge pull request #2 from JFrit/alternate-trialmanager-offsets
New TrialManager structure for flexible experiment creation
2 parents 1f53ee8 + c4d464f commit b1d1c18

4 files changed

Lines changed: 170 additions & 38 deletions

File tree

Assets/Scripts/ScriptableObjects/SessionSettings.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ public enum FeedbackType
7171
public float minDotLifetime;
7272
public float maxDotLifetime;
7373
public bool buddyDotsEnabled;
74+
public float outerStimulusStart;
75+
public float innerStimulusStart;
76+
public float attentionCueStart;
77+
78+
public float inputStart;
79+
public float inputDuration;
80+
public float fixationBreakCheckStart;
81+
public float fixationBreakCheckDuration;
7482

7583
// IMPORTANT: Any changes made in this function should be cross-checked with both the corresponding JSON
7684
// and the UXF data-points collection
@@ -94,7 +102,9 @@ public void LoadFromUxfJson()
94102
innerStimulusNoisePercentage = Convert.ToSingle(sessionSettingsDict["InnerStimulusNoisePercentage"]);
95103
innerStimulusRadius = Convert.ToSingle(sessionSettingsDict["InnerStimulusRadiusDegrees"]);
96104
innerStimulusSpawnRadius = Convert.ToSingle(sessionSettingsDict["InnerStimulusSpawnRadius"]);
105+
outerStimulusStart = Convert.ToSingle(sessionSettingsDict["OuterStimulusStartMs"]);
97106
outerStimulusDuration = Convert.ToSingle(sessionSettingsDict["OuterStimulusDurationMs"]);
107+
innerStimulusStart = Convert.ToSingle(sessionSettingsDict["InnerStimulusStartMs"]);
98108
innerStimulusDuration = Convert.ToSingle(sessionSettingsDict["InnerStimulusDurationMs"]);
99109
stimulusDepth = Convert.ToSingle(sessionSettingsDict["StimulusDepthMeters"]);
100110
interTrialDelay = Convert.ToSingle(sessionSettingsDict["InterTrialDelaySeconds"]);
@@ -112,7 +122,8 @@ public void LoadFromUxfJson()
112122
coarseAdjustEnabled = Convert.ToBoolean(sessionSettingsDict["CoarseAdjustment"]);
113123
choosableAngles = ParseFloatList((List<object>) sessionSettingsDict["ChoosableAngles"]);
114124

115-
attentionCueDuration = Convert.ToSingle(sessionSettingsDict["AttentionCueDuration"]);
125+
attentionCueStart = Convert.ToSingle(sessionSettingsDict["AttentionCueStartMs"]);
126+
attentionCueDuration = Convert.ToSingle(sessionSettingsDict["AttentionCueDurationMs"]);
116127
attentionCueDepth = Convert.ToSingle(sessionSettingsDict["AttentionCueDepth"]);
117128
attentionCueDistance = Convert.ToSingle(sessionSettingsDict["AttentionCueLengthDegrees"]);
118129
pulseFrequency = Convert.ToSingle(sessionSettingsDict["PulseFrequency"]);
@@ -126,6 +137,11 @@ public void LoadFromUxfJson()
126137

127138
fixationErrorTolerance = Convert.ToSingle(sessionSettingsDict["FixationErrorToleranceRadiusDegrees"]);
128139
buddyDotsEnabled = Convert.ToBoolean(sessionSettingsDict["EnableBuddyDots"]);
140+
141+
inputStart = Convert.ToSingle(sessionSettingsDict["InputStartMs"]);
142+
inputDuration = Convert.ToSingle(sessionSettingsDict["InputDurationMs"]);
143+
fixationBreakCheckStart = Convert.ToSingle(sessionSettingsDict["FixationBreakCheckStartMs"]);
144+
fixationBreakCheckDuration = Convert.ToSingle(sessionSettingsDict["FixationBreakCheckDurationMs"]);
129145
}
130146

131147
private static List<float> ParseFloatList(IEnumerable<object> list)

Assets/Scripts/Trial Manager/TrialManager.cs

Lines changed: 135 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections;
3+
using System.Data;
34
using DotStimulus;
45
using EyeTracker;
56
using ScriptableObjects;
@@ -126,7 +127,7 @@ public void EndTrial(Trial trial)
126127
Session.instance.CurrentBlock.CreateTrial();
127128
_trialCount++;
128129
}
129-
130+
130131
StartCoroutine(FeedBackRoutine());
131132
}
132133

@@ -272,63 +273,167 @@ private IEnumerator TrialRoutine(Trial trial)
272273
yield return WaitForFixation(sessionSettings.fixationTime,
273274
Mathf.Tan(sessionSettings.fixationErrorTolerance * Mathf.PI / 180 * sessionSettings.stimulusDepth));
274275

276+
var trialDuration = GetTrialDuration();
277+
278+
var outerStimulusRoutine = StartCoroutine(OuterStimulusRoutine());
279+
var innerStimulusRoutine = StartCoroutine(InnerStimulusRoutine());
280+
var inputRoutine = StartCoroutine(InputRoutine());
281+
var fixationBreakCheckRoutine = StartCoroutine(FixationBreakCheckRoutine());
282+
var attentionCueRoutine = AttentionCueRoutine();
283+
275284
if (sessionSettings.sessionType == SessionSettings.SessionType.Training)
285+
StartCoroutine(attentionCueRoutine);
286+
287+
var elapsedTime = 0.0f;
288+
while (!_isFixationBroken && elapsedTime < trialDuration / 1000)
276289
{
277-
attentionCue.SetActive(true);
278-
yield return new WaitForSeconds(sessionSettings.attentionCueDuration);
279-
attentionCue.SetActive(false);
290+
elapsedTime += Time.deltaTime;
291+
yield return null;
280292
}
293+
294+
StopCoroutine(outerStimulusRoutine);
295+
StopCoroutine(innerStimulusRoutine);
296+
StopCoroutine(inputRoutine);
297+
StopCoroutine(fixationBreakCheckRoutine);
298+
StopCoroutine(attentionCueRoutine);
299+
300+
outerStimulus.SetActive(false);
301+
innerStimulus.SetActive(false);
302+
stimulusSpacer.SetActive(false);
281303

282-
outerStimulus.SetActive(true);
283-
innerStimulus.SetActive(true);
284-
stimulusSpacer.SetActive(true);
285-
yield return CheckFixationBreakWithDelay(sessionSettings.innerStimulusDuration / 1000,
286-
Mathf.Tan(sessionSettings.fixationErrorTolerance * Mathf.PI / 180 * sessionSettings.stimulusDepth));
287-
288-
// End routine if fixation was broken
304+
// Start trial over if fixation was broken
289305
if (_isFixationBroken)
306+
{
307+
BeginTrial(trial);
290308
yield break;
309+
}
310+
311+
trial.End();
312+
}
291313

292-
laserManager.ActivateLaser();
293-
innerStimulus.SetActive(false);
314+
private float GetTrialDuration()
315+
{
316+
var endTimes = new[]
317+
{
318+
sessionSettings.outerStimulusStart + sessionSettings.outerStimulusDuration,
319+
sessionSettings.innerStimulusStart + sessionSettings.innerStimulusDuration,
320+
sessionSettings.fixationBreakCheckStart + sessionSettings.fixationBreakCheckDuration,
321+
sessionSettings.inputStart + sessionSettings.inputDuration
322+
};
294323

295-
// Inner stimulus renders one frame longer after it's disabled, so wait for next frame.
296-
yield return null;
297-
stimulusSpacer.SetActive(false);
298-
fixationDot.SetActive(false);
324+
return Mathf.Max(endTimes);
325+
}
326+
327+
private IEnumerator InputRoutine()
328+
{
329+
var elapsedTime = 0.0f;
330+
while (elapsedTime < sessionSettings.inputStart / 1000)
331+
{
332+
elapsedTime += Time.deltaTime;
333+
yield return null;
334+
}
299335
_waitingForInput = true;
336+
laserManager.ActivateLaser();
300337

301-
// Delta time is subtracted here to account for the extra frame we wait for a few lines above
302-
yield return new WaitForSeconds((sessionSettings.outerStimulusDuration - sessionSettings.innerStimulusDuration) / 1000 - Time.deltaTime);
303-
338+
elapsedTime = 0.0f;
339+
while (elapsedTime < sessionSettings.inputDuration / 1000)
340+
{
341+
elapsedTime += Time.deltaTime;
342+
yield return null;
343+
}
344+
laserManager.DeactivateBothLasers();
304345
_waitingForInput = false;
346+
}
347+
348+
private IEnumerator OuterStimulusRoutine()
349+
{
350+
var elapsedTime = 0.0f;
351+
while (elapsedTime < sessionSettings.outerStimulusStart / 1000)
352+
{
353+
elapsedTime += Time.deltaTime;
354+
yield return null;
355+
}
356+
357+
elapsedTime = 0.0f;
358+
outerStimulus.SetActive(true);
359+
while (elapsedTime < sessionSettings.outerStimulusDuration / 1000)
360+
{
361+
elapsedTime += Time.deltaTime;
362+
yield return null;
363+
}
305364
outerStimulus.SetActive(false);
306-
trial.End();
307365
}
366+
367+
private IEnumerator InnerStimulusRoutine()
368+
{
369+
var elapsedTime = 0.0f;
370+
while (elapsedTime < sessionSettings.innerStimulusStart / 1000)
371+
{
372+
elapsedTime += Time.deltaTime;
373+
yield return null;
374+
}
375+
innerStimulus.SetActive(true);
376+
stimulusSpacer.SetActive(true);
308377

309-
private IEnumerator CheckFixationBreakWithDelay(float fixationTime, float maxFixationError)
378+
elapsedTime = 0.0f;
379+
while (elapsedTime < sessionSettings.innerStimulusDuration / 1000)
380+
{
381+
elapsedTime += Time.deltaTime;
382+
yield return null;
383+
}
384+
innerStimulus.SetActive(false);
385+
yield return null;
386+
stimulusSpacer.SetActive(false);
387+
}
388+
389+
private IEnumerator AttentionCueRoutine()
390+
{
391+
var elapsedTime = 0.0f;
392+
while (elapsedTime < sessionSettings.attentionCueStart / 1000)
393+
{
394+
elapsedTime += Time.deltaTime;
395+
yield return null;
396+
}
397+
attentionCue.SetActive(true);
398+
399+
elapsedTime = 0.0f;
400+
while (elapsedTime < sessionSettings.attentionCueDuration / 1000)
401+
{
402+
elapsedTime += Time.deltaTime;
403+
yield return null;
404+
}
405+
attentionCue.SetActive(false);
406+
}
407+
408+
private IEnumerator FixationBreakCheckRoutine()
310409
{
311-
var time = 0.0f;
312-
while (time < fixationTime)
410+
var elapsedTime = 0.0f;
411+
while (elapsedTime < sessionSettings.attentionCueStart / 1000)
412+
{
413+
elapsedTime += Time.deltaTime;
414+
yield return null;
415+
}
416+
417+
elapsedTime = 0.0f;
418+
while (elapsedTime < sessionSettings.attentionCueDuration / 1000)
313419
{
314420
if (Physics.Raycast(cameraTransform.position,
315421
cameraTransform.TransformDirection(_eyeTracker.GetLocalGazeDirection()), out var hit))
316422
{
317423
Debug.DrawRay(cameraTransform.position,
318424
hit.distance * cameraTransform.TransformDirection(_eyeTracker.GetLocalGazeDirection()),
319425
Color.yellow);
320-
if ((hit.point - fixationDot.transform.position).magnitude > maxFixationError)
426+
var fixationError = Mathf.Tan(sessionSettings.fixationErrorTolerance * Mathf.PI / 180 *
427+
sessionSettings.stimulusDepth);
428+
if ((hit.point - fixationDot.transform.position).magnitude > fixationError)
321429
{
322-
StopCoroutine(_trialRoutine);
323430
innerStimulus.SetActive(false);
324431
outerStimulus.SetActive(false);
325432
_isFixationBroken = true;
326-
327-
BeginTrial(Session.instance.CurrentTrial);
328-
break;
433+
yield break;
329434
}
330435
}
331-
time += Time.deltaTime;
436+
elapsedTime += Time.deltaTime;
332437
yield return null;
333438
}
334439
}

Assets/StreamingAssets/TEMPLATE.json

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,33 @@
1010
"StimulusDotSizeArcMinutes": 14,
1111
"MinDotLifetimeSeconds": 0.2,
1212
"MaxDotLifetimeSeconds": 0.5,
13+
14+
"OuterStimulusStartMs": 1000,
1315
"OuterStimulusDurationMs": 5000,
1416
"OuterStimulusRadiusDegrees": 55,
1517
"OuterStimulusNoisePercentage": 100,
18+
19+
"InnerStimulusStartMs": 1000,
1620
"InnerStimulusDurationMs": 500,
1721
"InnerStimulusRadiusDegrees": 5,
1822
"InnerStimulusNoisePercentage": 50,
1923
"InnerStimulusSpawnRadius": 30,
2024

25+
"InputStartMs": 1500
26+
"InputDurationMs": 4500
27+
"FixationBreakCheckStartMs": 0
28+
"FixationBreakCheckDurationMs": 1500
29+
30+
"AttentionCueStartMs": 0
31+
"AttentionCueDurationMs": 1000,
32+
"AttentionCueDepth": 0.57,
33+
"AttentionCueLengthDegrees": 80,
34+
"PulseFrequency": 12,
35+
"SampleRate": 44100
36+
2137
"EnableBuddyDots": true,
2238

23-
"StimulusSpacingMeters": 0.001,
39+
"StimulusSpacingMeters": 0.05,
2440

2541
"StimulusDepthMeters": 0.57,
2642

@@ -37,11 +53,5 @@
3753
"CoherenceStaircase": [0, 40, 80, 120, 160, 200, 240, 280, 320, 338],
3854
"StaircaseIncreaseThreshold": 3,
3955
"StaircaseDecreaseThreshold": 1,
40-
41-
"AttentionCueDuration": 1,
42-
"AttentionCueDepth": 0.57,
43-
"AttentionCueLengthDegrees": 80,
44-
"PulseFrequency": 12,
45-
"SampleRate": 44100
4656
}
4757
}

ProjectSettings/ProjectSettings.asset

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ PlayerSettings:
127127
bundleVersion: 1.0
128128
preloadedAssets:
129129
- {fileID: 6405742922248523384, guid: efde690a735af1f4a89b7bfd2c31a41a, type: 2}
130+
- {fileID: 0}
130131
metroInputSource: 0
131132
wsaTransparentSwapchain: 0
132133
m_HolographicPauseOnTrackingLoss: 1

0 commit comments

Comments
 (0)