現在プレビューリリースされている Rx ライブラリR3。Unity の R3.Unity にはUI用便利拡張メソッド群の UnityUIComponentExtensions が用意されているが、Godot にはなかった。
ver.0.1.6 までは。
PRを出して無事マージしてもらい、Godot でも同じような感じのものが利用できるようになった(ver. 0.1.7~)。動作確認をとったものがショーケースに流用できると思ったので、以下に動画とコードを貼って記事に。
(apng なので表示・再生できないことがあるかもしれない)
public partial class UiShowcase : Node2D { private readonly CancellationTokenSource cts = new(); public override void _Ready() { var button = GetNode<Button>("Button"); var label = GetNode<Label>("Label"); var toggleButton = GetNode<Button>("ToggleButton"); var label2 = GetNode<Label>("Label2"); var checkButton = GetNode<CheckButton>("CheckButton"); var label3 = GetNode<Label>("Label3"); var slider = GetNode<HSlider>("HSlider"); var label4 = GetNode<Label>("Label4"); var spinBox = GetNode<SpinBox>("SpinBox"); var label5 = GetNode<Label>("Label5"); var lineEdit = GetNode<LineEdit>("LineEdit"); var label6 = GetNode<Label>("Label6"); var lineEdit2 = GetNode<LineEdit>("LineEdit2"); var label7 = GetNode<Label>("Label7"); var textEdit = GetNode<TextEdit>("TextEdit"); var label8 = GetNode<Label>("Label8"); var optionButton = GetNode<OptionButton>("OptionButton"); var label9 = GetNode<Label>("Label9"); var countSubscriptionsButton = GetNode<Button>("CountSubscriptionsButton"); var labelSubscriptionCount = GetNode<Label>("LabelSubscriptionCount"); var cancelAndGcButton = GetNode<Button>("CancelAndGcButton"); var labelCanceled = GetNode<Label>("LabelCanceled"); SubscriptionTracker.EnableTracking = true; //SubscriptionTracker.EnableStackTrace = true; // OnPressedAsObservable var count = 0; button.OnPressedAsObservable(cts.Token) .Select(_ => ++count) .SubscribeToLabel(label); // OnToggledAsObservable toggleButton.OnToggledAsObservable(cts.Token) .SubscribeToLabel(label2); checkButton.OnToggledAsObservable(cts.Token) .SubscribeToLabel(label3); // OnValueChangedAsObservable slider.OnValueChangedAsObservable(cts.Token) .SubscribeToLabel(label4); spinBox.OnValueChangedAsObservable(cts.Token) .SubscribeToLabel(label5); // OnTextSubmittedAsObservable lineEdit.OnTextSubmittedAsObservable(cts.Token) .SubscribeToLabel(label6); // OnTextChangedAsObservable lineEdit2.OnTextChangedAsObservable(cts.Token) .SubscribeToLabel(label7); textEdit.OnTextChangedAsObservable(cts.Token) .Select(_ => textEdit.Text) .SubscribeToLabel(label8); // OnItemSelectedAsObservable optionButton.OnItemSelectedAsObservable(cts.Token) .SubscribeToLabel(label9); // for debug countSubscriptionsButton.Pressed += () => { var count = 0; SubscriptionTracker.ForEachActiveTask(state => { ++count; if (SubscriptionTracker.EnableStackTrace) GD.Print(state); }); labelSubscriptionCount.Text = count.ToString(); }; cancelAndGcButton.Pressed += () => { GD.Print("cancel & GC"); cts.Cancel(); GC.Collect(); labelCanceled.Text = "CANCELED!"; }; } protected override void Dispose(bool disposing) { cts.Cancel(); cts.Dispose(); } }
比較的頻出のUIイベントをシンプルに利用できる。イベント処理をベタ書きしようとするとObservable.FromEvent
利用となるが、少しカロリーの高い書き方になるので、手軽に Rx するために便利拡張メソッドがあるのは良い。
キャンセルトークンについて
R3.Unity との違いとして、引数にキャンセルトークンを受ける(省略可能)。
これはどちらかというとなぜ R3.Unity がそうなっていないのか、という話。Unity はdestroyCancellationToken
という仕組みを持ち、R3.Unity は暗黙にそのトークンに利用している。
一方、明示的にトークンを渡せるのは任意タイミングのキャンセル可といったプラスの面もある。省略可能引数なので、選択肢が増えている、という捉え方もできる。
ちなみに、ver.0.1.7 は購読トラッカーのエディタUI実装 & R3.Godot のプラグイン化という大きな前進もあった。
R3、Godot に馴染んでくれて、良い。