Unity事件和委托心得

Unity事件,委托

最主要的作用是消息传递,倒无所谓其他什么代码效率之类的考虑,遇到什么监听的情况,比如鼠标有没有单击,某一个敌人是不是死亡,摄像机是不是还在启动这些事,还是得靠update去拿每一帧检测。

既然是消息传递,必然涉及两个类或者说是两个C#脚本。

具体使用方法: 先定义一个委托 public event Action<string> onCameraPositionChanged;

有人要问了委托不是delegate吗,这个event Action是什么?

Action是一个预定义的委托类型,它可以表示一个没有参数和返回值的方法。

event具有一些特定的限制和语法要求,使其更安全、封装和易于使用。

  1. event只能在类的内部定义和触发,不能在外部直接访问或触发。
  2. event不能被继承类重写,是只读的,无法直接赋值或清空。
  3. event的触发方法只能使用+=-=运算符进行订阅和取消订阅,不能直接调用。

以上三条大概看看就行了,真正写代码的时候写错了编译器会提醒你的

public event Action<string> onCameraPositionChanged;

public const int a;

所以这句代码的意思是,onCameraPositionChanged是一个event,类似const,static这样的关键字,限定了onCameraPositionChanged的一些功能。onCameraPositionChanged的具体类型是一个事件Action。对比一下int a的定义就完全理解了。

如果不是在Unity里,是完全C#编码的话,也经常能在其他博客里看到以下写法

public event delegate onCameraPositionChanged(string);

event加上就是一个有限制的委托,event不加上就是一个纯自定义的委托。

好,现在拐回去,说消息传递的事。

这东西最主要的作用通过订阅在两个C#文件之间进行消息传递。一定要记住用的这个东西了肯定是两个文件之间的事了,两个文件!一个文件也行,一个文件里那就有两个类,不过这样印象不深刻。

----------------------------.cs文件1-----------------------
----------------------------.cs文件1-----------------------
----------------------------.cs文件1-----------------------
using UnityEngine;
using System;

public class 脚本1: MonoBehaviour
{
    public Camera camera;
    public event Action<bool> onCameraPositionChanged; // 声明一个带参数的事件委托

    private void update()
    {
        Vector3 cameraPosition = camera.transform.position;

        if (cameraPosition == new Vector3(1f, 0f, 0f))
        {
            // 触发事件并传递参数
            onCameraPositionChanged?.Invoke(true);
        }
    }
}

好,在文件1里面把委托都定义好了,现在再去文件2里操作

onCameraPositionChanged?.Invoke(true);简介一下这句代码的意思,?是自动判空,这里判空不是判onCameraPositionChanged本身是不是空,是判断有没有函数订阅这个委托,如果有才执行Invoke,执行Invoke的意思就是正式的执行这个委托了,正式的执行这个委托了会发生什么在文件2里会说明。括号里面自然是普通的传参,毕竟之前定义的Action就有bool的参数。

--------------------------.cs文件2-----------------------------
--------------------------.cs文件2-----------------------------
--------------------------.cs文件2-----------------------------
using UnityEngine;

public class 脚本2: MonoBehaviour
{
    private void Start()
    {
        脚本1 positionChecker = GetComponent<脚本1>();
        positionChecker.onCameraPositionChanged += HandleCameraPositionChanged;
    }

    private void HandleCameraPositionChanged(bool flag)
    {
        if (flag==true)
        {
            Debug.Log("Camera position is (1, 0, 0).");
            // 在这里执行其他需要的操作
        }
    }
}

好,现在文件2也写好了。在文件2里面的Start()里面我们先get到了脚本1

positionChecker.onCameraPositionChanged += HandleCameraPositionChanged;

然后把脚本1的委托注册了一个函数叫HandleCameraPositionChanged。函数HandleCameraPositionChanged里面的内容就是我们真正要做的事情。

这样文件1里正式执行委托时,也就是Invoke时,真正执行的是函数HandleCameraPositionChanged或者其他一切注册到委托OnCameraPositionChanged上的函数。此时完成了消息传递的效果。

那么好了好了,你问哪里完成消息传递的效果了?这有两层意思

第一层是脚本2中的函数由脚本1来控制具体执行的时机了,通过注册这个机制,脚本1可以同时控制很多其他脚本里函数的执行了,只需要onCameraPositionChanged +=就行了

第二层是Action<bool>的参数传递过去了,函数参数可以携带很多信息。

下面是题外话,加深理解的话

可以想一想如果不搞这么复杂,又是这个又那个的,我不就是要看一下当前相机位置是不是在(1f,0f,0f)位置吗。

我在文件1里面新增一个bool flag,然后每次更新flag的值

反正我在文件2里面都已经get到脚本1了,GetComponent这一步也没少啊

直接用

if(脚本1.flag)

不也一样。我觉得也一样,所以我没怎么用过委托,我能想到的就是如果这个flag必须是private的时候就需要用这个办法了,其他的角度那只能是考虑到代码更灵活、可扩展和可维护这些内容了,Unity学多的人可能爱用这个东西吧,反正我用的少。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值