国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Unity事件處理機(jī)制與NGUI事件機(jī)制

2019-11-14 14:11:27
字體:
供稿:網(wǎng)友

1 Unity原生

1.1 GUI

void OnGUI(){if(GUI.Button(Rect position, string text)){    //點(diǎn)擊后立即執(zhí)行}

1.1 Input

每個手指觸控是通過Input.touches數(shù)據(jù)結(jié)構(gòu)描述的:

  • fingerId 手指索引
    The unique index for a touch. 觸摸的唯一索引。
  • position 位置
    The screen position of the touch. 觸摸屏幕的位置。
  • deltaPosition 增量位置
    The screen position change since the last frame.
    自最后一幀改變的屏幕位置。
  • deltaTime 增量時間
    Amount of time that has passed since the last state change.
    從最后狀態(tài)改變到現(xiàn)在經(jīng)過的時間
  • tapCount 點(diǎn)擊數(shù)
    The iphone/iPad screen is able to distinguish quick finger taps by the user. This counter will let you know how many times the user has tapped the screen without moving a finger to the sides. Android devices do not count number of taps, this field is always 1.
    iPhone/iPad屏幕能夠識別用過的快速點(diǎn)擊, 這個計數(shù)器讓你知道用戶點(diǎn)擊屏幕多少次,而不是移動手指。android設(shè)備不對點(diǎn)擊計數(shù),這個方法總是返回1
  • phase 相位(狀態(tài))
    Describes so called "phase" or the state of the touch. It can help you determine if the touch just began, if user moved the finger or if he just lifted the finger.
    描述觸摸的狀態(tài),可以幫助開發(fā)者確定用戶是否剛開始觸摸,是否用戶移動手指,是否用戶剛剛抬起手指。

  Phase can be one of the following:

  相位(狀態(tài))可能是下列之一:

    • Began 開始
      A finger just touched the screen. 手指剛剛觸摸屏幕
    • Moved 移動
      A finger moved on the screen. 手指在屏幕上移動
    • Stationary 靜止
      A finger is touching the screen but hasn't moved since the last frame.
      手指觸摸屏幕,但是自最后一幀沒有移動
    • Ended 結(jié)束
      A finger was lifted from the screen. This is the final phase of a touch.
      手指從屏幕上抬起,這是觸控的最后狀態(tài)。
    • Canceled 取消
      The system cancelled tracking for the touch, as when (for example) the user puts the device to her face or more than five touches happened simultaneously. This is the final phase of a touch.
      系統(tǒng)取消了觸控跟蹤,如,用戶將設(shè)備放在了臉上或超過同時超過5個觸摸點(diǎn)。這是觸控的最后狀態(tài)。
  • 下面的例子,只要用戶在屏幕上點(diǎn)擊,將射出一條光線:

var particle : GameObject;function Update () {    for (var touch : Touch in Input.touches) {        if (touch.phase == TouchPhase.Began) {            // Construct a ray from the current touch coordinates            //從當(dāng)前的觸摸坐標(biāo)建一條光線            var ray = Camera.main.ScreenPointToRay (touch.position);            if (Physics.Raycast (ray)) {                // Create a particle if hit                //如果觸摸就創(chuàng)建一個例子                Instantiate (particle, transform.position, transform.rotation);            }        }    }}

2 NGUI事件機(jī)制

       UICamera主要負(fù)責(zé)監(jiān)聽,分發(fā)所有此Camera渲染的GameObject。

       事件源:鼠標(biāo),觸屏,鍵盤和手柄

事件包括:懸停,按下/抬起,選中/取消選中,點(diǎn)擊,雙擊,拖拽,釋放,文本輸入,tips顯示,滾輪滑動,鍵盤輸入。

 

EventType:包括3D UI,3D world,2D UI,3D World用于區(qū)分UICamera處理UI事件的對象是UI空間還是3D物體。

EventMask:可以過濾到一些不需要接受UI事件的對象。

EventSource:只處理指定事件源,如touch

Thresholds:是指事件誤差的范圍。

2.1 NGUI事件注冊

2.1.1 直接監(jiān)聽事件

直接將MonoBehaviour的腳本上的方法綁定至Notifiy上面。這種方法不夠靈活,不推薦。

 

2.1.2 使用SendMessage

過期方式,不建議使用。

2.1.3 UIListener注冊

     在需要接收事件的gameobject上附加Event Listener。添加component->NGUI->Internal->Event Listener。

在任何一個腳本或者類中即可得到按鈕的點(diǎn)擊事件、把如下代碼放在任意類中或者腳本中。

void Awake ()     {                    //獲取需要監(jiān)聽的按鈕對象    GameObject button = GameObject.Find("UI Root (2D)/Camera/Anchor/Panel/LoadUI/MainCommon/Button");                //設(shè)置這個按鈕的監(jiān)聽,指向本類的ButtonClick方法中。    UIEventListener.Get(button).onClick = ButtonClick;    }         //計算按鈕的點(diǎn)擊事件    void ButtonClick(GameObject button)    {        Debug.Log("GameObject " + button.name);    }

3 NGUI事件相關(guān)源碼分析

3.1 事件注冊

UIEventListener.Get(gameObject).onClick = ButtonClick;//1、獲取GameObject對應(yīng)的UIEventListener的組件static public UIEventListener Get (GameObject go)    {        UIEventListener listener = go.GetComponent<UIEventListener>();        if (listener == null) listener = go.AddComponent<UIEventListener>();        return listener;    }//2、注冊事件委托public class UIEventListener : MonoBehaviour{    public delegate void VoidDelegate (GameObject go);        public VoidDelegate onClick;        void OnClick (){ if (onClick != null) onClick(gameObject); }}

3.1.1 觀察者模式和事件/委托機(jī)制

觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象,這個主題對象在狀態(tài)發(fā)生變化時,會通知所有的觀察者對象,使他們能夠執(zhí)行自己的相關(guān)行為。

 

可以看出,在觀察者模式的結(jié)構(gòu)圖有以下角色:

  • 抽象主題角色(Subject):抽象主題把所有觀察者對象的引用保存在一個列表中,并提供增加和刪除觀察者對象的操作,抽象主題角色又叫做抽象被觀察者角色,一般由抽象類或接口實(shí)現(xiàn)。
  • 抽象觀察者角色(Observer):為所有具體觀察者定義一個接口,在得到主題通知時更新自己,一般由抽象類或接口實(shí)現(xiàn)。
  • 具體主題角色(ConcreteSubject):實(shí)現(xiàn)抽象主題接口,具體主題角色又叫做具體被觀察者角色。
  • 具體觀察者角色(ConcreteObserver):實(shí)現(xiàn)抽象觀察者角色所要求的接口,以便使自身狀態(tài)與主題的狀態(tài)相協(xié)調(diào)。

3.1.1.1            委托

1、委托定義

在C#中定義一個委托非常簡單,只要包含關(guān)鍵詞delegate,其他的與普通方法一致。

public delegate void GreetingDelegate(string name);

委托是一個類,它定義了方法的類型,使得可以將方法當(dāng)作另一個方法的參數(shù)來進(jìn)行傳遞,這種將方法動態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語句,同時使得程序具有更好的可擴(kuò)展性。(與java中的接口非常相似)。

 2、方法綁定委托

上面的綁定onclick即是一個方法綁定。

UIEventListener.Get(gameObject).onClick = ButtonClick;

委托方法可以綁定多個方法,調(diào)用時會一次調(diào)用綁定的方法。

UIEventListener.Get(gameObject).onClick += ButtonClick2;

  委托還可以通過-=的方式解除綁定。

注意:第一次綁定必須用賦值=,如果使用+=將會發(fā)生編譯錯誤。

3.2 UICamera事件分發(fā)

3.2.1 初始化設(shè)置

設(shè)置fallThrough為攝像機(jī)節(jié)點(diǎn)的UI Root節(jié)點(diǎn)或者攝像機(jī)節(jié)點(diǎn)或者當(dāng)前本身gameobject。

3.2.2 update獲取事件源

Unity提供了Input接口,能夠從觸屏中獲取各類輸入事件。Update的時候查看事件輸入情況,并通過PRocessTouches處理觸屏事件。

 

ProcessTouches函數(shù)

public void ProcessTouches ()    {        currentScheme = ControlScheme.Touch;        for (int i = 0; i < Input.touchCount; ++i)        {            Touch touch = Input.GetTouch(i);                       currentTouchID = allowMultiTouch ? touch.fingerId : 1;            //根據(jù)TouchID獲取touch事件,如果是begin的則創(chuàng)建新對象加入緩存            currentTouch = GetTouch(currentTouchID);            //設(shè)置當(dāng)前輸入的相位            bool pressed = (touch.phase == TouchPhase.Began) || currentTouch.touchBegan;            bool unpressed = (touch.phase == TouchPhase.Canceled) || (touch.phase == TouchPhase.Ended);            currentTouch.touchBegan = false;            // Although input.deltaPosition can be used, calculating it manually is safer (just in case)            //如果不是開始按下,就需要計算與上一次的偏移情況            currentTouch.delta = pressed ? Vector2.zero : touch.position - currentTouch.pos;            currentTouch.pos = touch.position;            // Raycast into the screen            //通過射線獲取可以點(diǎn)擊的gameobject            if (!Raycast(currentTouch.pos)) hoveredObject = fallThrough;            if (hoveredObject == null) hoveredObject = mGenericHandler;            currentTouch.last = currentTouch.current;            currentTouch.current = hoveredObject;            lastTouchPosition = currentTouch.pos;            // 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;            // Double-tap support            //ios的多次點(diǎn)擊,則需要設(shè)置時間戳            if (touch.tapCount > 1) currentTouch.clickTime = RealTime.time;            // Process the events from this touch            ProcessTouch(pressed, unpressed);            // If the touch has ended, remove it from the list            if (unpressed) RemoveTouch(currentTouchID);            currentTouch.last = null;            currentTouch = null;            // Don't consider other touches            if (!allowMultiTouch) break;        }        if (Input.touchCount == 0)        {            if (useMouse) ProcessMouse();#if UNITY_EDITOR            else ProcessFakeTouches();#endif        }    }

這里需要重點(diǎn)介紹Raycast(Vector3 inpos)和ProcessTouch()。

3.2.2.1            Raycast

list中緩存這當(dāng)前場景中,所有的攝像機(jī),并按照深度來排序。

主要處理World_3D、UI_3D、World_2D和UI_2D4種不同類型的。

static public bool Raycast (Vector3 inPos)    {        for (int i = 0; i < list.size; ++i)        {            UICamera cam = list.buffer[i];                        // Skip inactive scripts            //沒有激活的,全部跳過            if (!cam.enabled || !NGUITools.GetActive(cam.gameObject)) continue;            // Convert to view space            currentCamera = cam.cachedCamera;            Vector3 pos = currentCamera.ScreenToViewportPoint(inPos);//找到屏幕坐標(biāo)            if (float.IsNaN(pos.x) || float.IsNaN(pos.y)) continue;            // If it's outside the camera's viewport, do nothing            if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f) continue;            // Cast a ray into the screen            Ray ray = currentCamera.ScreenPointToRay(inPos);            // Raycast into the screen            //UI層和事件層都OK的            int mask = currentCamera.cullingMask & (int)cam.eventReceiverMask;            float dist = (cam.rangeDistance > 0f) ? cam.rangeDistance : currentCamera.farClipPlane - currentCamera.nearClipPlane;            if (cam.eventType == EventType.World_3D)            {                if (Physics.Raycast(ray, out lastHit, dist, mask))                {                    lastWorldPosition = lastHit.point;                    hoveredObject = lastHit.collider.gameObject;                    //如果父節(jié)點(diǎn)上有剛體,則返回                    Rigidbody rb = FindRootRigidbody(hoveredObject.transform);                    if (rb != null) hoveredObject = rb.gameObject;                    return true;                }                continue;            }            else if (cam.eventType == EventType.UI_3D)            {                                RaycastHit[] hits = Physics.RaycastAll(ray, dist, mask);                if (hits.Length > 1)                {                    //碰到多個colider                    for (int b = 0; b < hits.Length; ++b)                    {                        GameObject go = hits[b].collider.gameObject;                        UIWidget w = go.GetComponent<UIWidget>();                        //根據(jù)UIWidget或者UIRect來判斷,落點(diǎn)是不是在節(jié)點(diǎn)里面                        if (w != null)                        {                            if (!w.isVisible) continue;                            if (w.hitCheck != null && !w.hitCheck(hits[b].point)) continue;                        }                        else                        {                            UIRect rect = NGUITools.FindInParents<UIRect>(go);                            if (rect != null && rect.finalAlpha < 0.001f) continue;                        }                        //計算射線的深度                        mHit.depth = NGUITools.CalculateRaycastDepth(go);                        if (mHit.depth != int.MaxValue)                        {                            mHit.hit = hits[b];                            mHit.point = hits[b].point;                            mHit.go = hits[b].collider.gameObject;                            mHits.Add(mHit);                        }                    }                    //根據(jù)深度排序                    mHits.Sort(delegate(DepthEntry r1, DepthEntry r2) { return r2.depth.CompareTo(r1.depth); });                    for (int b = 0; b < mHits.size; ++b)                    {#if UNITY_Flash                        if (IsVisible(mHits.buffer[b]))#else                        //最上層且可見的,為返回的節(jié)點(diǎn)                        if (IsVisible(ref mHits.buffer[b]))#endif                        {                            lastHit = mHits[b].hit;                            hoveredObject = mHits[b].go;                            lastWorldPosition = mHits[b].point;                            mHits.Clear();                            return true;                        }                    }                    mHits.Clear();                }                else if (hits.Length == 1)                {                    GameObject go = hits[0].collider.gameObject;                    UIWidget w = go.GetComponent<UIWidget>();                    if (w != null)                    {                        if (!w.isVisible) continue;                        if (w.hitCheck != null && !w.hitCheck(hits[0].point)) continue;                    }                    else                    {                        UIRect rect = NGUITools.FindInParents<UIRect>(go);                        if (rect != null && rect.finalAlpha < 0.001f) continue;                    }                    if (IsVisible(hits[0].point, hits[0].collider.gameObject))                    {                        lastHit = hits[0];                        lastWorldPosition = hits[0].point;                        hoveredObject = lastHit.collider.gameObject;                        return true;                    }                }                continue;            }            else if (cam.eventType == EventType.World_2D)            {                //用Plane射線獲取                if (m2DPlane.Raycast(ray, out dist))                {                    Vector3 point = ray.GetPoint(dist);                    Collider2D c2d = Physics2D.OverlapPoint(point, mask);                    if (c2d)                    {                        lastWorldPosition = point;                        hoveredObject = c2d.gameObject;                        Rigidbody2D rb = FindRootRigidbody2D(hoveredObject.transform);                        if (rb != null) hoveredObject = rb.gameObject;                        return true;                    }                }                continue;            }            else if (cam.eventType == EventType.UI_2D)            {                if (m2DPlane.Raycast(ray, out dist))                {                    lastWorldPosition = ray.GetPoint(dist);                    Collider2D[] hits = Physics2D.OverlapPointAll(lastWorldPosition, mask);                    if (hits.Length > 1)                    {                        for (int b = 0; b < hits.Length; ++b)                        {                            GameObject go = hits[b].gameObject;                            UIWidget w = go.GetComponent<UIWidget>();                            if (w != null)                            {                                if (!w.isVisible) continue;                                if (w.hitCheck != null && !w.hitCheck(lastWorldPosition)) continue;                            }                            else                            {                                UIRect rect = NGUITools.FindInParents<UIRect>(go);                                if (rect != null && rect.finalAlpha < 0.001f) continue;                            }                            mHit.depth = NGUITools.CalculateRaycastDepth(go);                            if (mHit.depth != int.MaxValue)                            {                                mHit.go = go;                                mHit.point = lastWorldPosition;                                mHits.Add(mHit);                            }                        }                        mHits.Sort(delegate(DepthEntry r1, DepthEntry r2) { return r2.depth.CompareTo(r1.depth); });                        for (int b = 0; b < mHits.size; ++b)                        {#if UNITY_FLASH                            if (IsVisible(mHits.buffer[b]))#else                            if (IsVisible(ref mHits.buffer[b]))#endif                            {                                hoveredObject = mHits[b].go;                                mHits.Clear();                                return true;                            }                        }                        mHits.Clear();                    }                    else if (hits.Length == 1)                    {                        GameObject go = hits[0].gameObject;                        UIWidget w = go.GetComponent<UIWidget>();                        if (w != null)                        {                            if (!w.isVisible) continue;                            if (w.hitCheck != null && !w.hitCheck(lastWorldPosition)) continue;                        }                        else                        {                            UIRect rect = NGUITools.FindInParents<UIRect>(go);                            if (rect != null && rect.finalAlpha < 0.001f) continue;                        }                        if (IsVisible(lastWorldPosition, go))                        {                            hoveredObject = go;                            return true;                        }                    }                }                continue;            }        }        return false;    }

3.2.2.2            ProcessTouch

ProcessTouch根據(jù)閥值,判斷需要通知的事件類型。直接調(diào)用RasyCast返回的GameObject上UIEventListen注冊的事件。

通過直接執(zhí)行事件委托(onClick),或者SendMessage給返回的GameObject上的相關(guān)事件委托。

4 Unity知識

4.1 Camera

游戲界面中所顯示的內(nèi)容是攝像機(jī)照射到得場景部分。攝像機(jī)可以設(shè)置自身的位置、照射方向、照射的面積(類似于顯示中照射廣度)和照射的圖層(只看到自己想看到的層次)。

 

Clear Flags:背景內(nèi)容,默認(rèn)為Skybox

Background:Clear Flag沒設(shè)置,將顯示純色

Culling Mask:用于選擇是否顯示某些層,默認(rèn)為“EveryThing”

Projection:攝像機(jī)類型,透視和正交。正交適合2D,沒有距離感。

Clipping Planes:開始攝像的最近點(diǎn)和最遠(yuǎn)點(diǎn)

Viewport Rect:設(shè)置顯示區(qū)域。多攝像機(jī)可以設(shè)置不同的區(qū)域,來進(jìn)行分屏顯示。

Depth:深度大的會,畫在小的上面。

Rendering Path:渲染方式。

4.2 Colider

Colider是所有碰撞器的基類,包括BoxColider,SphereColider,CapsuleColider,MeshColider,PhysicMaterial,Rigidbody。

4.2.1 RigidBody剛體

剛體可以附加物理屬性如物體質(zhì)量、摩擦力和碰撞系數(shù)。

Mass:質(zhì)量

Drag:阻力

Angular Drag:旋轉(zhuǎn)阻力,越大旋轉(zhuǎn)減慢越快

Use Gravity:是否用重力

Is Kinematic:是否受物理的影響

Collision Detection:碰撞檢測

Constraints:凍結(jié),某個方向上的物理效果

4.2.1.1            碰撞

通過sendMessage調(diào)用改方法

OnCollisionEnter(Collision collision):開始時,立刻調(diào)用

OnCollisionStay(Collision collision):碰撞中,每幀調(diào)用

OnCollisionExit(Collision collision):結(jié)束時調(diào)用

4.2.2 碰撞器

BoxColider(盒子碰撞器),SphereColider(球體碰撞器),CapsuleColider(膠囊碰撞器),MeshColider(自定義模型自身網(wǎng)格決定),WheelMaterial(車輪碰撞器)。

碰撞器之間可以添加物理材質(zhì),用于設(shè)定物理碰撞后的效果。如反彈。

4.2.3 射線

射線是3D世界中一個點(diǎn)向一個方向發(fā)射的一條無終點(diǎn)的線。在發(fā)射的軌跡中,一旦與其他模型發(fā)生碰撞,它將停止發(fā)射(也可以是All)。

創(chuàng)建一個射線首先要知道射線的起點(diǎn)和終點(diǎn)在3D世界中的坐標(biāo)。Ray即為起點(diǎn)和終點(diǎn)的封裝。ScreenPointToRay,是由攝像機(jī)當(dāng)前位置向鼠標(biāo)位置發(fā)射的射線。

5 參考文獻(xiàn)

http://game.ceeger.com/Manual/Input.html

http://blog.csdn.net/onerain88/article/details/18963539

http://wetest.QQ.com


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 容城县| 博白县| 临安市| 桃园市| 丹阳市| 定西市| 甘南县| 盐山县| 罗田县| SHOW| 沈阳市| 巨鹿县| 成安县| 龙泉市| 临高县| 隆德县| 永登县| 台安县| 泽普县| 灵丘县| 建德市| 南岸区| 潜江市| 江都市| 兴仁县| 米脂县| 成都市| 清水河县| 响水县| 老河口市| 海安县| 汉川市| 宣威市| 新闻| 宜章县| 云龙县| 仪征市| 通城县| 汕头市| 讷河市| 吉林市|