//*********************************************************** // Filename: DataManager.cs // Author: Niclas // Last changes: 08 August 2018 // Content: The DataManager which collects, formats and exports experiment data //*********************************************************** using System; using System.Collections; using System.IO; using UnityEngine; //TODO: rewrite class to complement the new StudyDataParser /// /// This class collects data from Events, formats them and exports them into a .csv file /// public class DataManager : MonoBehaviour { // Holds all data collected thus far private readonly ArrayList expData = new ArrayList(); // Number of teleports while a specific target is active private int currentTeleports = 0; // Holds a reference to the GameManager for future use private GameManager gManager; // Id of the currently active target, doubles as target count, starts with 0 private int currentTargetId; // Coordinates of the currently active target private Vector3 currentTargetPos; // Rotation of the currently active target private Vector3 currentTargetRot; // Distance between the current target and the one before private float currentTargetDist = 0; // Unique user id in case none gets set private string userId = Guid.NewGuid().ToString(); // Delimiter between items, used to format to .csv private const string Del = ","; // Use this for initialization void Start() { gManager = GetComponentInParent(); // Register listerners to their event TargetSpawnedEvent.RegisterListener(OnTargetSpawned); TargetReachedEvent.RegisterListener(OnTargetReached); TeleportEvent.RegisterListener(OnTeleport); ExperimentEndEvent.RegisterListener(OnExperimentEnd); } private void OnDestroy() { // Unregister listeners from their event TargetSpawnedEvent.UnregisterListener(OnTargetSpawned); TargetReachedEvent.UnregisterListener(OnTargetReached); TeleportEvent.UnregisterListener(OnTeleport); ExperimentEndEvent.UnregisterListener(OnExperimentEnd); } /// /// Listener for TargetSpawnedEvent, extracts information about the current target to variables /// /// The Event, contains its information private void OnTargetSpawned(TargetSpawnedEvent tse) { currentTargetId = tse.targetId; // Distance to spawned target, 0 if startTarget currentTargetDist = Vector3.Distance(currentTargetPos, tse.targetTransform.position); currentTargetPos = tse.targetTransform.position; currentTargetRot = tse.targetTransform.rotation.eulerAngles; } /// /// Listener for TeleportEvent, adds a row with data about the teleport in expData /// /// The Event, contains its information private void OnTeleport(TeleportEvent te) { if (currentTargetId == 0) return; currentTeleports++; string row = currentTargetId + Del + currentTeleports + Del + currentTargetPos.x + Del + currentTargetPos.z + Del + currentTargetRot.y + Del + te.startUserPosition.x + Del + te.startUserPosition.z + Del + te.startUserRotation.y + Del + te.startTeleportTime + Del + te.endUserPosition.x + Del + te.endUserPosition.z + Del + te.endUserRotation.y + Del + te.endTeleportTime + Del + (te.endTeleportTime - te.startTeleportTime) + Del + 0 + Del + Mathf.Sqrt(Mathf.Pow(te.endUserPosition.x - currentTargetPos.x, 2) + Mathf.Pow(te.endUserPosition.z - currentTargetPos.z, 2)) + Del + (te.endUserRotation.y - currentTargetRot.y + 180) % 360 + Del + currentTargetDist; expData.Add(row); } /// /// Listener for TargetReachedEvent, adds row to expData with data about the reached target and player, ends a teleport chain /// /// The Event, contains its information private void OnTargetReached(TargetReachedEvent tre) { Debug.Log("Received Target information, id: " + tre.targetId + " time: " + tre.time); string row = tre.targetId + Del + (-1) + Del + tre.targetTransform.position.x + Del + tre.targetTransform.position.z + Del + tre.targetTransform.rotation.eulerAngles.y + Del + 0 + Del + 0 + Del + 0 + Del + 0 + Del + tre.playerTransform.position.x + Del + tre.playerTransform.position.z + Del + tre.playerTransform.rotation.eulerAngles.y + Del + 0 + Del + 0 + Del + 0 + Del + tre.time + Del + Mathf.Sqrt(Mathf.Pow(tre.playerTransform.position.x - tre.targetTransform.position.x, 2) + Mathf.Pow(tre.playerTransform.position.z - tre.targetTransform.position.z, 2)) + Del + (tre.targetTransform.rotation.eulerAngles.y - tre.playerTransform.rotation.eulerAngles.y - 180) % 360 + Del + currentTargetDist; expData.Add(row); currentTeleports = 0; } /// /// Listener for ExperimentEndEvent, sets userID and invokes WriteToFile() to write the .csv file. /// Invokes with one second delay to give the last Events time to finish processing /// /// The Event, contains its information, however none is required at the moment private void OnExperimentEnd(ExperimentEndEvent e) { if (gManager.testSubjectId != "") { userId = gManager.testSubjectId; } // Waiting for last TargetReachedEvent to process Invoke("WriteToFile", 1); } /// /// Creates a new .csv file with userID, movement method and date as name. /// Writes first row with names of the columns, afterwards each string in expData as new row /// private void WriteToFile() { string filepath = string.Format(@"{0}-{1}-{2:yyyy-MM-dd_HH-mm-ss}.csv", GetComponentInParent().movementMethod, userId, DateTime.Now); using (StreamWriter writer = new StreamWriter(new FileStream(filepath, FileMode.Create, FileAccess.Write))) { writer.WriteLine("TargetID, TeleportID, TargetPositionX, TargetPositionZ, TargetRotation, PlayerLastPosX, PlayerLastPosZ, PlayerLastRot, TelStartTime, PlayerPosX, PlayerPosZ, PlayerRotation, TelEndTime, TelDistance, TelTime, TimeNeeded, OffsetPos, OffsetRot, DistTargetToTarget"); foreach (string row in expData) { writer.WriteLine(row); } } Debug.Log("Data written"); } }