Emotiv
2. Emotiv Epoc - softvér na vývoj
2.1. Quiz
Vytvorenie panelu – v Hierarchy vytvoríme cez pravé tlačidlo UI -> Panel. Toto bude naša obrazovka kde postupne pridáme tlačidlá a texty.

Pridanie textov – Do objektu Panel pridáme Text – TextMeshPro cez UI -> Text – TextMeshPro (ak vyskočí okno pre import TMP tak len potvrdíme). Po vytvorení ho v Hierarchy premenujeme na Question.

Objekt vieme presúvať po scéne cez Move Tool a meniť veľkosť cez Rect Tool. Presunieme teda text do hornej časti Panelu.

V Inspectore upravíme text a vycentrujeme.

Takýmto štýlom pridáme ešte dva texty do horných rohov Panela, ktorým nastavíme text na 0. V Hierarchy si texty pomenujeme Score a Timer.

Pridanie tlačidiel - Pridáme do panela 3 tlačidlá cez UI -> Button – TextMeshPro. Pomenujeme ich Start, Answer1, Answer2.

Tlačidlo Start presunieme do dolnej časti. Tlačidlo Answer1 presunieme na ľavú stranu a Answer2 na pravú stranu. Nastavíme im Width na 200 a Height na 100.

Každé tlačidlo obsahuje objekt Text. Text tlačidla Start nastavíme na Start.


Vytvorenie scriptu – v Assets vytvoríme C# Script, ktorý pomenujeme Quiz a otvoríme.

Na začiatok scriptu pridáme knižnice:
- je samotný Emotiv plugin
- je UI podpora tlačidiel
- knižnica pre Text - TMPro
using EmotivUnityPlugin; using UnityEngine.UI; using TMPro;
Do class Quiz pridáme premenné pre prihlásenie sa do Emotiv
Cortex API (potrebné pre prácu s Emotiv zariadením)
private string _clientId = ""; private string _clientSecret = ""; private string _appName = "emotiv"; private string _appVersion = "3.3.0"; EmotivUnityItf _eItf = EmotivUnityItf.Instance; DataStreamManager _dsManager = DataStreamManager.Instance; float _timerDataUpdate = 0; const float TIME_UPDATE_DATA = 1f; bool _isDataBufferUsing = false; // default subscribed data will not saved to Data buffer
Pridáme taktiež premenné pre Quiz
// Premenné na nastavenie Textov public TMP_Text QuestionText; public TMP_Text Answer1Text; public TMP_Text Answer2Text; public TMP_Text ScoreText; public TMP_Text TimerText; private bool _DataSubscribed = false; private bool _QuizEnabled = false; private int _AnswerBtn = -1; // cislo tlacidla so spravnym vysledkom private int _Score = 0; private int _SelAnswer = -1; // cislo zvoleneho tlacidla private float _Timer; // Maximalne cislo pri generovani prikladov private const int _MaxMathNum = 10;
Pridáme funckiu SetQnA,
ktorá bude generovať príklady
void SetQnA() { int num1 = Random.Range(1, _MaxMathNum + 1); int num2 = Random.Range(1, _MaxMathNum + 1); QuestionText.text = "Kolko je " + num1 + " + " + num2 + "?"; int answer = num1 + num2; // Nahodne nastavenie nespravneho vysledku (bud +1 alebo -1) int incorrect = (Random.Range(1, 3) == 1) ? 1 : -1; // Nahodny vyber tlacidla so spravnym vysledkom if ((_AnswerBtn = Random.Range(1, 2 + 1)) == 1) { num1 = answer; num2 = answer + incorrect; } else { num1 = answer + incorrect; num2 = answer; } Answer1Text.text = num1.ToString(); Answer2Text.text = num2.ToString(); }
Pridáme funckiu AnswerButtonSetup,
ktorá bude nastavovať farbu tlačidlám
void AnswerButtonSetup(int button, Color color) { if (button == 1) { GameObject.Find("Answer1").GetComponent<Button>().GetComponent<Image>().color = color; } else if (button == 2) { GameObject.Find("Answer2").GetComponent<Button>().GetComponent<Image>().color = color; } }
Pridáme funckiu ResetQnA, ktorá bude resetovať premenné do defaultu
void ResetQnA() { _AnswerBtn = -1; _Timer = 8; _SelAnswer = -1; QuestionText.text = "Toto je otázka?"; Answer2Text.text = "Odpoved"; Answer1Text.text = "Odpoved"; ScoreText.text = _Score.ToString(); TimerText.text = _Timer.ToString(); AnswerButtonSetup(1, Color.white); AnswerButtonSetup(2, Color.white); }
Pridáme funkciu StartQnA, ktorá spustí celý Quiz
void StartQnA() { ResetQnA(); SetQnA(); }
Do funkcie Start pridáme ResetQnA a inicializujeme Emotiv
void Start() { ResetQnA(); _eItf.Init(_clientId, _clientSecret, _appName, _appVersion, _isDataBufferUsing); _eItf.Start(); // Start Emotiv // Hook pre ziskanie dat o mimike _dsManager.FacialExpReceived += OnFacialExpReceived; }
Do funkcie Update pridáme Timer pre Quiz a kontrolu ci je spustená detekcia mimiky tváre
void Update() { // Ak je Quiz zapnuty, spusti sa odpocet, ktory na konci skontroluje odpovede if (_QuizEnabled) { _Timer -= Time.deltaTime; if (Mathf.FloorToInt(_Timer % 60) >= 0) { AnswerButtonSetup(_SelAnswer, Color.yellow); if (Mathf.FloorToInt(_Timer % 60) == 0) { // Kontrola odpovedi a nastavenie Score if (_AnswerBtn == _SelAnswer) { _Score++; AnswerButtonSetup(_AnswerBtn, Color.green); } else { _Score--; AnswerButtonSetup(_AnswerBtn, Color.green); if (_SelAnswer != -1) AnswerButtonSetup(_SelAnswer, Color.red); } _Timer = -1; } } else if (_Timer <= -2.0) StartQnA(); } // Nastavenie textov na obrazovke QuestionText.text = QuestionText.text; Answer2Text.text = Answer2Text.text; Answer1Text.text = Answer1Text.text; ScoreText.text = _Score.ToString(); // Text s casom bude vzdy mat hodnotu >= 0 TimerText.text = (_Timer >= 0) ? Mathf.FloorToInt(_Timer % 60).ToString() : "0"; // Spusti kontrolu Subscribe (spustenie detekcie v nasom pripade mimiky tvare) // raz za 1f (DEC: 31) aby sa nespustala kontrola kazdy frame _timerDataUpdate += Time.deltaTime; if (_timerDataUpdate < TIME_UPDATE_DATA) return; _timerDataUpdate -= TIME_UPDATE_DATA; if (_eItf.IsAuthorizedOK && _eItf.IsSessionCreated && !_DataSubscribed) { SetupSubscribe(); } }
Pridáme funkciu, ktorá sa vyvolá vždy keď sa získajú nové dáta o mimike
private void OnFacialExpReceived(object sender, FacEventArgs data) { // Ak uz je nejaka odpoved zvolená alebo nie je Quiz zapnuty -> return if (_SelAnswer != -1 || !_QuizEnabled) return; // Zmurknutie Lavym alebo Pravym okom if (data.EyeAct == "winkL") _SelAnswer = 1; else if (data.EyeAct == "winkR") _SelAnswer = 2; }
Pridáme funckiu onCreateSessionBtnClick, ktorá sa vyvolá pri stlačení tlačidla Start
public void onCreateSessionBtnClick() { // Pri vyuzivani Emotiv je potrebne vytvorit Session if (!_eItf.IsSessionCreated) { _eItf.CreateSessionWithHeadset(null); } // Ak klikneme na Start, zmeni sa nazov tlacidla na Stop a spusti sa Quiz // Ak klikneme na Stop, zmeni sa nazov tlacidla na Start a vypne sa Quiz if (!_QuizEnabled) { _QuizEnabled = true; StartQnA(); GameObject.Find("Start").GetComponent<Button>().GetComponentInChildren<TMP_Text>().text = "Stop"; } else { _QuizEnabled = false; _Score = 0; ResetQnA(); GameObject.Find("Start").GetComponent<Button>().GetComponentInChildren<TMP_Text>().text = "Start"; } }
Pridanie funckie OnApplicationQuit, ktorá sa vyvolá keď vypneme hru.
void OnApplicationQuit() { Debug.Log("Application ending after " + Time.time + " seconds"); _eItf.Stop(); }
Pridanie funckie SetupSubscribe
private void SetupSubscribe() { // Spustenie Subscribe pre face (mimiku) if (_eItf.IsSessionCreated) { List<string> _streams = new List<string> {}; _streams.Add("fac"); _eItf.DataSubLog = ""; // clear data subscribing log _eItf.SubscribeData(_streams); _DataSubscribed = true; } else { UnityEngine.Debug.LogError("Must create a session first before subscribing data."); } }
Script uložíme a presunieme ho z Assets do objektu Canvas

Z Hierarchy presunieme všetky texty na pravú stranu do scriptu podľa názvov. Question do Question Text, Text (TMP) pod tlačidlom Answer1 do Answer1 Text ...


Klikneme na objekt (tlačidlo) Start v Hierarchy a na pravej strane pod Button pridáme On Click (cet +) a to políčka na objekt presunieme z Hierarchy objekt Canvas. Do políčka No Function nastavíme funckiu onCreateSessionBtnClick. Teraz vždy po stlačení tlačidla Start/Stop sa zavolá daná funkcia.


Hru už len otestujeme (pred spustením je potrebné mať pripojené zariadenie a nastavené cez Emotiv Launcher).