Unity MVVM UniTask + 轻量级 ReactiveProperty

1. 负责数据绑定的"轻量级 ReactiveProperty"
cs 复制代码
using System;

// 极其轻量、0 GC 负担的响应式属性(示意版)
public class ReactiveProperty<T>
{
    private T _value;
    private Action<T> _onValueChanged;

    public T Value
    {
        get => _value;
        set
        {
            // 如果值没变,就不触发事件(防抖)
            if (Object.Equals(_value, value)) return; 
            _value = value;
            _onValueChanged?.Invoke(_value); // 通知所有订阅者
        }
    }

    public ReactiveProperty(T initialValue = default)
    {
        _value = initialValue;
    }

    // 提供给 UI 绑定的方法,返回一个可解绑的 Action
    public IDisposable Subscribe(Action<T> action)
    {
        _onValueChanged += action;
        action?.Invoke(_value); // 订阅时立刻推送一次当前值,让 UI 初始化
        return new Unsubscriber(() => _onValueChanged -= action);
    }
    
    // 内部类用于优雅解绑
    private class Unsubscriber : IDisposable
    {
        private Action _unsubscribe;
        public Unsubscriber(Action unsubscribe) => _unsubscribe = unsubscribe;
        public void Dispose() => _unsubscribe?.Invoke();
    }
}
Step 1: 编写 ViewModel(数据与逻辑中心)

这里包含了轻量级的状态数据,以及使用 UniTask 编写的线性业务流程。

cs 复制代码
using Cysharp.Threading.Tasks;
using UnityEngine;
using System.Threading;

public class ChestViewModel
{
    // 💡 纯粹的数据流:只负责保存状态,并在改变时向外广播
    public ReactiveProperty<string> ChestStateText { get; } = new ReactiveProperty<string>("点击开启宝箱");
    public ReactiveProperty<bool> IsButtonInteractable { get; } = new ReactiveProperty<bool>(true);

    // 💡 纯粹的控制流:使用 UniTask 串联整个异步逻辑
    // 传入 CancellationToken 是为了防止玩家在开箱中途关掉界面导致的空引用报错
    public async UniTask OpenChestAsync(CancellationToken token)
    {
        // 1. 改变状态:锁定按钮,更新文本
        IsButtonInteractable.Value = false;
        ChestStateText.Value = "宝箱正在开启中...";

        try
        {
            // 2. 等待宝箱抖动动画(等待 1 秒)
            // 魔法:Delay 不会产生任何 GC,且受 Unity TimeScale 影响
            await UniTask.Delay(1000, cancellationToken: token);

            // 3. 模拟网络请求战利品(等待 0.5 秒)
            ChestStateText.Value = "正在连接服务器...";
            await UniTask.Delay(500, cancellationToken: token); 
            string loot = "SSR 传说级大剑!🗡️"; // 假设这是网络返回的数据

            // 4. 最终展示结果
            ChestStateText.Value = $"开启成功!获得:{loot}";
        }
        catch (OperationCanceledException)
        {
            // 玩家中途关闭了界面,任务被优雅取消,不会有任何报错!
            Debug.Log("开箱流程被中断。");
        }
        finally
        {
            // 无论成功还是被取消,最终都可以执行清理逻辑
            IsButtonInteractable.Value = true;
        }
    }
}
Step 2: 编写 View(视图表现层)

UI 脚本现在变得 极其清爽 ,它只做两件事:把数据绑定到 UI 组件上,以及把用户的点击事件转发给 ViewModel。

cs 复制代码
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using System.Threading;

public class ChestView : MonoBehaviour
{
    public Text stateText;
    public Button openButton;

    private ChestViewModel _viewModel;
    private CancellationTokenSource _cts;

    void Start()
    {
        _viewModel = new ChestViewModel();
        _cts = new CancellationTokenSource(); // 用于管理异步任务的生命周期

        // 🌟 1. UI 数据绑定:将 ViewModel 的数据连接到 UI 元素
        _viewModel.ChestStateText.Subscribe(text => stateText.text = text);
        _viewModel.IsButtonInteractable.Subscribe(interactable => openButton.interactable = interactable);

        // 🌟 2. 事件转发:按钮点击触发 ViewModel 的异步流程
        openButton.onClick.AddListener(() =>
        {
            // Fire and Forget (触发并忘记),启动异步任务
            _viewModel.OpenChestAsync(this.GetCancellationTokenOnDestroy()).Forget();
        });
    }

    void OnDestroy()
    {
        // View 销毁时,取消所有正在进行的异步任务,防止内存泄漏或空引用!
        _cts.Cancel();
        _cts.Dispose();
    }
}
相关推荐
叶帆12 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君12 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
会思考的猴子12 天前
Unity VFX 属性 Postion 和 TargetPostion
unity
心前阳光13 天前
Unity资源导入之自动化资源导入
unity·自动化·游戏引擎
心前阳光13 天前
Unity之2021.3.45f2c1发布安卓程序遇到的问题
android·unity·游戏引擎
纪纯13 天前
PicoVR Unity Integration SDK 3.4 常用交互API
unity·游戏引擎·vr·pico
龙智DevSecOps解决方案13 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
葛兰岱尔13 天前
从 SolidWorks 到 Three.js,从 Inventor 到 Unity——制造业CAD模型“几何-语义一体化“转换,不再是天方夜谭!
开发语言·javascript·unity
玉夏13 天前
【Shader基础】UV 与纹理采样 Part1
unity·着色器·uv
zdr尽职尽责13 天前
Unity录像功能
学习·ui·unity·游戏引擎