Files
2026-09-15 16:20:39 +02:00

226 lines
6.0 KiB
C#

using Edia;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UXF;
using System.Collections.Generic;
public class TaskNavigation : XBlock {
/*
* Xblock order of execution:
* 1. OnBlockStart
* 2. OnTrialStart
* 3. first step method
* 4. InBetweenSteps
* 5. next step method
* 6. ...
* 7. OnTrialEnd
* 8. OnBlockEnd
* 9. OnBlockOutro
*/
[SerializeField] private VideoClipPicker videoPicker;
[SerializeField] private Material skybox360Video;
private int _currentVideoIndex;
[SerializeField] private ScreenInVR messageCanvas;
[SerializeField] private Button doneButton;
[SerializeField] private TextMeshProUGUI timerText;
[Header("Cheat Controls")]
[SerializeField] private GameObject cheatPanel;
[SerializeField] private List<Button> videoButtons;
[SerializeField] private Button playResumeButton;
private float _timer;
private bool _isNavigating;
private void Awake() {
/*
Each trial exists out of a sequence of steps.
Each step is a standalone part of the experiment task.
I.e. Show a message to the user, show a fixation cross, wait for user input, etc.
In order to use the steps, they need to be defined in the trial sequence.
A common approach within a trial is as follows:
*/
RenderSettings.skybox = null;
DynamicGI.UpdateEnvironment();
AddToTrialSequence(Setup); // #1 Set up environment / Generate Stimuli / etc
AddToTrialSequence(ShowVideoReference);
AddToTrialSequence(PlayVideoReference);
AddToTrialSequence(FinishedPlayingVideo);
AddToTrialSequence(Cleanup);
}
private void Update()
{
if (_isNavigating)
{
_timer += Time.deltaTime;
timerText.text = _timer.ToString("F2");
}
}
#region TASK STEPS
/*
The framework provides a set of tools to make it easier to implement the task.
For example:
* XRManager.Instance.xxxxx => All things XR related
* Experiment.instance.xxxxx => All things related to the progress of the experiment, logging data, etc
See documentation for more details.
*/
// -------------------------------------------------------------------------------------------
// #1
/// <summary>Prepare and show stimuli</summary>
[ContextMenu("Setup")]
void Setup() {
/*
* A step always ends with either a 'PROCEED' and/or 'WAITONPROCEED'
*/
Camera.main.clearFlags = CameraClearFlags.Skybox;
_timer = 0;
_isNavigating = false;
timerText.text = "0.0";
messageCanvas.Show(true);
for (int i = 0; i < videoButtons.Count; i++)
{
int index = i; // Capture the current value of i
videoButtons[i].onClick.AddListener(() => ForceChangeVideoReference(index));
}
playResumeButton.onClick.AddListener(PauseResumeVideo);
doneButton.onClick.AddListener(NavigationDone);
XRManager.Instance.EnableAllInteraction(true);
Experiment.Instance.WaitOnProceed();
}
private void PauseResumeVideo()
{
videoPicker.TogglePause();
Experiment.Instance.StoreMarker("VideoPaused" + _timer.ToString("F2"));
}
private void NavigationDone()
{
_isNavigating = false;
Experiment.Instance.AddToTrialResults("Index", "Video_" + _currentVideoIndex);
Experiment.Instance.AddToTrialResults("NavigationTime", _timer.ToString("F2"));
Experiment.Instance.WaitOnProceed();
}
private void ShowVideoReference() {
var videoIndex = Session.instance.CurrentTrial.settings.GetInt("videoId");
_currentVideoIndex = videoIndex;
// Show 360 skybox
RenderSettings.skybox = skybox360Video;
DynamicGI.UpdateEnvironment();
videoPicker.SelectClip(videoIndex);
videoPicker.StartCountdown(); // start on the first frame; press Proceed to Play
// Add results and relevant data to trial results
Experiment.Instance.AddToTrialResults("Navigating Video ID", _currentVideoIndex.ToString());
Experiment.Instance.WaitOnProceed();
}
void PlayVideoReference()
{
_isNavigating = true;
// Resume video
videoPicker.Resume();
Experiment.Instance.StoreMarker("Playing video " + _currentVideoIndex);
Experiment.Instance.WaitOnProceed();
}
void FinishedPlayingVideo()
{
_isNavigating = false;
Experiment.Instance.StoreMarker("Finished video " + _currentVideoIndex);
Experiment.Instance.WaitOnProceed();
}
private void Cleanup()
{
doneButton.onClick.RemoveAllListeners();
messageCanvas.Show(false);
Camera.main.clearFlags = CameraClearFlags.SolidColor;
foreach (var button in videoButtons)
{
button.onClick.RemoveAllListeners();
}
cheatPanel.SetActive(false);
RenderSettings.skybox = null;
DynamicGI.UpdateEnvironment();
Experiment.Instance.WaitOnProceed();
}
private void ForceChangeVideoReference(int videoIndex)
{
_currentVideoIndex = videoIndex;
videoPicker.SelectClip(_currentVideoIndex);
videoPicker.StartCountdown();
videoPicker.Resume();
Experiment.Instance.StoreMarker("Forced Change to Video " + _currentVideoIndex);
}
#endregion
#region STATEMACHINE OVERRIDES
public override void OnBlockStart() {
/*
* Shows message to the user if there is a value defined in the configs with the key "_intro"
*/
}
public override void OnStartTrial() {
}
public override void OnEndTrial() {
}
public override void OnBetweenSteps() {
}
public override void OnBlockEnd()
{
/*
* Shows message to the user if there is a value defined in the configs with the key "_outro"
*/
}
public override void OnBlockOutro() {
}
#endregion
}