博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何使用眼动仪在UGUI中模拟按钮相关事件
阅读量:6622 次
发布时间:2019-06-25

本文共 4881 字,大约阅读时间需要 16 分钟。

最近在开发一款使用Tobii眼动仪控制的游戏,然后界面上的按钮都是使用UGUI,在前期用鼠标控制表现良好,但是最终需要用眼动仪控制按钮。而Unity默认的按钮是不支持眼动仪点击按钮的,并且Tobii眼动仪提供的API也只能拿到眼睛看到的坐标。

最后经过调查,发现Unity是通过StandaloneInputModule发送鼠标点击事件的,所以我利用已有的StandaloneInputModule源码重新写了一个GazeInputModle,最后实现了这个需求。目前眼动仪只要捕捉到眼光在按钮上停留两秒就会触发鼠标点击事件。

以下是主要的代码:

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;using Tobii.Gaming;public class GazeInputModule : {    private GameObject currentOverGameObject;    private PointerEventData pointerEventData;    private float durationTime;    protected void HandlePointerExitAndEnter2(PointerEventData currentPointerData, GameObject newEnterTarget)    {        // if we have no target / pointerEnter has been deleted         // just send exit events to anything we are tracking         // then exit         if (newEnterTarget == null || currentPointerData.pointerEnter == null)        {            for (var i = 0; i < currentPointerData.hovered.Count; ++i)                ExecuteEvents.Execute(currentPointerData.hovered[i], currentPointerData, ExecuteEvents.pointerExitHandler);            currentPointerData.hovered.Clear();            if (newEnterTarget == null)            {                currentPointerData.pointerEnter = newEnterTarget;                return;            }        }        // if we have not changed hover target         if (currentPointerData.pointerEnter == newEnterTarget && newEnterTarget)            return;        GameObject commonRoot = FindCommonRoot(currentPointerData.pointerEnter, newEnterTarget);        // and we already an entered object from last time         if (currentPointerData.pointerEnter != null)        {            // send exit handler call to all elements in the chain             // until we reach the new target, or null!             Transform t = currentPointerData.pointerEnter.transform;            while (t != null)            {                // if we reach the common root break out!                 if (commonRoot != null && commonRoot.transform == t)                    break;                ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerExitHandler);                currentPointerData.hovered.Remove(t.gameObject);                t = t.parent;            }        }        // now issue the enter call up to but not including the common root         currentPointerData.pointerEnter = newEnterTarget;        if (newEnterTarget != null)        {            Transform t = newEnterTarget.transform;            while (t != null && t.gameObject != commonRoot)            {                ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerEnterHandler);                currentPointerData.hovered.Add(t.gameObject);                t = t.parent;            }        }    }    public void ProcessPoint()    {        List
results = new List
(); EventSystem.current.RaycastAll(pointerEventData, results); // Debug.Log("mousePosition=" + Input.mousePosition + ", count=" + results.Count); RaycastResult raycastResult = FindFirstRaycast(results); HandlePointerExitAndEnter2(pointerEventData, raycastResult.gameObject); if (raycastResult.gameObject == pointerEventData.pointerEnter && raycastResult.gameObject != null) { durationTime += Time.deltaTime; } else { durationTime = 0; } if (durationTime > Configuration.GetFloat("InputMode.GazeClickDurationTime", 2)) //看一个对象两秒触发点击事件,可以配置 { Debug.Log("Send Click event, name=" + raycastResult.gameObject.name); ExecuteEvents.Execute(raycastResult.gameObject, pointerEventData, ExecuteEvents.pointerClickHandler); durationTime = 0; } } public void Update() { if (pointerEventData == null) { pointerEventData = new PointerEventData(gameObject.GetComponent
()); } if (Configuration.GetBool("InputMode.TestMode", false) == false) //如果是测试模式则使用鼠标模拟眼动仪,便于测试 { GazePoint gazePoint = TobiiAPI.GetGazePoint(); if (gazePoint.IsValid) { pointerEventData.position = gazePoint.Screen; ProcessPoint(); } } else { pointerEventData.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y); ProcessPoint(); } } public override void Process() { //do nothing to avoid mouse event cover ours } }

  主要继承了StandaloneInputModule,然后在Update里检测点是否停留在按钮上。

  用的时候需要把这个脚本挂载在EventSystem对象上,同时需要disable对象上的StandaloneInputModule,否则在选中按钮时每个Module都会发送PointerEnter事件。

  目前只实现了PointerEnter、PointerExit、PointerClick事件,如果有需要可以增加其他事件。

  代码中Configuration相关方法是自己写一个配置类,用的时候需要修改下这些代码。

转载于:https://www.cnblogs.com/liu102401/p/10241435.html

你可能感兴趣的文章
webservice测试工具
查看>>
[Oracle]如何获得出现故障时,客户端的详细连接信息
查看>>
spring-boot-starter-actuator(健康监控)配置和使用
查看>>
BabeLua常见问题
查看>>
刚装上最新node,npm install报这个错误!求ndoe大神解答!!!
查看>>
iOS设置拍照retake和use按钮为中文简体
查看>>
Elasticsearch 基础概念知识
查看>>
Additional information: 对 COM 组件的调用返回了错误 HRESULT E_FAIL
查看>>
python -- ajax数组传递和后台接收
查看>>
Spring之AOP二
查看>>
压缩解压缩
查看>>
SPI协议及其工作原理浅析【转】
查看>>
ab和jmeter进行GET/POST压力测试的使用心得和比较
查看>>
Porting .Net RSA xml keys to Java
查看>>
用户命令切换-命令su
查看>>
检测 nginx.conf 是否配置正确
查看>>
[ReactVR] Add Lighting Using Light Components in React VR
查看>>
String hashCode 方法为什么选择数字31作为乘子
查看>>
最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和...
查看>>
测试妹子的呐喊:为什么总是收不到推送?
查看>>