Skip to content

快速开始

安装

主包:

shell
dotnet add package QfStudio.Godette.ReactiveUI

推荐的可选包能改善开发体验:

  • GodotSharp.SourceGenerators —— 提供 [SceneTree] 特性,用于类型安全的场景加载以及无需 GetNode 调用的强类型节点访问。
  • ReactiveUI.SourceGenerators —— 提供 [Reactive] 特性,为 partial 属性自动生成 RaiseAndSetIfChanged 样板代码。
shell
dotnet add package GodotSharp.SourceGenerators
dotnet add package ReactiveUI.SourceGenerators

使用 [SceneTree] 标注 .tscn 根脚本后,可获得:

  • 一个 TscnFilePath 静态属性,用于类型安全的场景加载。
  • 为标记了 unique_name_in_owner 的节点生成强类型字段 —— 无需 GetNode 调用。
csharp
// 使用 [SceneTree] — 节点可直接作为属性访问
[SceneTree(root: "_root")]
public partial class MyScene : Control
{
    public override void _Ready()
    {
        BackButton.Pressed += () => GetTree().ChangeSceneToFile(HomeScene.TscnFilePath);
        NameEdit.Text = "hello";
    }
}
csharp
// 不使用 [SceneTree] — 需要通过字符串路径调用 GetNode
public partial class MyScene : Control
{
    public override void _Ready()
    {
        GetNode<Button>("BackButton").Pressed += () =>
            GetTree().ChangeSceneToFile("res://Views/HomeScene.tscn");
        GetNode<LineEdit>("NameEdit").Text = "hello";
    }
}
csharp
// 使用 [Reactive]
public partial class MyViewModel : ReactiveObject
{
    [Reactive] public partial string Name { get; set; } = "";
}
csharp
// 不使用 [Reactive] — 手动编写 backing field + RaiseAndSetIfChanged
public class MyViewModel : ReactiveObject
{
    private string _name = "";
    public string Name
    {
        get => _name;
        set => this.RaiseAndSetIfChanged(ref _name, value);
    }
}

Autoload 配置

创建一个引导类来初始化 ReactiveUI 服务,并将其在 Godot 中注册为 Autoload:

csharp
using Godot;
using QfStudio.Godette.ReactiveUI;
using ReactiveUI.Builder;

public partial class RxAppBootstrapper : Godot.Node
{
    private readonly GodotFrameScheduler _processFrameScheduler = new();
    private readonly GodotFrameScheduler _physicsFrameScheduler = new();

    public RxAppBootstrapper()
    {
        RxAppBuilder.CreateReactiveUIBuilder()
            .WithGodot(_processFrameScheduler, _physicsFrameScheduler)
            .WithGodotConverters()
            .WithGodotViewLocator(locator =>
            {
                locator.RegisterViewsFromAssemblyViaReflection(typeof(RxAppBootstrapper).Assembly, verbose: false);
            })
            .BuildApp();
    }

    public override void _Process(double delta) => _processFrameScheduler.NotifyProcess(delta);

    public override void _PhysicsProcess(double delta) => _physicsFrameScheduler.NotifyProcess(delta);
}

WithGodot(processFrameScheduler, physicsFrameScheduler) 负责搭建 Godot 平台:它基于 SynchronizationContext.Current 创建主线程调度器,通过 GodotSchedulers 暴露全部三个调度器,并借助 GodotRegistrations 注册 Godot 平台服务(GodotActivationFetcherGodotPropertyBinderGodotPollBasedPropertyBinderGodotCommandBinder)。它也会调用 WithCoreServices() 准备好 ReactiveUI 核心服务,因此无需自行调用。float↔double 绑定转换器和 GodotViewLocator 的注册都是可选、需显式启用的:转换器通过 .WithGodotConverters()、视图定位器通过 .WithGodotViewLocator(...)(见下文)启用——二者都不在 WithGodot 内。

在 Godot 编辑器中,进入 项目 > 项目设置 > Autoload,将该脚本以 RxAppBootstrapper 之类的名称添加为 Autoload。

RxAppBuilder.BuildApp() 会将通过 .WithMainThreadScheduler(...) 注册的调度器同步到 ReactiveUI 的 RxSchedulers.MainThreadScheduler,因此 ObserveOn(RxSchedulers.MainThreadScheduler) 会解析为这里设置的同一个 GodotMainThreadSchedulerGodotSchedulers 是同一组实例在 Godot 侧的别名,供帧运算符及其他 Godot 专用 API 使用。

NOTE

若不调用 .WithGodotConverters()(即不注册 FloatToDoubleConverter / DoubleToFloatConverter),那么在暴露 double 属性的 Godot 控件(例如 Range.ValueColorPicker.Color)与 ViewModel 的 float 属性之间建立绑定时,会在绑定时抛出 ConverterNotFoundException。本库还附带 EnumToStringConverter<TEnum>StringToEnumConverter<TEnum> 以及 Variant 与基元类型互转的转换器 —— 在上面的 builder 中通过 .WithConverter(...) 注册你需要的那部分即可。