private void StartTask() { RecordData.Log("Starting task " + CurrentTaskIndex + " (" + (numTasksFinished + 1) + " / " + currentSequence.Length + ")"); RecordData.CurrentRecord.taskStartTime = Time.realtimeSinceStartup; tasks[CurrentTaskIndex].gameObject.SetActive(true); tasks[CurrentTaskIndex].StartTask(); }
private void NextSequence() { // Load new sequences in case old ones are all used up, which should not be a problem when using a file with all possible permutations. if (sequences == null || sequences.GetLength(0) == 0) { LoadSequences(); } // Remember previous task in case we don't want to repeat it. int lastTask = (currentSequence == null) ? -1 : CurrentTaskIndex; int sequenceIndex; do { // Pick sequence and remove it from list of available sequences. sequenceIndex = Random.Range(0, sequences.GetLength(0)); currentSequence = sequences[sequenceIndex]; } while (randomizeTasks && preventDirectRepetition && lastTask == currentSequence[0]); Assert.AreEqual(currentSequence.Length, tasks.Length); // This removes the used element, but it's quite ugly... var tmp = new List <int[]>(sequences); tmp.RemoveAt(sequenceIndex); sequences = tmp.ToArray(); RecordData.Log("New task sequence is " + string.Join(", ", new List <int>(currentSequence).ConvertAll(i => i.ToString()).ToArray())); }
private void StartTutorials() { numTutorialsFinished = 0; runningTutorial = true; RecordData.Log("Starting tutorial 0 (1/" + tutorials.Count + ") with tutorial condition instead of condition " + FindObjectOfType <ConditionSwitcher>().CurrentConditionIndex + "."); FindObjectOfType <ConditionSwitcher>().tutorialCondition.viewMode = "default"; tutorials[0].gameObject.SetActive(true); tutorials[0].StartTask(); }
public void NextCondition() { // Last condition was reached -> experiment is over! if (numConditionsFinished == conditions.Length - 1) { FindObjectOfType <TaskDisplay>().CurrentDescriptionID = "finished"; RecordData.Log("All conditions completed. The experiment is over."); } else { ++numConditionsFinished; RecordData.Log("Starting condition " + CurrentConditionIndex + " (" + (numConditionsFinished + 1) + " / " + sequence.Length + ")"); } }
private void Update() { FindObjectOfType <TaskDisplay>().SetLanguage(displayLanguage); if (!waitingForKeypress) { if (Input.GetKeyDown(KeyCode.X)) { RecordData.CurrentRecord.skipped = !RecordData.CurrentRecord.skipped; RecordData.CurrentRecord.skippedAfterSeconds = RecordData.CurrentRecord.skipped ? Time.realtimeSinceStartup - RecordData.CurrentRecord.taskStartTime : 0f; RecordData.Log("Skip status of current task was marked as " + RecordData.CurrentRecord.skipped); } return; } if (runningTutorial) { // After start, tutorials need to be run by pressing Space or Return. FindObjectOfType <TaskDisplay>().CurrentDescriptionID = "waitTutorial"; if (Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.Return)) { waitingForKeypress = false; StartTutorials(); } } // Finished tutorials; waiting for experiment or repeating tutorials. else { FindObjectOfType <TaskDisplay>().CurrentDescriptionID = "waitExperiment"; if (Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.Return)) { waitingForKeypress = false; NextSequence(); numTasksFinished = 0; StartTask(); } else if (!skipTutorials && tutorials.Count > 0 && numTasksFinished == 0 && // So that when pausing between experiment conditions, tutorials cannot be started. (Input.GetKeyDown(KeyCode.Backspace) || Input.GetKeyDown(KeyCode.R))) { runningTutorial = true; } } }
private void Awake() { var json = conditionsJson.text; var config = JsonUtility.FromJson <ConditionConfiguration>(json); conditions = config.conditions; if (sequence == null || sequence.Length != conditions.Length) { Debug.LogWarning(conditionsJson.name + " defines " + conditions.Length + " conditions, but set sequence is invalid. Using default sequence."); sequence = new int[conditions.Length]; for (int i = 0; i < sequence.Length; ++i) { sequence[i] = i; } } RecordData.Log("Condition sequence is " + string.Join(", ", new List <int>(sequence).ConvertAll(i => i.ToString()).ToArray()) + ", starting with condition " + CurrentConditionIndex + " (" + (numConditionsFinished + 1) + " / " + sequence.Length + ")" + "."); }
protected virtual void LogSubtask() { // FIXME: Not really the best approach for getting a distinct name. RecordData.Log("Starting subtask " + gameObject.name + "."); }
private void Update() { if (!IsStarted) { return; } var hand = laser.GetHand(); if (acceptAction.GetStateDown(hand.handType) || Input.GetMouseButtonDown(0)) { if (!laser.IsFrozen) { laser.IsFrozen = true; FindObjectOfType <TaskDisplay>().CurrentDescriptionID = "pointingConfirm"; startConfirmationTime = Time.realtimeSinceStartup; } else { float endTime = Time.realtimeSinceStartup; RecordData.CurrentRecord.pointingTime = endTime - startTime; RecordData.CurrentRecord.confirmationTime = endTime - startConfirmationTime; RecordData.CurrentRecord.positionAtConfirmation = Camera.main.transform.position; RecordData.CurrentRecord.viewAtConfirmation = Camera.main.transform.rotation.eulerAngles; RecordData.CurrentRecord.rayPosition = laser.Ray.origin; RecordData.CurrentRecord.rayDirection = laser.Ray.direction; var hits = Physics.RaycastAll(laser.Ray, 200f); foreach (var hit in hits) { // Go through all hits. If hit is room AND room is target, record related data. // Second condition should always be true since we disabled all room colliders except for the target room. if (hit.collider.GetComponent <SelectRoom>() != null && hit.collider.GetComponent <SelectRoom>().IsTargetRoom) { RecordData.CurrentRecord.hitRoom = true; RecordData.CurrentRecord.hitLocation = hit.point - hit.transform.position; break; } } var roomBounds = targetRoom.GetComponent <Renderer>().bounds; // Determine pointing error towards room center. Vector3 correctDir = (roomBounds.center - laser.Ray.origin).normalized; Vector3 actualDir = laser.Ray.direction.normalized; // Positive horizontal angle means error to the right of center (from user POV), negative means left. Vector2 correctProjHoriz = new Vector2(correctDir.z, correctDir.x); Vector2 actualProjHoriz = new Vector2(actualDir.z, actualDir.x); float horizAngle = Vector2.SignedAngle(correctProjHoriz, actualProjHoriz); // Positive horizontal angle means error over center (from user POV), negative means under. Vector2 correctProjVert = new Vector2(correctDir.y, correctDir.z); Vector2 actualProjVert = new Vector2(actualDir.y, actualDir.z); float vertAngle = Vector2.SignedAngle(correctProjVert, actualProjVert); RecordData.CurrentRecord.horizOffsetDeg = horizAngle; RecordData.CurrentRecord.vertOffsetDeg = vertAngle; RecordData.Log("Pointing error in degrees: " + horizAngle + ", " + vertAngle); // Do next trial. FindObjectOfType <TaskSwitcher>().NextTask(); } } else if ((backAction.GetStateDown(hand.handType) || Input.GetKeyDown(KeyCode.Backspace)) && laser.IsFrozen) { laser.IsFrozen = false; FindObjectOfType <TaskDisplay>().CurrentDescriptionID = "pointingNormal"; ++RecordData.CurrentRecord.numCorrections; } }
public void NextTask() { if (runningTutorial) { tutorials[numTutorialsFinished].StopTask(); tutorials[numTutorialsFinished].gameObject.SetActive(false); ++numTutorialsFinished; if (numTutorialsFinished == tutorials.Count) { runningTutorial = false; waitingForKeypress = true; return; } RecordData.Log("Starting tutorial " + numTutorialsFinished + " (" + (numTutorialsFinished + 1) + "/" + tutorials.Count + ") with tutorial condition instead of condition " + FindObjectOfType <ConditionSwitcher>().CurrentConditionIndex + "."); if (numTutorialsFinished % 2 != 0) { FindObjectOfType <ConditionSwitcher>().tutorialCondition.viewMode = "flat"; } else { FindObjectOfType <ConditionSwitcher>().tutorialCondition.viewMode = "default"; } tutorials[CurrentTaskIndex].gameObject.SetActive(true); tutorials[CurrentTaskIndex].StartTask(); return; } // ------ // The following will only be executed when all tutorials are finished. // ------ tasks[CurrentTaskIndex].StopTask(); tasks[CurrentTaskIndex].gameObject.SetActive(false); RecordData.CurrentRecord.taskEndTime = Time.realtimeSinceStartup; RecordData.CurrentRecord.taskDuration = RecordData.CurrentRecord.taskEndTime - RecordData.CurrentRecord.taskStartTime; SaveData(); if (numTasksFinished == tasks.Length - 1) { // Switch conditions. var condSwitcher = FindObjectOfType <ConditionSwitcher>(); int lastCondition = condSwitcher.CurrentConditionIndex; condSwitcher.NextCondition(); // If conditions were not switched, it means all conditions were completed. // In that case, don't start the next task (there is none) and just keep the // task display and wait for user to take off HMD. if (lastCondition == condSwitcher.CurrentConditionIndex) { return; } waitingForKeypress = true; } else { ++numTasksFinished; StartTask(); } }