using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace NextMind.Devices { /// /// This component displays the reliablity of the 's contacts. /// /// /// It will display contact values as colors on the component of the children objects. To map a contact's to its value, children must have specific names. /// The following table shows the relation between electrodes names and their id: /// /// /// Name /// Id /// /// PO80 /// PO41 /// /// /// O22 /// /// /// POZ3 /// /// /// O14 /// /// /// OZ5 /// /// /// PO36 /// /// /// PO77 /// /// /// If you intend to get the contacts values by yourself, you may want to use the method with these ids as parameter. /// public class ContactsVisualization : MonoBehaviour { /// /// The color to apply on a electrode in a neutral state (e.g. not on the user's head). /// [SerializeField] private Color neutralColor = Color.grey; /// /// The gradient coloring the electrdodes from bad contact to perfect contact. /// [SerializeField] private Gradient colorGradient; /// /// The list of electrodes names. /// private List electrodesNames = new List { "PO8", "PO4", "O2", "POZ", "O1", "OZ", "PO3", "PO7" }; private List electrodesImage = new List(); /// /// The device currently connected. /// private Device connectedDevice; /// /// The last batch of contact values /// private Dictionary contactValues = new Dictionary(); /// /// One lerp coroutine for each contact. /// private Coroutine[] colorLerpCoroutines; /// /// Are we currently updating the contacts? /// private bool updatingContacts = false; private void OnEnable() { contactValues = new Dictionary(); electrodesImage = new List(); // Get the electrodes Image components from their GameObject name. for (int i = 0; i < electrodesNames.Count; i++) { contactValues.Add(electrodesNames[i], 0); foreach (Transform t in transform) { if (t.name == electrodesNames[i]) { electrodesImage.Add(t.GetComponent()); break; } } } colorLerpCoroutines = new Coroutine[electrodesImage.Count]; // Refresh contact 25 times per second. StartUpdateContactValues(25f); } private void OnDisable() { updatingContacts = false; } private void StartUpdateContactValues(float rate) { if (rate == 0) { updatingContacts = false; } else { updatingContacts = true; StartCoroutine(RefreshContactValues(1f / rate)); } } private IEnumerator RefreshContactValues(float rate) { while (updatingContacts) { if (connectedDevice != null && connectedDevice.IsConnected) { for (int i = 0; i < electrodesNames.Count; i++) { float contactValue = connectedDevice.GetContact((uint)i) / 100f; // If the contact value changed. if (!Mathf.Approximately(contactValues[electrodesNames[i]], contactValue)) { contactValues[electrodesNames[i]] = contactValue; if (colorLerpCoroutines[i] == null) { Color targetColor; float value = contactValues[electrodesNames[i]]; if (value < 0 || value > 1) { targetColor = neutralColor; } else { targetColor = colorGradient.Evaluate(value); } electrodesImage[i].color = targetColor; } } } } else { // Retrieve the first connected device. var connectedDevices = NeuroManager.Instance.ConnectedDevices; for (int i = 0; i < connectedDevices.Count; i++) { Device device = connectedDevices[i]; if (device.IsConnected) { connectedDevice = device; break; } } } yield return new WaitForSeconds(rate); } } } }