快速开始
安装
主包:
dotnet add package QfStudio.Godette.ReactiveUI推荐的可选包能改善开发体验:
- GodotSharp.SourceGenerators —— 提供
[SceneTree]特性,用于类型安全的场景加载以及无需GetNode调用的强类型节点访问。 - ReactiveUI.SourceGenerators —— 提供
[Reactive]特性,为 partial 属性自动生成RaiseAndSetIfChanged样板代码。
dotnet add package GodotSharp.SourceGenerators
dotnet add package ReactiveUI.SourceGenerators使用 [SceneTree] 标注 .tscn 根脚本后,可获得:
- 一个
TscnFilePath静态属性,用于类型安全的场景加载。 - 为标记了
unique_name_in_owner的节点生成强类型字段 —— 无需GetNode调用。
// 使用 [SceneTree] — 节点可直接作为属性访问
[SceneTree(root: "_root")]
public partial class MyScene : Control
{
public override void _Ready()
{
BackButton.Pressed += () => GetTree().ChangeSceneToFile(HomeScene.TscnFilePath);
NameEdit.Text = "hello";
}
}// 不使用 [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";
}
}// 使用 [Reactive]
public partial class MyViewModel : ReactiveObject
{
[Reactive] public partial string Name { get; set; } = "";
}// 不使用 [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:
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 平台服务(GodotActivationFetcher、GodotPropertyBinder、GodotPollBasedPropertyBinder、GodotCommandBinder)。它也会调用 WithCoreServices() 准备好 ReactiveUI 核心服务,因此无需自行调用。float↔double 绑定转换器和 GodotViewLocator 的注册都是可选、需显式启用的:转换器通过 .WithGodotConverters()、视图定位器通过 .WithGodotViewLocator(...)(见下文)启用——二者都不在 WithGodot 内。
在 Godot 编辑器中,进入 项目 > 项目设置 > Autoload,将该脚本以 RxAppBootstrapper 之类的名称添加为 Autoload。
RxAppBuilder.BuildApp() 会将通过 .WithMainThreadScheduler(...) 注册的调度器同步到 ReactiveUI 的 RxSchedulers.MainThreadScheduler,因此 ObserveOn(RxSchedulers.MainThreadScheduler) 会解析为这里设置的同一个 GodotMainThreadScheduler。GodotSchedulers 是同一组实例在 Godot 侧的别名,供帧运算符及其他 Godot 专用 API 使用。
NOTE
若不调用 .WithGodotConverters()(即不注册 FloatToDoubleConverter / DoubleToFloatConverter),那么在暴露 double 属性的 Godot 控件(例如 Range.Value、ColorPicker.Color)与 ViewModel 的 float 属性之间建立绑定时,会在绑定时抛出 ConverterNotFoundException。本库还附带 EnumToStringConverter<TEnum>、StringToEnumConverter<TEnum> 以及 Variant 与基元类型互转的转换器 —— 在上面的 builder 中通过 .WithConverter(...) 注册你需要的那部分即可。