Unity自我实现响应式属性

news2024/11/15 18:57:40

        其实只是写着玩,响应式编程建议使用UniRx插件(一套成熟的响应式编程解决方案),我写的主要是借鉴一下这个思想,实现的也不够优雅,不过逻辑也算严密可以正常使用.你可以查看我写的理解响应式属性的思想.

        借鉴UniRx的ReactiveProperty类,且UniRx不仅有响应式属性.

using System;
using System.Linq;

/// <summary>
/// 当值发生变化时触发回调(例如当玩家血量变化时更新GUI)。
/// </summary>
public class ReactiveValue<T>
{
    /// <summary>
    /// 定义过滤器委托,允许在设置新值时对值进行过滤或修正。
    /// </summary>
    private delegate T Filter(T originalValue, T newValue);

    /// <summary>
    /// 值变化时的回调委托。
    /// </summary>
    private Action<T> m_Set;

    /// <summary>
    /// 用于处理值变化前的过滤器。
    /// </summary>
    private Filter m_Filter;

    /// <summary>
    /// 当前的值。
    /// </summary>
    private T m_CurrentValue;

    /// <summary>
    /// 上一次的值,仅供内部使用。
    /// </summary>
    private T m_LastValue;

    /// <summary>
    /// 初始化值。
    /// </summary>
    /// <param name="initialValue">初始值。</param>
    public ReactiveValue(T initialValue)
    {
        m_CurrentValue = initialValue;
        m_LastValue = m_CurrentValue;
    }
    /// <summary>
    /// 使用T的默认值初始化值
    /// </summary>
    public ReactiveValue() : this(default(T)) { }

    /// <summary>
    /// 判断当前值是否等于指定值。
    /// </summary>
    /// <param name="value">要比较的值。</param>
    /// <returns>如果当前值等于指定值,返回 true;否则返回 false。</returns>
    public bool IsEquals(T value)
    {
        return m_CurrentValue != null && m_CurrentValue.Equals(value);
    }

    /// <summary>
    /// 添加一个回调
    /// </summary>
    /// <param name="callback">回调</param>
    /// <param name="immediateCall">添加了回调是否立即调用</param>
    public void AddChangeListener(Action<T> callback, bool immediateCall = false)
    {

        if (m_Set == null || !m_Set.GetInvocationList().Contains(callback))
        {
            m_Set += callback;
            if (immediateCall)
            {
                callback?.Invoke(m_CurrentValue);
            }
        }
    }

    /// <summary>
    /// 移除指定的监听器。
    /// </summary>
    /// <param name="callback">要移除的回调函数。</param>
    public void RemoveChangeListener(Action<T> callback)
    {
        if (m_Set != null && m_Set.GetInvocationList().Contains(callback))
        {
            m_Set -= callback;
        }
    }

    /// <summary>
    /// 移除所有的监听器,谨慎使用,因为别人也进行了订阅
    /// </summary>
    public void RemoveAllChangeListeners()
    {
        m_Set = null;
    }

    /// <summary>
    /// 设置过滤器,过滤器将在回调前被调用,适合用于值限制(如玩家血量不能超过最大值等)。
    /// </summary>
    /// <param name="filter">过滤器委托:<原值,新值,返回值>。</param>
    public void SetFilter(Func<T, T, T> filter)
    {
        m_Filter = new Filter(filter);
    }

    /// <summary>
    /// 获取当前值。
    /// </summary>
    /// <returns>返回当前值。</returns>
    public T Get()
    {
        return m_CurrentValue;
    }

    /// <summary>
    /// 设置新值,只有当新值与旧值不相同时才会触发回调。
    /// </summary>
    /// <param name="value">要设置的新值。</param>
    public void Set(T value)
    {
        m_LastValue = m_CurrentValue;
        m_CurrentValue = value;

        if (m_Filter != null)
            m_CurrentValue = m_Filter(m_LastValue, m_CurrentValue);

        // 当新值和旧值不相等时触发回调
        if (m_LastValue == null || !m_LastValue.Equals(m_CurrentValue))
            m_Set?.Invoke(m_CurrentValue);
    }

    /// <summary>
    /// 强制更新值并触发回调,即使新值与旧值相同。
    /// </summary>
    /// <param name="value">要设置的新值。</param>
    public void SetValueForceCallBack(T value)
    {
        m_LastValue = m_CurrentValue;
        m_CurrentValue = value;

        if (m_Filter != null)
            m_CurrentValue = m_Filter(m_LastValue, m_CurrentValue);

        // 强制触发回调
        m_Set?.Invoke(m_CurrentValue);
    }

    /// <summary>
    /// 设置新值但不触发回调。
    /// </summary>
    /// <param name="value">要设置的新值。</param>
    public void SetValueDontCallBack(T value)
    {
        m_LastValue = m_CurrentValue;
        m_CurrentValue = value;

        if (m_Filter != null)
            m_CurrentValue = m_Filter(m_LastValue, m_CurrentValue);
    }
}




示例用法

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

public class Test : MonoBehaviour
{
    public Text textComponent;
    //一般会声明在数据层,可以优雅地实现MVC等框架,这里为了方便
    ReactiveValue<string> t = new ReactiveValue<string>("张三");
    void Start()
    {
        t.AddChangeListener(Handle, true);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (t.IsEquals("张三"))
            {
                t.Set("李四");
            }
            else
            {
                t.Set("张三");
            }
        }
    }

    void Handle(string t)
    {
        textComponent.text = t;
    }
    private void OnDestroy()
    {
        t.RemoveChangeListener(Handle);
    }
}

UniRx实现

如果使用UniRx实现的话非常优雅.

AddTo的意思就是绑定了这个gameObject对象,当这个对象被销毁那么自动移除这个对象绑定的回调,就不需要傻傻的在OnDestroy中移除了,并且也可以使用匿名函数.

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

public class Test : MonoBehaviour
{
    public Text textComponent;
    ReactiveProperty<string> t = new ReactiveProperty<string>("张三");
    void Start()
    {
        t.Subscribe(t => textComponent.text = t).AddTo(gameObject);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (t.Value == "张三")
            {
                t.Value = "李四";
            }
            else
            {
                t.Value = "张三";
            }
        }
    }


}

实际是动态为gameObject对象动态添加了一个

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2154628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光伏板缺陷红外检测数据集

光伏板缺陷红外检测数据集 包含以下4个数据文件&#xff1a; /train&#xff1a;训练集 /valid&#xff1a;验证集 /test&#xff1a;测试集 README.txt&#xff1a;数据说明 【数据说明】检测目标以Pascal VOC格式进行标注&#xff0c;对每个图像进行以下预处理&#xff0c;统…

【Linux笔记】如何将内容从一个文件复制到另一个文件

比如&#xff1a;将文件tmp_file.txt中的部分数据&#xff0c;复制到file01.txt中去 tmp_file.txt文中内容&#xff1a; file01.txt为空文档 一、使用vi编辑器 I、文件中直接使用:e 目标文件进行切换文件复制 1、打开被复制文件 vi tmp_file.txt 2、进入一般命令模式 默认情况为…

2024年华为杯-研赛更新时间轴-资料分享

本次 助攻CDF题 问题一二三问均已完成更新&#xff0c;更新计划轴如图所示 由于赛题之间存在紧密的联系&#xff0c;单独发布问题一二&#xff0c;有可能与明天最终论文不相符&#xff0c;会根据后面问题对前面几问进行调整。个人建议&#xff0c;等明天上午的完整论文即可 题 …

ACT训练调参技巧

ACT Tuning Tips 这里是针对斯坦福Aloha机械臂远程训练调参技巧的中文解释&#xff0c;初学者可能会对此感到陌生&#xff0c;不过不用担心&#xff0c;多尝试&#xff0c;多实验。 - Chunk size is the most important param to tune when applying ACT to a new environment…

【YOLO目标检测学生课堂行为数据集】共4266张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;4266 标注数量(txt文件个数)&#xff1a;4266 标注类别数&#xff1a;3 标注类别名称&#xff1a;hand、read、write 数据集下载&#xff1a;学生课堂行为数据集 图片示例 数据集图片&#…

HTML5中新增元素介绍

引入了许多新元素&#xff0c;以增强网页的语义和功能。这些新元素大致可以按以下几类进行分类和介绍。 下面是对各标签的详解&#xff0c;section、header、footer、nav、article、aside、figure、code、dialog、meter、time、progress、video、audio、details、atagrid、menu…

AIGC7: 高通骁龙AIPC开发者沙龙过程记录A

图中是一座高耸的宫殿。 就像AI的出现&#xff0c;慢慢初现端倪&#xff0c;头角峥嵘。 背景 一直以来都比较关注AI的发展&#xff0c;有幸再一次参加异常AI的盛会。 从我的角度看。 高通是一家生产芯片的公司&#xff0c;国内的小米&#xff0c;荣耀&#xff0c;Oppo , Vi…

Qt_窗口界面QMainWindow的介绍

目录 1、菜单栏QMenuBar 1.1 使用QMainWindow的准备工作 1.2 在ui文件中设计窗口 1.3 在代码中设计窗口 1.4 实现点击菜单项的反馈 1.5 菜单中设置快捷键 1.6 菜单中添加子菜单 1.7 菜单项中添加分割线和图标 1.8 关于菜单栏创建方式的讨论 2、工具栏QToolBar …

[产品管理-32]:NPDP新产品开发 - 30 - 文化、团队与领导力 - 领导力与团队的可持续发展

目录 一、团队领导的领导力 1.1 领导力 1、领导力的定义 2、领导力的重要性 3、领导力的构成要素 4、如何提升领导力 1.2 情商 二、虚拟团队 1、团队定义与特征 2、团队优势 3、团队挑战与应对策略 三、可持续发展 四、团队管理和领导力中的度量指标 4.1 激励创新…

unix中的进程标识以及使用场景

一、前言 本文将介绍unix系统中的进程标识以及使用场景。进程标识和用户标识类似&#xff0c;只不过其指代的对象是一个进程。我们常把进程标识称为进程ID&#xff0c;本文将讨论如下内容&#xff1a; 1.什么是进程标识&#xff1f; 2.特殊的进程标识 3.如果获取以及使用进程标…

深度学习02-pytorch-09(pytorch完结篇)-基本使用介绍-线性回归案例

使用PyTorch的基本流程&#xff1a;数据准备&#xff1a;通过make_regression生成回归数据&#xff0c;使用 TensorDataset 和 DataLoader 来封装数据。 模型定义&#xff1a;使用 nn.Module 或内置层&#xff08;如 nn.Linear&#xff09;来定义模型结构。 损失函数和优化器…

【全网最全】2024年华为杯研赛D题成品论文获取入口(后续会更新)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片&#xff0c;那是获取资料的入口&#xff01; 点击链接加入【2024华为杯研赛资料汇总】&#xff1a;https://qm.qq.com/q/XzdIsvbiM0https://qm.qq.com/q/XzdIsvbiM0 你是否在寻找数学建模比赛的突破点…

【他山之石】优化 JavaScript 的乐趣与价值(下)

前言 继本文的 上篇 发表之后&#xff0c;没想到反响还挺好&#xff0c;看来大家在 JS 优化的问题上越来越注重“与国际接轨”了。一起来看本文的下篇&#xff0c;也是干货满满。 文章目录 6. Avoid large objectsWhat the eff should I do about this? 7. Use eval8. Use str…

多元形式助力商业价值最大化,王鹤棣商业影响力遥遥领先

明星商业代言层出不穷&#xff0c;但在个人影响力的升级玩法上&#xff0c;当代青年偶像王鹤棣以其独特的个人魅力和卓越的商业头脑&#xff0c;正逐步搭建起一个以个人形象为核心&#xff0c;与各大品牌相互成就的立体商业模型。通过一系列创新的商务合作模式&#xff0c;王鹤…

[Java并发编程] synchronized(含与ReentrantLock的区别)

文章目录 1. synchronized与ReentrantLock的区别2. synchronized的作用3. synchronized的使用3.1 修饰实例方法&#xff0c;作用于当前实例&#xff0c;进入同步代码前需要先获取实例的锁3.2 修饰静态方法&#xff0c;作用于类的Class对象&#xff0c;进入修饰的静态方法前需要…

React组件如何暴露自身的方法

一、研究背景 最近遇到一个如何暴露React组件自身方法的问题。在某些时候&#xff0c;我们需要调用某个组件内部的方法以实现某个功能&#xff0c;因此我们需要了解如何暴露组件内部API的方法。 二、实践过程 本文主要介绍React组件暴露子组件API的方法&#xff0c;以下是实…

2024年研赛-华为杯数模竞赛C题论文首发+论文讲解+代码分享

2024年华为杯-研赛分享资料&#xff08;论文分享部分代码&#xff09;&#xff08;已更新部分代码&#xff09;&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1HGIYjV3lqzUc_3H0vg5H8w 提取码&#xff1a;sxjm 题 目&#xff1a; _基于数据驱动下磁性元件的磁芯损耗建模…

leetcode第十三题:罗马数字转整数

罗马数字包含以下七种字符: I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#x…

OpenCV特征检测(7)角点检测函数goodFeaturesToTrack()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 确定图像上的强角点。 该函数根据 240中所描述的方法查找图像中最显著的角点或者指定图像区域内的最显著角点。 函数使用 cornerMinEigenVal 或…

华南理工大学信息工程高频电子线路课程设计——基于锁相环的调试解调器设计

完整报告链接如下&#xff1a; 通过网盘分享的文件&#xff1a;高频课设报告.docx 链接: https://pan.baidu.com/s/1J83UCDSU0UHcv4ONYxfyhg?pwdzqyr 提取码: zqyr --来自百度网盘超级会员v5的分享 懒得贴上来了&#xff0c;放一下截图。