Unity自我实现响应式属性

news/2024/9/22 23:46:49/

        其实只是写着玩,响应式编程建议使用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 framevoid 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 framevoid Update(){if (Input.GetKeyDown(KeyCode.A)){if (t.Value == "张三"){t.Value = "李四";}else{t.Value = "张三";}}}}

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


http://www.ppmy.cn/news/1529058.html

相关文章

【笔记】第三节 组织与性能

3.1 基本成分 3.2 微观组织特征 0.6-0.8C%碳素钢的组织为珠光体和少量的铁素体。 如何把组织和性能联系起来&#xff1f;德国克虏伯公司的研究——珠光体片间距与渗碳体片层厚度成比例&#xff1a; t s 0 ( ρ 15 ( C % ) − 1 ) ts_0(\frac{\rho}{15(C\%)}-1) ts0​(15(C%)…

分布式计算技术是什么?在数据集成值得作用?

数据是现代科技技术的基础&#xff0c;面对爆炸性数据的增长&#xff0c;要求计算能力要求更高、数据整合和处理更有效&#xff0c;如何应对数据集成带来的挑战&#xff1f;本文将探讨分布式计算技术在数据集成中的优化作用。 一 分布式计算技术。 定义&#xff1a;分布式计算…

[数据结构]无头单向非循环链表的实现与应用

文章目录 一、引言二、线性表的基本概念1、线性表是什么2、链表与顺序表的区别3、无头单向非循环链表 三、无头单向非循环链表的实现1、结构体定义2、初始化3、销毁4、显示5、增删查改 四、分析无头单向非循环链表1、存储方式2、优点3、缺点 五、总结1、练习题2、源代码 一、引…

深度学习----------------------文本预处理

目录 文本预处理读取数据集词源化词表该部分总代码该部分总代码 整合所有功能该部分总代码 文本预处理 文本预处理&#xff1a;把文本当作一个时序序列 将解析文本的常见预处理步骤。 这些步骤通常包括&#xff1a; ①将文本作为字符串加载到内存中。 ②将字符串拆分为词元&…

在线查看 Android 系统源代码 Git repositories on android

在线查看 Android 系统源代码 Git repositories on android 1. Git repositories on android1.1. Android Make Build System1.2. Android Open Source Project Code Review References 1. Git repositories on android https://android.googlesource.com/ 1.1. Android Make …

HarmonyOS鸿蒙开发实战(5.0)自定义全局弹窗实践

鸿蒙HarmonyOS开发实战往期文章必看&#xff1a; HarmonyOS NEXT应用开发性能实践总结 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; 非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&am…

求两个数二进制中不同位的数

//求两个数二进制中不同位的数 //编程实现&#xff1a;两个int&#xff08;32位&#xff09;整数m和n的二进制表达中&#xff0c; //有多少个位&#xff08;bit&#xff09;不同&#xff1f; //输入例子 &#xff1a;1999 2299 //输出例子&#xff1a;7 #include<stdio.h>…

Mac虚拟机Parallels Desktop 20 for Mac破解版发布 完整支持 Windows 11

Parallels Desktop 20 for Mac 破解版是一款虚拟化软件&#xff0c;允许用户在 Mac 设备上运行 Windows 和其他操作系统。Parallels Desktop 20 for Mac 特别适合需要同时使用 macOS 和 Windows 应用的用户&#xff0c;常用于开发、设计、办公等场景。 自从OpenAI推出ChatGPT之…