- 最后登录
- 2018-1-5
- 注册时间
- 2012-10-11
- 阅读权限
- 30
- 积分
- 651
- 纳金币
- 0
- 精华
- 3
|
pstatus"> 本帖最后由 艾西格亚 于 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
试验非常成功,item上的OnClick事件的处理工作很好的转移到__ItemOnClickHandler方法上。这样我们就可以省去大量的绑定脚本的工作。我们可以更有远见的想象一下,加入一个视图比较复杂,我之前做了一个东西的,截图如下:
这个UI中需要处理的事件至少有4个,而且还会在下面动态生成展现渲染对象,并对其填充数据。这样一来,用绑脚本的方式即使解决了问题,那也是非常稀烂的解法。我是这样处理的,用一个类来控制这个窗口,将这些需要发布事件的控件动态添加UIEventListener脚本,然后在这个类中用不同的回调函数来处理这些事件。事后证明,这种方法是非常有效的,虽然还有待改进。这样一来,我们就省去了很多很多不必要的帮脚本的麻烦。
我们可以试验一下,尝试着为一个复杂的视图的各个子控件添加不同的事件,然后分别用不同的回调函数来处理。下一篇,我将深入一下这方面的讲解,我想这些东西多少是大家需要的,希望大家多多回复,支持一下我的工作呀!
|
|