您的位置:首页 > 产品设计 > UI/UE

UICamera的触摸事件

2015-06-11 20:49 459 查看
转载自:  http://dsqiu.iteye.com/blog/1971866

记得刚开始用NGUI的时候,就有心思要去琢磨下UICamera,那个时候NGUI还是2.6的版本,现在已经到了3.0.3f,NGUI更新真的很强劲, 当然改动也挺大的,特性也越来越多了。之前本来研究下UICamera最后还是放弃了,因为UICamera的代码太复杂了,很凌乱,也就放下去了,这几天重新翻看了下,发现UICamera的可读性太强了,代码的组织逻辑很强,完全可以当做文本来从上到下来阅读,所以才会有这篇文章。

       UICamera做了很多有优化,新增了一些特性,之前可能觉得NGUI只是做一个工具,现在越来越完美了,少废话,下面把看到的亮点呈上。

ClickNotification
/// <summary>
/// Whether the touch event will be sending out the OnClick notification at the end.
/// </summary>

public enum ClickNotification
{
None,
Always,
BasedOnDelta,
}


      ClickNotification定义了OnClick响应的条件,后面也定义了ClickNotification变量 public ClickNotification clickNotification = ClickNotification.Always;

       ClickNotification.None: 不响应OnClick事件

       ClickNotification.Always:总是响应OnClick事件

       ClickNotification.BaseOnDelta:依据移动的delta的距离判断是否响应OnClick函数,如果移动距离大于float click  = isMouse ? mouseClickThreshold : touchClickThreshold;则不响应OnClick事件

下面这部分代码是当响应了OnDrag事件就把currentTouch.clickNotification = ClickNotification.None;就不在会响应OnClick事件了。
bool isDisabled = (currentTouch.clickNotification == ClickNotification.None);
Notify(currentTouch.dragged, "OnDrag", currentTouch.delta);
isDragging = false;

if (isDisabled)
{
// If the notification status has already been disabled, keep it as such
currentTouch.clickNotification = ClickNotification.None;
}
else if (currentTouch.clickNotification == ClickNotification.BasedOnDelta && click < mag)
{
// We've dragged far enough to cancel the click
currentTouch.clickNotification = ClickNotification.None;
}


 然后再执行OnClick和OnDoubleClick事件先判断条件currentTouch.clickNotification != ClickNotification.None 是否成立:
// If the touch should consider clicks, send out an OnClick notification
if (currentTouch.clickNotification != ClickNotification.None)
{
float time = Time.realtimeSinceStartup;

Notify(currentTouch.pressed, "OnClick", null);

if (currentTouch.clickTime + 0.35f > time)
{
Notify(currentTouch.pressed, "OnDoubleClick", null);
}
currentTouch.clickTime = time;
}


 EventType
public enum EventType
{
World,	// Perform a Physics.Raycast and sort by distance to the point that was hit.
UI,		// Perform a Physics.Raycast and sort by widget depth.
}


        这个很简单就是定义当前射线和碰撞体碰撞的判断标准,如果是UI则以Depth来判断,如果是World是以实际距离来判断。
/// <summary>
/// List of all active cameras in the scene.
/// </summary>

static public List<UICamera> list = new List<UICamera>();


        UICamera在初始化的时候会被加入 mList这个链表中,然后对链表进行排序,根据相机的深度,深度值越小的相机排位靠前,最靠前的相机为场景的主UICamera,然后只有只有主UICamera才会去监测场景中的事件,其他的UICamera并不执行监测任务。UICamera利用Unity的Raycast去监测事件发生的对象,因为发射出去的Ray对象必须碰撞到Collider才会有反应,所以NGUI中所有需要响应事件的控件均需要添加Collider,同时Ray只会碰撞到深度最小的Collider,Ray射线的最大深度为rangeDistance,当这个值为-1时则发射深度和相机深度一样,主UICamera每一帧都会主动去发射Ray检测鼠标此时触碰到的对象并将其记录在对应的鼠标按键事件中,这是能监测到OnHover这个动作的关键(当然只有在useMouse为true时才会有此操作)。

        在游戏场景初始化阶段,每个UICamera都会根据平台义useMouse、useTouch、useKeyboard和useController 这些属性,分别对应的是能否在场景使用鼠标、触摸屏、键盘以及摇杆。
public bool useMouse = true;

public bool useTouch = true;

public bool allowMultiTouch = true;

public bool useKeyboard = true;

public bool useController = true;


MouseOrTouch
/// <summary>
/// Ambiguous mouse, touch, or controller event.
/// </summary>

public class MouseOrTouch
{
public Vector2 pos;				// Current position of the mouse or touch event
public Vector2 delta;			// Delta since last update
public Vector2 totalDelta;		// Delta since the event started being tracked

public Camera pressedCam;		// Camera that the OnPress(true) was fired with

public GameObject current;		// The current game object under the touch or mouse
public GameObject pressed;		// The last game object to receive OnPress
public GameObject dragged;		// The last game object to receive OnDrag

public float clickTime = 0f;	// The last time a click event was sent out

public ClickNotification clickNotification = ClickNotification.Always;
public bool touchBegan = true;
public bool pressStarted = false;
public bool dragStarted = false;
}


       MouseOrTouch是一个很重要的类,是一个事件的结构体,然后就定义了不同平台的事件,记录Camera监测的事件:MouseOrTouch只是记录“鼠标”等的移动的“物理”信息——位置,移动距离等,只有鼠标是否按下只有在Update中每帧监测。

       下面定义不同平台的事件,例如鼠标事件,mMouse记录鼠标左键,右键和中键的事件(因为鼠标这里只记录鼠标的三个按键,所以mMouse才是有三个元素,现在明白为啥了吧)。
// Mouse events
static MouseOrTouch[] mMouse = new MouseOrTouch[] { new MouseOrTouch(), new MouseOrTouch(), new MouseOrTouch() };

// The last object to receive OnHover
static GameObject mHover;

// Joystick/controller/keyboard event
static MouseOrTouch mController = new MouseOrTouch();

// Used to ensure that joystick-based controls don't trigger that often
static float mNextEvent = 0f;

// List of currently active touches
static Dictionary<int, MouseOrTouch> mTouches = new Dictionary<int, MouseOrTouch>();


 currentTouch
/// <summary>
/// ID of the touch or mouse operation prior to sending out the event. Mouse ID is '-1' for left, '-2' for right mouse button, '-3' for middle.
/// </summary>

static public int currentTouchID = -1;

/// <summary>
/// Current touch, set before any event function gets called.
/// </summary>

static public MouseOrTouch currentTouch = null;


       currentTouch这个变量是整个UICamera中控制事件监测的关键所在,记录了当前事件的触发对象和一些其他诸如position位置、dealta时间、totaldealta总时间等属性,然后用currentTouchID记录当前事件的类型,这些类型包括鼠标事件、键盘控制器事件以及触摸屏事件。

ProcessTouch

       ProcessTouch这个函数就是根据currentTouch来针对不同的情况响应不同的函数,被ProcessMouse,ProcessTouch和ProcessOthers调用,如ProcessMouse,分别捕获鼠标三个按键的状态,然后调用ProcessTouch来响应:
// Process all 3 mouse buttons as individual touches
if (useMouse)
{
for (int i = 0; i < 3; ++i)
{
bool pressed = Input.GetMouseButtonDown(i);
bool unpressed = Input.GetMouseButtonUp(i);

currentTouch = mMouse[i];
currentTouchID = -1 - i;

// We don't want to update the last camera while there is a touch happening
if (pressed) currentTouch.pressedCam = currentCamera;
else if (currentTouch.pressed != null) currentCamera = currentTouch.pressedCam;

// Process the mouse events
ProcessTouch(pressed, unpressed);
}


 其他

        UICamera还提供其他一些“特性”,能够让开发者实现更多的功能(就不解释了吧, 有注释):
/// <summary>
/// If 'true', once a press event is started on some object, that object will be the only one that will be
/// receiving future events until the press event is finally released, regardless of where that happens.
/// If 'false', the press event won't be locked to the original object, and other objects will be receiving
/// OnPress(true) and OnPress(false) events as the touch enters and leaves their area.
/// </summary>

public bool stickyPress = true;

/// <summary>
/// If set, this game object will receive all events regardless of whether they were handled or not.
/// </summary>

static public GameObject genericEventHandler;

/// <summary>
/// If events don't get handled, they will be forwarded to this game object.
/// </summary>

static public GameObject fallThrough;


最后,NGUI一共支持一下事件:
void OnHover (bool isOver) – Sent out when the mouse hovers over the collider or moves away from it. Not sent on touch-based devices.
void OnPress (bool isDown) – Sent when a mouse button (or touch event) gets pressed over the collider (with ‘true’) and when it gets released (with ‘false’, sent to the same collider even if it’s released elsewhere).
void OnClick() — Sent to a mouse button or touch event gets released on the same collider as OnPress. UICamera.currentTouchID tells you which button was clicked.
void OnDoubleClick () — Sent when the click happens twice within a fourth of a second. UICamera.currentTouchID tells you which button was clicked.
void OnSelect (bool selected) – Same as OnClick, but once a collider is selected it will not receive any further OnSelect events until you select some other collider.
void OnDrag (Vector2 delta) – Sent when the mouse or touch is moving in between of OnPress(true) and OnPress(false).
void OnDrop (GameObject drag) – Sent out to the collider under the mouse or touch when OnPress(false) is called over a different collider than triggered the OnPress(true) event. The passed parameter is the game object of the collider that received the OnPress(true) event.
void OnInput (string text) – Sent to the same collider that received OnSelect(true) message after typing something. You likely won’t need this, but it’s used by UIInput
void OnTooltip (bool show) – Sent after the mouse hovers over a collider without moving for longer than tooltipDelay, and when the tooltip should be hidden. Not sent on touch-based devices.
void OnScroll (float delta) is sent out when the mouse scroll wheel is moved.
void OnKey (KeyCode key) is sent when keyboard or controller input is used.


       最近由于项目要用到FastGUI,然后手上的FastGUI不支持NGUI(NGUI变动太大了),然后自己要升级下FastGUI,就要更多的掌握NGUI的原理,所以才会一直不断的写一些文章。写文章主要是记录下自己从中看到的东西,当然D.S.Qiu最喜欢和大家分享,希望能对读者有帮助,哪怕只有一个人,D.S.Qiu也会很兴奋的,因为很多次D.S.Qiu都不打算写的(文章写的太烂,没有深度,逻辑差,每次都要熬夜等),但当我看到别人文章的亮点时,我就觉得自己还是可以分享些的。

       今天把FastGUI 兼容到了NGUi3.0.3f,还增加一些功能,然后要写一个文档给美术的同事,我感觉头就大了,感觉如果要我口述一定能让听者完全明白,但是写起来就完全不着调,所以觉得D.S.Qiu的文字很渣,马上就是凌晨1:30,睡觉,晚安!

        如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity3d