2019-05-25 13:52:27 xiaoxiaoting1010 阅读数 79

1.定义一个委托(委托要与后面的执行函数参数保持相同,也可以不带参数)

2.通过委托 声明一个事件

3.发送方:发送事件

4.接收方:a.执行函数, b.绑定事件

 

 

新建C#脚本 fasong,代码如下:

using UnityEngine;
using System.Collections;

public class fasong : MonoBehaviour {
    //!!!!定义委托(委托参数要与后面执行函数参数保持一致)
    public delegate void ListenerHandler(Object sender);
    //!!!!通过委托 声明一个事件
    public event ListenerHandler Listener = null;

    // Use this for initialization
    void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
        //!!!!发送事件
        if (Input.GetMouseButtonDown(0))//0为左键,1为右键
        {
            this.Listener(this);
        }
        //!!!键盘A监听
        if (Input.GetKeyDown(KeyCode.A))//键盘按下A,发送事件
        {
            Listener(this);
        }



    }
}

把脚本挂在其中一个物体上。

接收者人物的脚本修改如下:

using UnityEngine;
using System.Collections;
//!!!!!!!!!!!
using System.Collections.Generic;

public class womenRun : MonoBehaviour {
    private NavMeshAgent agent;
    public GameObject target;
    private Animator animator;
//!!!!!!!!!!!!
    public GameObject aaa;

	// Use this for initialization
	void Start () {
        //获取组件NavMeshAgent
        agent = GetComponent<NavMeshAgent>();         
        animator = GetComponent<Animator>();
        //!!!!!绑定事件
        aaa.GetComponent<fasong>().Listener += new fasong.ListenerHandler(noteMe);	
	}
	
	// Update is called once per frame
	void Update () {	
	}

    //!!!!!执行函数
    private void noteMe(Object sender)
    {
        Debug.Log(sender.name);
        //SetDestination自动寻路函数,targer为目标,transform为目标组件,position为组件上位置
        agent.SetDestination(target.transform.position);
        animator.Play("run");
    }
}

上面fasong脚本挂在哪个物体上,则把哪个物体拖到人物脚本上:

2018-01-03 10:38:57 linuxheik 阅读数 929

Unity UGUI 按钮绑定事件的 4 种方式

UGUI 可视化创建以及关联事件很方便, 动态创建可以利用创建好的 Prefab 进行实例化, 只是在关联事件上有些复杂, 本文总结了几种给按钮绑定事件的关联方式.

1. 可视化创建及事件绑定 #

Step 1 : 通过 Hierarchy 面板创建 UI > Button.

Step 2 : 创建一个脚本 TestClick.cs, 定义了一个 Click 的 public 方法.

Step 3 : 选中 Hierarchy 中的 Button, Add Component 脚本 TestClick.cs

Step 4 : 在 Button(Script) 关联 TestClick 脚本里的 Click 方法.

Step 5 : Done.

TestClick.cs

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

public class TestClick : MonoBehaviour {

    public void Click(){
        Debug.Log ("Button Clicked. TestClick.");
    }
}

2. 通过直接绑定脚本来绑定事件 #

Step 1 : 通过 Hierarchy 面板创建 UI > Button.

Step 2 : 创建一个 ClickHandler.cs 脚本, 定义了一个私有方法 OnClick(), 并在 Start() 方法里为 Button 添加点击事件的监听,作为参数传入 OnClick 方法.

Step 3 : 将 ClickHandler 绑定在 Button 对象上.

Step 4 : Done.

ClickHandler.cs

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

public class ClickHandler : MonoBehaviour {

    void Start () {
        Button btn = this.GetComponent<Button> ();
        btn.onClick.AddListener (OnClick);
    }

    private void OnClick(){
        Debug.Log ("Button Clicked. ClickHandler.");
    }

}

3. 通过 EventTrigger 实现按钮点击事件 #

UGUI 系统中 Button 默认只提供了 OnClick 的调用方法, 有时候我们还需要监听鼠标进入事件 (MouseIn) 和鼠标滑出事件 (MouseOut). 就需要借助 UI 系统中的 EventTrigger 脚本来实现.

Step 1 : 通过 Hierarchy 面板创建 UI > Button.

Step 2 : 创建一个 EventTriggerHandler.cs 脚本, 利用 UnityEngine.EventSystems.EventTrigger 添加监听事件.

Step 3 : 绑定 EventTriggerHandler.cs 脚本到 Button 上.

Step 4 : Done.

EventTriggerHandler.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

// 需要 EventTrigger 脚本的支援
[RequireComponent(typeof(UnityEngine.EventSystems.EventTrigger))]
public class EventTriggerHandler : MonoBehaviour {

    // Use this for initialization
    void Start () {
        Button btn = this.GetComponent<Button> ();
        EventTrigger trigger = btn.gameObject.GetComponent<EventTrigger> ();
        EventTrigger.Entry entry = new EventTrigger.Entry ();
        // 鼠标点击事件
        entry.eventID = EventTriggerType.PointerClick;
        // 鼠标进入事件 entry.eventID = EventTriggerType.PointerEnter;
        // 鼠标滑出事件 entry.eventID = EventTriggerType.PointerExit;
        entry.callback = new EventTrigger.TriggerEvent ();
        entry.callback.AddListener (OnClick);
        // entry.callback.AddListener (OnMouseEnter);
        trigger.triggers.Add (entry);
    }

    private void OnClick(BaseEventData pointData){
        Debug.Log ("Button Clicked. EventTrigger..");
    }

    private void OnMouseEnter(BaseEventData pointData){
        Debug.Log ("Button Enter. EventTrigger..");
    }
}

4. 通过 MonoBehaviour 实现事件类接口来实现事件的监听 #

Step 1 : 通过 Hierarchy 面板创建 UI > Button.

Step 2 : 创建一个 EventHandler.cs 脚本.

Step 3 : 将脚本绑定在 Button 对象上.

Step 4 : Done.

EventHandler.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class EventHandler : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IDragHandler {

    public void OnPointerClick(PointerEventData eventData){
        if(eventData.pointerId == -1){
            Debug.Log ("Left Mouse Clicked.");
        } else if(eventData.pointerId == -2){
            Debug.Log ("Right Mouse Clicked.");
        }
    }

    public void OnPointerEnter(PointerEventData eventData){
        Debug.Log ("Pointer Enter..");
    }

    public void OnPointerExit(PointerEventData eventData){
        Debug.Log ("Pointer Exit..");
    }

    public void OnPointerDown(PointerEventData eventData){
        Debug.Log ("Pointer Down..");
    }

    public void OnDrag(PointerEventData eventData){
        Debug.Log ("Dragged..");
    }

}

UGUI 如何判断 UI 元素被点击时是鼠标的哪个按键, 上面的代码中我们可以根据 eventData.pointerId 来监听是鼠标左键还是右键. 但是每个 UI 元素都创建一个 MonoBehaviour 来监听各个事件显然不好, 下面是通过利用 Delegate 和 Event 来做一个通用类 UIEventListener 来处理事件 (观察者模式).

UIEventListener.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UIEventListener : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler {

    // 定义事件代理
    public delegate void UIEventProxy(GameObject gb);

    // 鼠标点击事件
    public event UIEventProxy OnClick;

    // 鼠标进入事件
    public event UIEventProxy OnMouseEnter;

    // 鼠标滑出事件
    public event UIEventProxy OnMouseExit;

    public void OnPointerClick(PointerEventData eventData){
        if (OnClick != null)
            OnClick (this.gameObject);
    }

    public void OnPointerEnter(PointerEventData eventData){
        if (OnMouseEnter != null)
            OnMouseEnter (this.gameObject);
    }

    public void OnPointerExit(PointerEventData eventData){
        if (OnMouseExit != null)
            OnMouseExit (this.gameObject);
    }

}

TestEvent.cs

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

public class TestEvent : MonoBehaviour {

    void Start () {
        Button btn = this.GetComponent<Button> ();
        UIEventListener btnListener = btn.gameObject.AddComponent<UIEventListener> ();

        btnListener.OnClick += delegate(GameObject gb) {
            Debug.Log(gb.name + " OnClick");
        };

        btnListener.OnMouseEnter += delegate(GameObject gb) {
            Debug.Log(gb.name + " OnMouseEnter");
        };

        btnListener.OnMouseExit += delegate(GameObject gb) {
            Debug.Log(gb.name + " OnMOuseExit");
        };
    }

}

TestEvent 脚本绑定在 Button 上即可.


Project 结构

代码 : Here

End.

分类: ScriptC#,Unity3D
标签: UGUI
2019-10-28 16:12:29 qq_39339846 阅读数 8

【Unity 3D事件优化】

公司项目开发中,大部分函数功能回调都是通过注册,派发事件实现的。将回调的一个或多个对象方法绑定某个事件,当派发该事件时,绑定该事件的一个或多个对象接收到该事件后调用对应的方法。模式属于:一对一或一对多。这样的模式在处理大多数事件情况非常得体。
最近接策划的一个案子,大体功能是组队功能界面的多个队员item,实时显示更新队员的血量。项目中所有玩家的血量改变都通过一个SM_HealthChange协议,该协议包含要改变血量的玩家Id号和改变的血量值。接收到这个协议,通过该协议的Id号,获取对应玩家的entity实体table表,然后调用该entity的setHp函数处理血量。开始想到的组队界面血量同步方法是:沿用项目已有的事件系统,所有队员先注册血量改变事件,当接收SM_HealthChange协议时,发送血量改变事件同时将改变血量的玩家Id号和改变的血量值作为参数传递。之前注册了血量改变事件的队员接到该事件后,先判断血量改变的玩家id是不是自己的,如果是自己的改变自己的血量显示,否则就不做处理。这样就实现了血量同步方法。
但后面分析存在个问题,只要接到SM_HealthChange协议就发送事件,不管绑定的对象id是不是协议中的玩家id,只要发送事件就得接受,因为事件发送者没法提前判断多个绑定事件的对象谁才是真正要接收的对象,从而造成了不必要的开销消耗。后来采取同事的建议,可以采用c#自带的事件功能event,每个玩家实体entity内创建一个血量改变事件,组队界面每个队员item将对应的玩家entity的血量改变事件和自身的血量更新函数绑定,这样当对应的entity改变血量调用自身的setHp函数时就调用对应组队界面队员item绑定的血量改变函数,实现了谁的血量改变就调用对应玩家的血量同步函数,达到了一对一的事件处理,优化了不必要的开销。
下面上热腾腾的代码

using System;
using System.Collections.Generic;

namespace 深入理解CShape
{
    class Entity
    {
        public delegate void Func(float hp);
        public event Func HP_ChangeEvent;

        public readonly int ID;

        private float hp;

        public Entity(int id)
        {
            ID = id;
        }

        public float HP
        {
            get { return hp; }
            set {
                hp = value;
                Console.WriteLine("玩家{0}的血量改变为{1}", ID, hp);
                HP_ChangeEvent(hp);
            }
        }
    }

    class TeamMember
    {
        public readonly int ID;
        private float m_Hp;

        public TeamMember(int id)
        {
            ID = id;
        }

        public void SynchronousBlood(float hp)
        {
            m_Hp = hp;
            Console.WriteLine("队员{0}改变血量为{1}", ID, hp);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<int, Entity> entityList = new Dictionary<int, Entity>();
            for(int i = 1; i <= 5; ++i)
            {
                entityList.Add(i, new Entity(i));
                TeamMember teamMember = new TeamMember(i);
                Entity entity = entityList[teamMember.ID];
                entity.HP_ChangeEvent += teamMember.SynchronousBlood;
            }

            var iter = entityList.GetEnumerator();
            Random random = new Random();
            while (iter.MoveNext())
            {
                iter.Current.Value.HP = random.Next(50, 100);
                Console.WriteLine();
            }
            Console.ReadLine();
        }
    }
}

运行结果
在这里插入图片描述
这样一对一发送,保证了对应的事件改变发送给对应的监听者,省去了不必要的开销。个人对优化的理解就行,在保障功能不受影响的前提下,重复计算处理的,不需要计算的统统pass,只留下真正起作用的部分,以保障性能开销。

2017-06-26 19:15:26 Mogoson 阅读数 2102

MGS-MechanicalDrive

概述

Unity3D 绑定机械传动 插件包。

需求

  1. 制作啮合齿轮传动机构。
  2. 制作按比例速度同步传动机构。
  3. 制作蜗轮蜗杆传动机构。
  4. 制作皮带飞轮传动机构。
  5. 制作链条齿轮传动机构。

方案

  1. 统一线速度驱动啮合齿轮,齿轮角速度依据齿轮半径计算。
  2. 统一线速度驱动各个机构单元,单元的线速度依据比例计算。
  3. 统一线速度驱动蜗轮蜗杆,蜗杆角速度依据蜗杆半径计算;蜗轮角速度依据蜗杆头数(螺旋线条数)和蜗轮齿数计算。
  4. 统一线速度驱动飞轮,皮带转动速度依据比例计算(保持飞轮与皮带同步);皮带转动使用UV动画实现。
  5. 统一线速度驱动齿轮,链条;链条转动轨迹使用动画曲线AnimationCurve实现。

实现

  • Gear.cs:齿轮,绕Z轴向作圆周运动。
  • Belt.cs:传送带,UV沿X方向移动模拟运转。
  • Chain.cs:链条,由相同的链节点连接而成,依据锚点路径移动和旋转。
  • DynamicChain.cs:动态链条,在Chain的基础上适应路径锚点变化,模拟由于重力,振动等原因导致的链条轨迹变形。
  • RollerChain.cs:滚子链,由两个不同的链节点交替连接而成,依据锚点路径移动和旋转。
  • DynamicRollerChain.cs:动态滚子链,在RollerChain的基础上适应路径锚点变化,模拟由于重力,振动等原因导致的链条轨迹变形。
  • LinearVibrator.cs:线性振动器,沿Z轴向作往复运动。
  • CentrifugalVibrator.cs:离心振动器,绕Z轴向作离心运动。
  • Synchronizer.cs:同步器,统一线速度驱动同步器的所有机构。
  • Transmission.cs:变速器,按指定比例线速度驱动变速器的相应机构,用于协调多个机构的运转。
  • WormGear.cs:绑定蜗轮蜗杆。
  • Engine.cs:引擎,统一驱动所有机构。
  • Damper.cs:阻尼器,模拟引擎启动后加速,停止后减速等效果。

案例

  • “MGS-MechanicalDrive/Scenes”文件夹存有上述传动装置的演示案例供读者参考。
  • “MGS-MechanicalDrive/Prefabs”文件夹存有上述传动装置的绑定预制体,供读者修改复用,以便快速绑定机械传动。

源码

源码托管地址

2018-01-31 19:41:19 YuAnHandSome 阅读数 1479

Unity UI EventTrigger 动态添加UI事件

UI中点击、按下、抬起、进入、退出、拖拽等事件,可以引用各自的接口,实现接口中的方法来完成相应需求。但是如果一个对象身上要完成很多事件,引用大量接口就显得麻烦了。为了避免引用借口过多,实现动态绑定事件可以用EventTrigger组件来完成。下面给大家演示一下EventTrigger组件的使用方法,以及如何在代码里动态添加所需的事件。

EventTrigger的在Inspector中使用

EventTrigger在Inspector面板的属性:在代码中写好对应事件的方法,选出要添加Event Type,像Button一样把方法拖拽到对应的EventType上即可,如下图:

EventTrigger的在带代码动态绑定事件使用

代码中动态创建要有以下几个步骤:
1、实例化所有委托的列表
2、新建所需的事件
3、注册eventID
4、新建callback
5、设置对应事件的内容
6、绑定事件
7、把事件添加到委托列表

以上7步是EventTrigger动态添加事件的步骤,按照步骤来就很容易了。
下面是演示效果

EventTrigger用好动态添加事件,会很方便,省去很多接口,随便一个UI控件加上EventTrigger组件后,所有的交互都可以很容易的完成。下面附上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// using namespace
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class EventTriggerTest : MonoBehaviour {

    Text testT;
    EventTrigger testET;
    private void Start()
    {
        testT = transform.Find("Text").GetComponent<Text>();
        
        testET = gameObject.GetComponent<EventTrigger>();
        if (testET == null)
            testET = gameObject.AddComponent<EventTrigger>();

        // 实例化委托列表
        testET.triggers = new List<EventTrigger.Entry>();

        // 注册事件
        EventTrigger.Entry entryPointerEnter = new EventTrigger.Entry();
        EventTrigger.Entry entryPointerExit = new EventTrigger.Entry();
        EventTrigger.Entry entryPointerDown = new EventTrigger.Entry();
        EventTrigger.Entry entryPointerUp = new EventTrigger.Entry();
        EventTrigger.Entry entryDrag = new EventTrigger.Entry();

        // 实例化eventID
        entryPointerEnter.eventID = EventTriggerType.PointerEnter;
        entryPointerExit.eventID = EventTriggerType.PointerExit;
        entryPointerDown.eventID = EventTriggerType.PointerDown;
        entryPointerUp.eventID = EventTriggerType.PointerUp;
        entryDrag.eventID = EventTriggerType.Drag;

        // 实例化callback
        entryPointerEnter.callback = new EventTrigger.TriggerEvent();
        entryPointerExit.callback = new EventTrigger.TriggerEvent();
        entryPointerDown.callback = new EventTrigger.TriggerEvent();
        entryPointerUp.callback = new EventTrigger.TriggerEvent();
        entryDrag.callback = new EventTrigger.TriggerEvent();

        // 设置事件
        UnityAction<BaseEventData> pointerEnterCB = new UnityAction<BaseEventData>(OnPointerEnterCBTarget);
        UnityAction<BaseEventData> pointerExitCB = new UnityAction<BaseEventData>(OnPointerExitCBTarget);
        UnityAction<BaseEventData> pointerDownCB = new UnityAction<BaseEventData>(OnPointerDownCBTarget);
        UnityAction<BaseEventData> pointerUpCB = new UnityAction<BaseEventData>(OnPointerUpCBTarget);
        UnityAction<BaseEventData> DragCB = new UnityAction<BaseEventData>(OnDragCBTarget);

        // 绑定事件
        entryPointerEnter.callback.AddListener(pointerEnterCB);
        entryPointerExit.callback.AddListener(pointerExitCB);
        entryPointerDown.callback.AddListener(pointerDownCB);
        entryPointerUp.callback.AddListener(pointerUpCB);
        entryDrag.callback.AddListener(DragCB);

        // 添加到委托列表
        testET.triggers.Add(entryPointerEnter);
        testET.triggers.Add(entryPointerExit);
        testET.triggers.Add(entryPointerDown);
        testET.triggers.Add(entryPointerUp);
        testET.triggers.Add(entryDrag);
    }
    // 进入 要做的事
    void OnPointerEnterCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerEnter";
        Debug.Log("write here when PointerDown");
    }
    // 离开 要做的事
    void OnPointerExitCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerExit";
        Debug.Log("write here when PointerExit");
    }
    // 按下 要做的事
    void OnPointerDownCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerDown";
        Debug.Log("write here when PointerDown");
    }
    // 抬起 要做的事
    void OnPointerUpCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerUp";
        Debug.Log("write here when PointerUp");
    }
    // 点击 要做的事
    void OnDragCBTarget(BaseEventData baseEventData)
    {
        transform.position = Input.mousePosition;
        testT.text = "Drag:" + Input.mousePosition;
        Debug.Log("write here when PointerClick");
    }
}

其他

更多Blog请见:https://yiyuan1130.github.io/
Github地址:https://github.com/yiyuan1130

没有更多推荐了,返回首页