Unity自我实现响应式属性

ops/2024/9/22 22:51:32/

        其实只是写着玩,响应式编程建议使用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/ops/114449.html

相关文章

Matlab simulink建模与仿真 第十四章(信号输出库)

参考视频&#xff1a;simulink1.1simulink简介_哔哩哔哩_bilibili 一、信号输出库中的模块概览 注&#xff1a;部分模块在第二章中有介绍&#xff0c;本章不再赘述。 二、文件及工作空间模块 1、To File文件模块 &#xff08;1&#xff09;在MATLAB中可用MAT文件对工作区的…

利用Metasploit进行信息收集与扫描

Metasploit之信息收集和扫描 在本文中&#xff0c;我们将学习以下内容 使用Metasploit被动收集信息 使用Metasploit主动收集信息 使用Nmap进行端口扫描 使用db_nmap方式进行端口扫描 使用ARP进行主机发现 UDP服务探测 SMB扫描和枚举 SSH版本扫描 FTP扫描 SMTP枚举 …

单例模式(饿汉式-懒汉式)

我给面试官讲解了单例模式后&#xff0c;他对我竖起了大拇指&#xff01;https://blog.csdn.net/weixin_41949328/article/details/107296517?ops_request_misc%257B%2522request%255Fid%2522%253A%2522FAEE9ABD-432D-416C-98C6-9DD939138DEB%2522%252C%2522scm%2522%253A%252…

MySQL 事件调度器用法解析

MySQL 事件调度器用法解析 在日常的数据库运维与开发实践中&#xff0c;自动化执行任务是一项至关重要的需求&#xff0c;它极大地提升了数据库管理的效率和准确性。这些任务可能包括清理不再需要的历史数据以释放存储空间、更新汇总或统计信息以保持数据的新鲜度&#xff0c;…

设计模式中工厂模式的C语言实现

在C语言中实现工厂模式&#xff08;Factory Pattern&#xff09;通常需要模拟面向对象的编程方式。工厂模式的核心思想是通过工厂函数来创建不同类型的对象&#xff0c;隐藏对象创建的细节。下面是一个简单的工厂模式在C语言中的实现。 工厂模式示例&#xff1a;几何形状工厂 …

数据库提权【笔记总结】

文章目录 UDF提权以有webshell只有数据库权限条件复现msf工具sql语句提权 MOF提权前言条件复现msf工具php脚本提权 sqlserver提权前言条件xp_cmdshell提权复现 沙盒提权介绍复现 Oracle提权靶场搭建执行任意命令复现 通过注入存储过程提权&#xff08;低权限提升至DBA&#xff…

ELK 企业级日志分析系统

1、ELK概述 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 ELK 是 Elasticsearch、Logstash、Kibana 的缩写&#xff0c;这三个工具组合在一…

阿里1688一面总结

首先&#xff0c;面试官进行对业务进行介绍&#xff0c;然后&#xff0c;候选人进行自我介绍。 面试官根据候选人经历进行提问。 候选人针对想了解的事情进行提问。 接下来主要是对面试官的问题进行记录&#xff1a; 在容量管理优化查询逻辑里面&#xff0c;集群及单机信息是…