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();
    }
}
相关推荐
mxwin1 天前
Unity Shader Alpha测试 · 模板测试 · 深度测试
unity·游戏引擎
Sator11 天前
unity解决粒子与物体接触时的硬边缘问题
unity·游戏引擎
程序员JerrySUN1 天前
Jetson边缘嵌入式实战课程第三讲:L4T 与 Jetson 系统架构
linux·服务器·人工智能·安全·unity·系统架构·游戏引擎
萌萌的提莫队长1 天前
Unity HDRP 渲染管线 Camera 输出到RenderTexture没有Alpha通道
unity·游戏引擎
winlife_1 天前
Unity Editor 工具不该用反射写组件字段:SerializedObject 在 4 个场景里非用不可
unity·自动化·游戏引擎
星河耀银海1 天前
Unity C#入门:变量的定义与访问权限(public/private)
unity·c#·lucene
郝学胜-神的一滴1 天前
中级OpenGL教程 005:为球体&平面注入法线灵魂
c++·unity·图形渲染·three.js·opengl·unreal
那个村的李富贵1 天前
unity编辑器工具,输出使用的字体
unity·编辑器·游戏引擎
游乐码2 天前
UnityGUI(五)GUI控件综合使用
开发语言·unity·c#
LF男男2 天前
TshitBullect.cs
unity