using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using Random=System.Random; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Reflection; [StructLayout(LayoutKind.Sequential, Pack = 0)] public struct TimingSetting { public float TrialStart; public float TargetOnset; public float TargetOnsetDev; public float Go; public float MoveMax; public float HoldTime; }; public class GameController : MonoBehaviour { public string TimingSettingFile = @"\Tables\Timings.csv"; public TriggerBoundary DestTriggerBoundary; public SpriteRenderer PlayerSprite; public GameObject[] Goals; public GameObject Base; public bool TrialResult {get; private set;} private TimingSetting mTimingSetting; private string[] TableHeader; private float[] TableData; private ChangeColour[] GoalsChangeColour; private int ExperimentTrial = 0; private float Timer = 0f; private Random GoalSetter = new System.Random(300); private Random OnsetDeviator = new System.Random(100); private TriggerBoundary BaseTriggerBoundary; private float OnsetDev = 0; private int GoalSet = 0; private const int NumGoals = 2; // If exceeds this time including hold time, then the player loses private const float FailTime = 4.0f; // Player must keep their sprite in the goal for this long in order to complete the task private const float HoldTime = 1.0f; // Time the player must spend in the base to be considered end of trial private const float BaseHoldTime = 0.2f; private bool TrialState = false; // 0: inactive trial, 1: active trial private GameObject Goal; void Awake() { GoalsChangeColour = new ChangeColour[Goals.Length]; } // Start is called before the first frame update void Start() { int length = Marshal.SizeOf (typeof(TimingSetting)); TableHeader = GetTableHeader(TimingSettingFile); TableData = GetTableFloat(TimingSettingFile); mTimingSetting = FloatArrayToStruct(TableData,mTimingSetting); BaseTriggerBoundary = Base.GetComponent<TriggerBoundary>(); PlayerSprite.enabled = true; for (int i = 0; i < Goals.Length; i++) { GoalsChangeColour[i] = Goals[i].GetComponent<ChangeColour>(); } /* GoalSet = GoalSetter.Next(NumGoals); */ /* OnsetDev = OnsetDeviator.Next(mTimingSetting.TargetOnsetDev); */ Debug.Log("GoalSet: " + GoalSet); } // Update is called once per frame void Update() { float dt = Time.deltaTime; // measure in ms Timer += dt*1000; // Timer started ticking? Then the trial has started if (Timer > 0) { TrialState = true; } if (Timer > mTimingSetting.TrialStart) { bool[] states = CheckGoalStates(GoalsChangeColour); bool flag = false; for (int i = 0; i < NumGoals; i++) { if (states[i]) { flag = true; } } if (!flag) { GoalSet = GoalSetter.Next(NumGoals); GoalsChangeColour[GoalSet].GoalState = 1; OnsetDev = OnsetDeviator.Next((int)mTimingSetting.TargetOnsetDev*2) - mTimingSetting.TargetOnsetDev; Debug.Log("OnsetDev: " + OnsetDev); } } if (Timer > (mTimingSetting.TrialStart + mTimingSetting.TargetOnset + OnsetDev) ) { GoalsChangeColour[GoalSet].GoalState = 2; } // If the player is in the target start counting DestTriggerBoundary = Goals[GoalSet].GetComponent<TriggerBoundary>(); // If the player hasn't achieved the hold time in the allotted time // they fail if (Timer > FailTime) { TrialResult = false; TrialState = false; } else if (Timer <= FailTime && DestTriggerBoundary.GetStayTime() >= HoldTime) { TrialResult = true; TrialState = false; } if (!TrialState) { // Don't begin the new trial until the user has returned to the // base position if ( DestTriggerBoundary.GetStayTime() >= BaseHoldTime ) { Debug.Log("BaseStayTime: " + DestTriggerBoundary.GetStayTime()); EndTrialSequence(); } } } private string[] GetTableHeader(string filename) { string[] header; string table_file = @".\Assets\Scripts"; table_file = table_file + filename; using (var reader = new StreamReader(table_file)) { var line = reader.ReadLine(); header = line.Split(','); } return header; } private float[] GetTableFloat(string filename) { float[] data = new float[6]; string table_file = @".\Assets\Scripts"; table_file = table_file + filename; using (var reader = new StreamReader(table_file)) { reader.ReadLine(); var line = reader.ReadLine(); string []values = line.Split(','); for (int i = 0; i < values.Length; i++) { data[i] = Single.Parse(values[i]); } } return data; } private TimingSetting FloatArrayToStruct(float[] floatarray, TimingSetting structureObj) { int length = floatarray.Length; IntPtr ptr = Marshal.AllocHGlobal (length); Marshal.Copy (floatarray, 0, ptr, length); structureObj = (TimingSetting)Marshal.PtrToStructure (ptr, structureObj.GetType()); Marshal.FreeHGlobal (ptr); return structureObj; } private bool[] CheckGoalStates(ChangeColour[] GoalColours) { bool[] states = new bool[GoalColours.Length]; for (int i = 0 ; i < GoalColours.Length; i++) { if (GoalColours[i].GoalState > 0) { states[i] = true; } else { states[i] = false; } } return states; } private void EndTrialSequence() { ExperimentTrial++; GoalsChangeColour[GoalSet].GoalState = 0; Timer = 0; } // Check for any fail conditions here // Incl: Taking too long to finish, leaving early (disqualification) private bool FailConditions() { return true; } }