StudyDataParser.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. //***********************************************************
  2. // Filename: StudyDataParser.cs
  3. // Author: Marco Fendrich, Moritz Kolvenbach
  4. // Last changes: Thursday, 9th of August 2018
  5. // Content: A parser to read the data from a given study; containers to implement a structure for the data from the study; further processes the data and writes it into a csv file
  6. //***********************************************************
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Linq;
  11. using UnityEngine;
  12. using System.Runtime.CompilerServices;
  13. using Debug = UnityEngine.Debug;
  14. /// <summary>
  15. /// A class containing multiple container classes that represent a structure for the recorded data, and further process the raw data.
  16. /// Reads a given file of study data and and sorts it into the data structure. Writes the processed data into a new file.
  17. /// </summary>
  18. public class StudyDataParser : MonoBehaviour
  19. {
  20. //Information about the current study parameters
  21. private const int NumberOfConditions = 5;
  22. private const int SampleSize = 50; // Amount of trials for each condition
  23. private const int NumberOfSubjects = 20;
  24. private const int NumberResultValues = 8; // Amount of values being processed from the raw data
  25. // Delimiter for writing and reading the csv file
  26. private string del = ",";
  27. // Use this for initialization
  28. void Start()
  29. {
  30. List<StudySubjectSample> parsedSubjectList = ScanFiles();
  31. ProcessData(parsedSubjectList);
  32. WriteToFile(parsedSubjectList);
  33. }
  34. /// <summary>
  35. /// Writes the final processed list of data into a csv file. Grouped after study subjects
  36. /// </summary>
  37. /// <param name="parsedSubjectList"> A list containing all the study subjects and their respective processed data</param>
  38. void WriteToFile(List<StudySubjectSample> parsedSubjectList)
  39. {
  40. // The string for the name of the csv file
  41. var filepath = string.Format(@"{0:yyyy-MM-dd_HH-mm-ss}-analysis.csv", System.DateTime.Now);
  42. // start writing the csv file
  43. using (StreamWriter writer = new StreamWriter(new FileStream(filepath, FileMode.Create, FileAccess.Write)))
  44. {
  45. // write first row with two empty fields (being filled later only)
  46. string subjectIDs = " " + del + " " + del;
  47. for (int i = 0; i < NumberOfSubjects; i++)
  48. {
  49. subjectIDs = subjectIDs + parsedSubjectList[i].SubjectIdentifier() + del;
  50. }
  51. writer.WriteLine(subjectIDs);
  52. // loop for different values to be calculated
  53. for (int i = 1; i <= NumberResultValues; i++)
  54. {
  55. string resultValue;
  56. switch (i)
  57. {
  58. case 1:
  59. resultValue = "distanceOffset";
  60. break;
  61. case 2:
  62. resultValue = "distanceOffsetAfterTeleport";
  63. break;
  64. case 3:
  65. resultValue = "rotationOffset";
  66. break;
  67. case 4:
  68. resultValue = "rotationOffsetAfterTeleport";
  69. break;
  70. case 5:
  71. resultValue = "timeUntilConfirmation";
  72. break;
  73. case 6:
  74. resultValue = "timeForTeleports";
  75. break;
  76. case 7:
  77. resultValue = "timeForCorrection";
  78. break;
  79. case 8:
  80. resultValue = "teleportsNeeded";
  81. break;
  82. default:
  83. resultValue = "somethingWentIncrediblyWrong";
  84. break;
  85. }
  86. // loop for teleportConditions
  87. for (int j = 0; j < NumberOfConditions; j++)
  88. {
  89. string condition;
  90. switch (j)
  91. {
  92. case 0:
  93. condition = "linear";
  94. break;
  95. case 1:
  96. condition = "parabolic";
  97. break;
  98. case 2:
  99. condition = "angleSelect";
  100. break;
  101. case 3:
  102. condition = "curve";
  103. break;
  104. case 4:
  105. condition = "distorted";
  106. break;
  107. default:
  108. condition = "dafuqHappendHere?!";
  109. break;
  110. }
  111. string row = resultValue + del + condition + del;
  112. // write all calculated average values for each study subject
  113. foreach (StudySubjectSample studySubject in parsedSubjectList)
  114. {
  115. switch (i)
  116. {
  117. case 1:
  118. row = row + studySubject.AvgDistanceOffset[j] + del;
  119. break;
  120. case 2:
  121. row = row + studySubject.AvgDistanceOffsetAfterTeleport[j] + del;
  122. break;
  123. case 3:
  124. row = row + studySubject.AvgRotationOffset[j] + del;
  125. break;
  126. case 4:
  127. row = row + studySubject.AvgRotationOffsetAfterTeleport[j] + del;
  128. break;
  129. case 5:
  130. row = row + studySubject.AvgTimeUntilConfirmation[j] + del;
  131. break;
  132. case 6:
  133. row = row + studySubject.AvgTimeForTeleports[j] + del;
  134. break;
  135. case 7:
  136. row = row + studySubject.AvgTimeForCorrection[j] + del;
  137. break;
  138. case 8:
  139. row = row + studySubject.AvgTeleportsNeeded[j] + del;
  140. break;
  141. }
  142. }
  143. // write specific values
  144. writer.WriteLine(row);
  145. }
  146. }
  147. }
  148. }
  149. /// <summary>
  150. /// Averages the required values over the whole study sample
  151. /// </summary>
  152. /// <param name="parsedSubjectList"> A list containing all the study subjects for a given study</param>
  153. private void ProcessData(List<StudySubjectSample> parsedSubjectList)
  154. {
  155. //*** all arrays per teleportation [linear, parabolic, angleSelect, curve, distorted] ***//
  156. float[] avgDistanceOffset = new float[NumberOfConditions]; // average offset after confirmation
  157. float[] avgDistanceOffsetAfterTeleport = new float[NumberOfConditions]; // average offset after last teleportation
  158. float[] avgRotationOffset = new float[NumberOfConditions]; // average rotation after confirmation
  159. float[] avgRotationOffsetAfterTeleport = new float[NumberOfConditions]; // average rotation after last teleportation
  160. float[] avgTimeUntilConfirmation = new float[NumberOfConditions]; // average time needed per target from first teleport to confirmation
  161. float[] avgTimeForTeleports = new float[NumberOfConditions]; // average time needed for all teleportation between two targets
  162. float[] avgTimeForCorrection = new float[NumberOfConditions]; // average time needed for correcting one's position after last teleport until confirmation
  163. float[] avgTeleportsNeeded = new float[NumberOfConditions]; // average number of teleportations needed to reach target
  164. // average the values for each teleportCondition separately
  165. for (int i = 0; i < NumberOfConditions; i++)
  166. {
  167. // add up the values from each ubject for each condition
  168. foreach (StudySubjectSample studySubject in parsedSubjectList)
  169. {
  170. avgDistanceOffset[i] += studySubject.AvgDistanceOffset[i];
  171. avgDistanceOffsetAfterTeleport[i] += studySubject.AvgDistanceOffsetAfterTeleport[i];
  172. avgRotationOffset[i] += studySubject.AvgRotationOffset[i];
  173. avgRotationOffsetAfterTeleport[i] += studySubject.AvgRotationOffsetAfterTeleport[i];
  174. avgTimeUntilConfirmation[i] += studySubject.AvgTimeUntilConfirmation[i];
  175. avgTimeForTeleports[i] += studySubject.AvgTimeForTeleports[i];
  176. avgTimeForCorrection[i] += studySubject.AvgTimeForCorrection[i];
  177. avgTeleportsNeeded[i] += studySubject.AvgTeleportsNeeded[i];
  178. }
  179. // average the values per condition
  180. avgDistanceOffset[i] = avgDistanceOffset[i] / NumberOfSubjects;
  181. avgDistanceOffsetAfterTeleport[i] = avgDistanceOffsetAfterTeleport[i] / NumberOfSubjects;
  182. avgRotationOffset[i] = avgRotationOffset[i] / NumberOfSubjects;
  183. avgRotationOffsetAfterTeleport[i] = avgRotationOffsetAfterTeleport[i] / NumberOfSubjects;
  184. avgTimeUntilConfirmation[i] = avgTimeUntilConfirmation[i] / NumberOfSubjects;
  185. avgTimeForTeleports[i] = avgTimeForTeleports[i] / NumberOfSubjects;
  186. avgTimeForCorrection[i] = avgTimeForCorrection[i] / NumberOfSubjects;
  187. avgTeleportsNeeded[i] = avgTeleportsNeeded[i] / NumberOfSubjects;
  188. }
  189. }
  190. /// <summary>
  191. /// Iterates through all folders of a given directory and uses <see cref="ReadFile(string)"/> to read each file. Creates a list with all confirmed targets per condition per subject.
  192. /// </summary>
  193. /// <returns> A list of all the studySubjects and their respective targtes per condition</returns>
  194. private List<StudySubjectSample> ScanFiles()
  195. {
  196. // A list containing one entry for each studySubject
  197. List<StudySubjectSample> returnList = new List<StudySubjectSample>();
  198. // Iterate through the different folders
  199. for (int i = 1; i <= NumberOfSubjects; i++)
  200. {
  201. // path to the directory
  202. string path = ("Assets/UserStudy/VP" + i);
  203. // create new lists for each condition
  204. List<TargetDataSample> linearTeleport = new List<TargetDataSample>();
  205. List<TargetDataSample> parabolicTeleport = new List<TargetDataSample>();
  206. List<TargetDataSample> angleSelectTeleport = new List<TargetDataSample>();
  207. List<TargetDataSample> curveTeleport = new List<TargetDataSample>();
  208. List<TargetDataSample> distortedTeleport = new List<TargetDataSample>();
  209. // ID for the current studySubject
  210. string subjectIdentifier = "userNotFound";
  211. // Get the filePath for each separate csv file of data
  212. string[] filePathList = Directory.GetFiles(path);
  213. // Read all the files from the current directory into the lists
  214. foreach (string filePath in filePathList)
  215. {
  216. if (Path.GetExtension(filePath) == ".csv")
  217. switch (Path.GetFileName(filePath).Substring(0, 4))
  218. {
  219. case "line":
  220. linearTeleport = ReadFile(filePath);
  221. subjectIdentifier = Path.GetFileName(filePath).Substring(15, 4);
  222. break;
  223. case "para":
  224. parabolicTeleport = ReadFile(filePath);
  225. break;
  226. case "turn":
  227. angleSelectTeleport = ReadFile(filePath);
  228. break;
  229. case "curv":
  230. curveTeleport = ReadFile(filePath);
  231. break;
  232. case "dist":
  233. distortedTeleport = ReadFile(filePath);
  234. break;
  235. }
  236. }
  237. // Write all the condition lists for the current studySubject into a new StudySubjectSample object and add the subject to the return list
  238. returnList.Add(new StudySubjectSample(subjectIdentifier, linearTeleport, parabolicTeleport, angleSelectTeleport, curveTeleport, distortedTeleport));
  239. }
  240. return returnList;
  241. }
  242. /// <summary>
  243. /// Reads a given csv file of studyData and sorts the data into the container classes <see cref="TargetDataSample"/> <see cref="TeleportDataSample"/>
  244. /// </summary>
  245. /// <param name="path"> The path to the file that's supposed to be read</param>
  246. /// <returns> A list of TargetDataSample each containing a list of TeleportDataSample </returns>
  247. private static List<TargetDataSample> ReadFile(string path)
  248. {
  249. // raw input from the csv file
  250. string fileData = System.IO.File.ReadAllText(path);
  251. // raw input splitted
  252. string[] temp = fileData.Split("\n"[0]);
  253. // skip first two rows (header and initial target) and last row (empty)
  254. string[] rows = new string[temp.Length - 3];
  255. for (int i = 0; i < temp.Length - 3; i++)
  256. {
  257. rows[i] = temp[i + 2];
  258. }
  259. List<TargetDataSample> parsedTargetList = new List<TargetDataSample>();
  260. List<TeleportDataSample> currentTeleportList = new List<TeleportDataSample>();
  261. bool newTarget = false;
  262. // get time until first target was triggered
  263. string[] temporaryContent = (temp[1].Trim()).Split(","[0]);
  264. float timeSinceLastTarget = float.Parse(temporaryContent[15]);
  265. // iterate through each row of the rawData
  266. foreach (string row in rows)
  267. {
  268. string[] content = (row.Trim()).Split(","[0]);
  269. // skip last empty row
  270. if (content.Length >= 2)
  271. {
  272. int typeIdentificator;
  273. if (int.TryParse(content[1], out typeIdentificator))
  274. {
  275. // if content is of type target
  276. if (typeIdentificator == -1)
  277. {
  278. newTarget = true;
  279. timeSinceLastTarget += float.Parse(content[15]);
  280. // create a new TargetDataSample from the data
  281. TargetDataSample target = new TargetDataSample(
  282. int.Parse(content[0]),
  283. new Vector2(float.Parse(content[2]), float.Parse(content[3])),
  284. float.Parse(content[4]),
  285. new Vector2(float.Parse(content[9]), float.Parse(content[10])),
  286. float.Parse(content[11]),
  287. timeSinceLastTarget,
  288. currentTeleportList
  289. );
  290. parsedTargetList.Add(target);
  291. }
  292. // If content is of type teleport
  293. else
  294. {
  295. if (newTarget)
  296. {
  297. // Create new list of teleports for the next TargetDataSample
  298. currentTeleportList = new List<TeleportDataSample>();
  299. }
  300. // Create new TeleportDataSample from the data and add it to the list of teleports needed for the current TargetDataSample
  301. TeleportDataSample teleport = new TeleportDataSample(
  302. int.Parse(content[1]),
  303. new Vector2(float.Parse(content[5]), float.Parse(content[6])),
  304. new Vector2(float.Parse(content[9]), float.Parse(content[10])),
  305. float.Parse(content[7]),
  306. float.Parse(content[11]),
  307. float.Parse(content[8]),
  308. float.Parse(content[12])
  309. );
  310. currentTeleportList.Add(teleport);
  311. newTarget = false;
  312. }
  313. }
  314. }
  315. }
  316. return parsedTargetList;
  317. }
  318. /// <summary>
  319. /// A container class representing the studyData for one studySubject in a given study. Infers required values from raw inputData and averages them over all trials of the subject
  320. /// </summary>
  321. public class StudySubjectSample
  322. {
  323. // values being given on construction
  324. private readonly string subjectIdentifier;
  325. private readonly List<TargetDataSample>[] teleportDataSamples = new List<TargetDataSample>[NumberOfConditions]; // the TeleportDataSample between this target and the last one
  326. private readonly List<TargetDataSample> linearTeleport;
  327. private readonly List<TargetDataSample> parabolicTeleport;
  328. private readonly List<TargetDataSample> angleSelectTeleport;
  329. private readonly List<TargetDataSample> curveTeleport;
  330. private readonly List<TargetDataSample> distortedTeleport;
  331. // values inferred from above data as average; see TargetDataSample for details
  332. //*** all arrays per teleportation [linear, parabolic, angleSelect, curve, distorted] ***//
  333. private readonly float[] avgDistanceOffset = new float[NumberOfConditions];
  334. private readonly float[] avgDistanceOffsetAfterTeleport = new float[NumberOfConditions];
  335. private readonly float[] avgRotationOffset = new float[NumberOfConditions];
  336. private readonly float[] avgRotationOffsetAfterTeleport = new float[NumberOfConditions];
  337. private readonly float[] avgTimeUntilConfirmation = new float[NumberOfConditions];
  338. private readonly float[] avgTimeForTeleports = new float[NumberOfConditions];
  339. private readonly float[] avgTimeForCorrection = new float[NumberOfConditions];
  340. private readonly float[] avgTeleportsNeeded = new float[NumberOfConditions];
  341. public StudySubjectSample(string subjectIdentifier, List<TargetDataSample> linearTeleport,
  342. List<TargetDataSample> parabolicTeleport, List<TargetDataSample> angleSelectTeleport,
  343. List<TargetDataSample> curveTeleport, List<TargetDataSample> distortedTeleport)
  344. {
  345. this.subjectIdentifier = subjectIdentifier;
  346. this.linearTeleport = linearTeleport;
  347. this.parabolicTeleport = parabolicTeleport;
  348. this.angleSelectTeleport = angleSelectTeleport;
  349. this.curveTeleport = curveTeleport;
  350. this.distortedTeleport = distortedTeleport;
  351. teleportDataSamples[0] = linearTeleport;
  352. teleportDataSamples[1] = parabolicTeleport;
  353. teleportDataSamples[2] = angleSelectTeleport;
  354. teleportDataSamples[3] = curveTeleport;
  355. teleportDataSamples[4] = distortedTeleport;
  356. // check if all data samples have the same size and throw exception if not
  357. if (new[] { parabolicTeleport.Count, angleSelectTeleport.Count, curveTeleport.Count, distortedTeleport.Count }
  358. .All(trialSize => trialSize != linearTeleport.Count)) throw new System.FormatException();
  359. // average the values for each condition
  360. for (int j = 0; j < teleportDataSamples.Length; j++)
  361. {
  362. for (int i = 0; i < SampleSize; i++)
  363. {
  364. // sum up single values
  365. avgDistanceOffset[j] += (teleportDataSamples[j])[i].DistanceOffset;
  366. avgDistanceOffsetAfterTeleport[j] += (teleportDataSamples[j])[i].DistanceOffsetAfterTeleport;
  367. avgRotationOffset[j] += (teleportDataSamples[j])[i].RotationOffset;
  368. avgRotationOffsetAfterTeleport[j] += (teleportDataSamples[j])[i].RotationOffsetAfterTeleport;
  369. avgTimeUntilConfirmation[j] += (teleportDataSamples[j])[i].TimeUntilConfirmation;
  370. avgTimeForTeleports[j] += (teleportDataSamples[j])[i].TimeForTeleports;
  371. avgTimeForCorrection[j] += (teleportDataSamples[j])[i].TimeForCorrection;
  372. avgTeleportsNeeded[j] += (teleportDataSamples[j])[i].TeleportsNeeded;
  373. }
  374. // average single values
  375. avgDistanceOffset[j] = avgDistanceOffset[j] / SampleSize;
  376. avgDistanceOffsetAfterTeleport[j] = avgDistanceOffsetAfterTeleport[j] / SampleSize;
  377. avgRotationOffset[j] = avgRotationOffset[j] / SampleSize;
  378. avgRotationOffsetAfterTeleport[j] = avgRotationOffsetAfterTeleport[j] / SampleSize;
  379. avgTimeUntilConfirmation[j] = avgTimeUntilConfirmation[j] / SampleSize;
  380. avgTimeForTeleports[j] = avgTimeForTeleports[j] / SampleSize;
  381. avgTimeForCorrection[j] = avgTimeForCorrection[j] / SampleSize;
  382. avgTeleportsNeeded[j] = avgTeleportsNeeded[j] / SampleSize;
  383. }
  384. }
  385. //*** getter
  386. public string SubjectIdentifier() { return subjectIdentifier; }
  387. public List<TargetDataSample> LinearTeleport() { return linearTeleport; }
  388. public List<TargetDataSample> ParabolicTeleport() { return parabolicTeleport; }
  389. public List<TargetDataSample> AngleSelectTeleport() { return angleSelectTeleport; }
  390. public List<TargetDataSample> CurveTeleport() { return curveTeleport; }
  391. public List<TargetDataSample> DistortedTeleport() { return distortedTeleport; }
  392. public List<TargetDataSample>[] AllTeleports() { return teleportDataSamples; }
  393. public float[] AvgDistanceOffset { get { return avgDistanceOffset; } }
  394. public float[] AvgDistanceOffsetAfterTeleport { get { return avgDistanceOffsetAfterTeleport; } }
  395. public float[] AvgRotationOffset { get { return avgRotationOffset; } }
  396. public float[] AvgRotationOffsetAfterTeleport { get { return avgRotationOffsetAfterTeleport; } }
  397. public float[] AvgTimeUntilConfirmation { get { return avgTimeUntilConfirmation; } }
  398. public float[] AvgTimeForTeleports { get { return avgTimeForTeleports; } }
  399. public float[] AvgTimeForCorrection { get { return avgTimeForCorrection; } }
  400. public float[] AvgTeleportsNeeded { get { return avgTeleportsNeeded; } }
  401. }
  402. /// <summary>
  403. /// A container class representing one confirmed target in a given trial of a Study. Contains a list of <see cref="TeleportDataSample"/> with information about all the teleports used between confirmation
  404. /// of this target and the last one
  405. /// </summary>
  406. public class TargetDataSample
  407. {
  408. // Values being given on construction
  409. private readonly int targetIdentifier; // target number since trial start
  410. private readonly Vector2 targetPosition; // position of this target
  411. private readonly float targetRotation; // rotation to zero world of this target
  412. private readonly Vector2 playerPositionOnTrigger; // position of player when triggering
  413. private readonly float playerRotationOnTrigger; // rotation of player to zero world when triggering
  414. private readonly float timeTriggered; // absolute time since trial start when triggering
  415. private readonly List<TeleportDataSample> teleports; // list of teleports needed since last target
  416. // Values inferred from above data
  417. private readonly float distanceOffset; // distance from player to target on confirmation
  418. private readonly float distanceOffsetAfterTeleport; // distance from player to target after last teleportation
  419. private readonly float rotationOffset; // rotation from player to target on confirmation
  420. private readonly float rotationOffsetAfterTeleport; // rotation from player to target on confirmation after last teleportation
  421. private readonly float timeUntilConfirmation; // time from first teleport initiation to confirmation of target
  422. private readonly float timeForTeleports; // time needed for all teleports (first teleport initiation until completion of last teleport)
  423. private readonly float timeForCorrection; // time needed for correcting one's position after last teleport
  424. private readonly int teleportsNeeded; // number of teleports needed to get to target
  425. public TargetDataSample(int targetIdentifier, Vector2 targetPosition, float targetRotation, Vector2 playerPositionOnTrigger, float playerRotationOnTrigger, float timeTriggered, List<TeleportDataSample> teleports)
  426. {
  427. this.targetIdentifier = targetIdentifier;
  428. this.targetPosition = targetPosition;
  429. this.targetRotation = targetRotation;
  430. this.playerPositionOnTrigger = playerPositionOnTrigger;
  431. this.playerRotationOnTrigger = playerRotationOnTrigger;
  432. this.timeTriggered = timeTriggered;
  433. this.teleports = teleports;
  434. // Infer required values from rawData
  435. distanceOffset = Mathf.Sqrt(Mathf.Pow(playerPositionOnTrigger.x - targetPosition.x, 2) + Mathf.Pow(playerPositionOnTrigger.y - targetPosition.y, 2));
  436. distanceOffsetAfterTeleport = Mathf.Sqrt(Mathf.Pow(teleports[teleports.Count - 1].PlayerEndPosition.x - targetPosition.x, 2) + Mathf.Pow(teleports[teleports.Count - 1].PlayerEndPosition.y - targetPosition.y, 2));
  437. float tempRot = (playerRotationOnTrigger - targetRotation + 180) % 360;
  438. rotationOffset = Mathf.Abs(tempRot >= 180 ? tempRot - 360 : tempRot);
  439. tempRot = (teleports[teleports.Count - 1].PlayerEndRotation - targetRotation + 180) % 360;
  440. rotationOffsetAfterTeleport = Mathf.Abs(tempRot >= 180 ? tempRot - 360 : tempRot);
  441. timeUntilConfirmation = timeTriggered - teleports[0].TeleportStartTime;
  442. timeForTeleports = teleports[teleports.Count - 1].TeleportEndTime - teleports[0].TeleportStartTime;
  443. timeForCorrection = timeTriggered - teleports[teleports.Count - 1].TeleportEndTime;
  444. teleportsNeeded = teleports.Count;
  445. }
  446. //*** getter
  447. public int TargetIdentifier { get { return targetIdentifier; } }
  448. public Vector2 TargetPosition { get { return targetPosition; } }
  449. public float TargetRotation { get { return targetRotation; } }
  450. public Vector2 PlayerPositionOnTrigger { get { return playerPositionOnTrigger; } }
  451. public float PlayerRotationOnTrigger { get { return playerRotationOnTrigger; } }
  452. public float TimeTriggered { get { return timeTriggered; } }
  453. public List<TeleportDataSample> Teleports { get { return teleports; } }
  454. public float DistanceOffset { get { return distanceOffset; } }
  455. public float DistanceOffsetAfterTeleport { get { return distanceOffsetAfterTeleport; } }
  456. public float RotationOffset { get { return rotationOffset; } }
  457. public float RotationOffsetAfterTeleport { get { return rotationOffsetAfterTeleport; } }
  458. public float TimeUntilConfirmation { get { return timeUntilConfirmation; } }
  459. public float TimeForTeleports { get { return timeForTeleports; } }
  460. public float TimeForCorrection { get { return timeForCorrection; } }
  461. public int TeleportsNeeded { get { return teleportsNeeded; } }
  462. }
  463. /// <summary>
  464. /// A container class representing a single teleport event.
  465. /// </summary>
  466. public class TeleportDataSample
  467. {
  468. private readonly int teleportIdentifier; // teleports since last target triggered
  469. private readonly Vector2 playerStartPosition; // player position when pressing down teleport button
  470. private readonly Vector2 playerEndPosition; // player position after teleport
  471. private readonly float playerStartRotation; // player rotation when pressing down teleport button
  472. private readonly float playerEndRotation; // player rotation after teleport
  473. private readonly float teleportStartTime; // absolute time since trial start when player pressed down teleport button
  474. private readonly float teleportEndTime; // absolute time since trial start of teleport
  475. public TeleportDataSample(int teleportIdentifier, Vector2 playerStartPosition, Vector2 playerEndPosition, float playerStartRotation, float playerEndRotation, float teleportStartTime, float teleportEndTime)
  476. {
  477. this.teleportIdentifier = teleportIdentifier;
  478. this.playerStartPosition = playerStartPosition;
  479. this.playerEndPosition = playerEndPosition;
  480. this.playerStartRotation = playerStartRotation;
  481. this.playerEndRotation = playerEndRotation;
  482. this.teleportStartTime = teleportStartTime;
  483. this.teleportEndTime = teleportEndTime;
  484. }
  485. //*** getter
  486. public int TeleportIdentifier { get { return teleportIdentifier; } }
  487. public Vector2 PlayerStartPosition { get { return playerStartPosition; } }
  488. public Vector2 PlayerEndPosition { get { return playerEndPosition; } }
  489. public float PlayerStartRotation { get { return playerStartRotation; } }
  490. public float PlayerEndRotation { get { return playerEndRotation; } }
  491. public float TeleportStartTime { get { return teleportStartTime; } }
  492. public float TeleportEndTime { get { return teleportEndTime; } }
  493. }
  494. }