//***********************************************************
// 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");
}
}