纳金网

标题: Unity中的事件编程1 [打印本页]

作者: wyb314    时间: 2013-4-15 22:44
标题: Unity中的事件编程1
本帖最后由 艾西格亚 于 2013-4-16 23:09 编辑

                                                                                Unity3D事件编程
      相信大家对Unity3D中的NGUI插件不会陌生吧,但很少有人认真的看过里面的代码。也确实,看那些代码需要相当的毅力的,但是不看的话,就永远也别想用好NGUI,这并不是危言耸听。我接下来要讲述的事件编程将要从NGUI中的一个非常有用的NGUI脚本开始:

        大家打开Unity,导入NGUI包后,打开一个名为UIEventListener.cs的脚本,如下:


using UnityEngine;

[AddComponentMenu("NGUI/Internal/Event Listener")]
public class UIEventListener : MonoBehaviour
{
        public delegate void VoidDelegate (GameObject go);
        public delegate void BoolDelegate (GameObject go, bool state);
        public delegate void FloatDelegate (GameObject go, float delta);
        public delegate void VectorDelegate (GameObject go, Vector2 delta);
        public delegate void StringDelegate (GameObject go, string text);
        public delegate void ObjectDelegate (GameObject go, GameObject draggedObject);
        public delegate void KeyCodeDelegate (GameObject go, KeyCode key);

        public object parameter;

        public VoidDelegate onSubmit;
        public VoidDelegate onClick;
        public VoidDelegate onDoubleClick;
        public BoolDelegate onHover;
        public BoolDelegate onPress;
        public BoolDelegate onSelect;
        public FloatDelegate onScroll;
        public VectorDelegate onDrag;
        public ObjectDelegate onDrop;
        public StringDelegate onInput;
        public KeyCodeDelegate onKey;

        void OnSubmit ()                                { if (onSubmit != null) onSubmit(gameObject); }
        void OnClick ()                                        { if (onClick != null) onClick(gameObject); }
        void OnDoubleClick ()                        { if (onDoubleClick != null) onDoubleClick(gameObject); }
        void OnHover (bool isOver)                { if (onHover != null) onHover(gameObject, isOver); }
        void OnPress (bool isPressed)        { if (onPress != null) onPress(gameObject, isPressed); }
        void OnSelect (bool selected)        { if (onSelect != null) onSelect(gameObject, selected); }
        void OnScroll (float delta)                { if (onScroll != null) onScroll(gameObject, delta); }
        void OnDrag (Vector2 delta)                { if (onDrag != null) onDrag(gameObject, delta); }
        void OnDrop (GameObject go)                { if (onDrop != null) onDrop(gameObject, go); }
        void OnInput (string text)                { if (onInput != null) onInput(gameObject, text); }
        void OnKey (KeyCode key)                { if (onKey != null) onKey(gameObject, key); }

        static public UIEventListener Get (GameObject go)
        {
                UIEventListener listener = go.GetComponent<UIEventListener>();
                if (listener == null) listener = go.AddComponent<UIEventListener>();
                return listener;
        }
}


        如果大家对C#中的事件发布与事件订阅很熟的话,看懂以上代码是轻而易举的事。这里我为对这方面并不熟的朋友唠叨几句:所谓事件的发布者,即为事件的侦听对象,当某个事件发生之后,这个侦听对象就会马上将此事件发送到各个订阅者手上。事件的订阅者即为订阅某个事件的对象,同一个事件可以被多个订阅者所订阅。事件的订阅对象必然会在事件作出相应的动作,否则没必要多此一举。例如:当我们按下某个UI界面的按钮时,一般界面会发生相应的界面,比如谷歌搜索引擎。此时,按钮就相当于事件的发布者,搜索界面的控制程序就相当于事件的订阅对象,针对按钮发布的事件,获取到相应的数据,并将其填充到搜索界面。
        我们可以利用这个脚本中的Get函数来动态的添加事件了。 接下来很快就会看到此种编程的好处了!

        我们打开NGUI中的第7个粒子:Scroll View(Panel)。新建一个Manager的空的GameObject,然后新建一个脚本TestEvent.cs,代码如下:


using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class TestUIEvent : MonoBehaviour {

    public GameObject uiGrid;//所有item的父容器

    private List<Transform> items;//存储所有items的线性表

        // Use this for initialization
        void Start () {

            if(uiGrid == null)//检查父容器是否存在

            {
               Debug.LogError("The uiGide is not exist!");
                return;
            }



            FillItems();//将父容器下的所有子物体添加到items容器中。
        }

    private void FillItems()
    {
        if(items == null)
        {
            items = new List<Transform>(); //实例化此集合
        }

        Transform tr = uiGrid.transform;//获得此父容器的transform
        int count = tr.childCount;//获得此父容器下的子物体数量,便于后面通过transform.GetChild(int index)函数遍历各个子物体的Transform


        if(count == 0)//如果子物体数量为0,就不需要进行下去了。
        {
            Debug.Log("The uiGrid'child count is zero! ");
            return;
        }

        for (int i = 0; i < count; i++)
        {
            items.Add(tr.GetChild(i));//添加各个子物体到items线性表中

        }

        foreach (Transform tm in items)
        {
            UIEventListener listener = null;
            listener = tm.gameObject.GetComponent<UIEventListener>();

            if(listener == null)
            {
                listener = UIEventListener.Get(tm.gameObject);//为各个item动态添加UIEventListener脚本
                listener.onClick += new UIEventListener.VoidDelegate(__ItemOnClickHandler);//订阅各个Item上的OnClick事件

            }

        }
    }

    private void __ItemOnClickHandler(GameObject go) //处理item被单击后的事件。
    {
        Debug.Log("The item name is : "+ go.name +" is onClick!");//简单的打印一下item的名字
    }
}


如图所示,将图中的UIGrid拖拽到TestEvent脚本上的uiGrid选项上:

为此,我特意将Item增加到20个。
好了,我们运行一下吧,结果如下:


UIEventListener脚本已经添加上去了,控制台输出结果如下:
file:///C:/Users/wyb314/AppData/Local/youdao/ynote/images/3FFB8C3DDF374D71BE740EB8F05CBA00/clipboard.png
3.png

试验非常成功,item上的OnClick事件的处理工作很好的转移到__ItemOnClickHandler方法上。这样我们就可以省去大量的绑定脚本的工作。我们可以更有远见的想象一下,加入一个视图比较复杂,我之前做了一个东西的,截图如下:
4.png

这个UI中需要处理的事件至少有4个,而且还会在下面动态生成展现渲染对象,并对其填充数据。这样一来,用绑脚本的方式即使解决了问题,那也是非常稀烂的解法。我是这样处理的,用一个类来控制这个窗口,将这些需要发布事件的控件动态添加UIEventListener脚本,然后在这个类中用不同的回调函数来处理这些事件。事后证明,这种方法是非常有效的,虽然还有待改进。这样一来,我们就省去了很多很多不必要的帮脚本的麻烦。
        我们可以试验一下,尝试着为一个复杂的视图的各个子控件添加不同的事件,然后分别用不同的回调函数来处理。下一篇,我将深入一下这方面的讲解,我想这些东西多少是大家需要的,希望大家多多回复,支持一下我的工作呀!





作者: 狂风大尉    时间: 2013-4-15 22:59
支持楼主的文章,很好的资料分享,收藏了
作者: liu1809    时间: 2013-4-16 08:09

看上去和可视化编程的工具很像,也是节点的,不错哦

作者: 我没有过去    时间: 2013-4-16 17:45
感谢楼主的分享,强啊
作者: hpl123    时间: 2013-4-17 08:37
太犀利,谢谢奉献~~~~~~~~~~~~
作者: Furion    时间: 2013-4-18 12:27
NGUI与游戏的整合!Good!
作者: bbsbot    时间: 2013-4-21 09:16
kankan zhege kankan
作者: 筱筱    时间: 2013-4-24 08:52
谢楼主分享
作者: saviosun    时间: 2013-4-26 15:53
很不错的想法
作者: Sora    时间: 2013-4-28 08:53
很不錯的學習思路
作者: xielei69    时间: 2013-12-9 16:37
很好的思路
作者: HIDEOKOJIMA    时间: 2013-12-9 17:10
谢楼主分享
作者: HIDEOKOJIMA    时间: 2013-12-9 21:34
谢楼主分享
作者: yinzhuo    时间: 2013-12-10 12:39
感谢分享。  回复 赚点钱。。。。
作者: dzspb    时间: 2013-12-10 20:51
很好的教程,谢谢!
作者: nianhua2008    时间: 2013-12-28 23:46
学习了,支持!
作者: zardcom    时间: 2014-7-23 15:45
楼主好棒。。。。




欢迎光临 纳金网 (http://course.narkii.com/club/) Powered by Discuz! X2.5