導入
こんにちは、foriver4725 です。
Unityでボタンクリックを処理する時、連打に対処したりする必要があるかと思います。
これまではUniTaskメインで以下のように書いていましたが、
private async UniTask Hoge(Button button, CancellationToken ct)
{
if (button == null)
{
Debug.LogError("Button is null. Cannot start the task.");
return;
}
while (!ct.IsCancellationRequested)
{
await button
.OnClickAsObservable()
.FirstAsync(cancellationToken: ct);
Debug.Log("Clicked");
await UniTask.NextFrame(ct);
}
}
こちらの記事でR3を用いた簡潔な書き方が紹介されていたので、
自分なりにライブラリ化してみました。
連打禁止・モバイルでの同時押し禁止など、工夫しています。
こちらがGitHubのレポジトリになります。
READMEに従ってインストールできます。(UniTask,R3の導入は必須)
説明
このライブラリではBetterButtonクラスが提供されます。
簡単に説明すると、次のように使います。
// 連打禁止、0.3秒ごとにしか受け付けない
private readonly BetterButton betterButton = new(0.3f);
// クリック時の処理が非同期の場合
betterButton.Subscribe(button, onClick, destroyCancellationToken);
// クリック時の処理が同期の場合
betterButton.SubscribeAwait(button, onClickAsync, destroyCancellationToken);
同じBetterButtonインスタンスにボタンをSubscribeする限り、それらボタンのクリックは排他制御されます。
つまり、例えばUIのショップを展開するとして、「購入」ボタンの演出中に「閉じる」ボタンを押しても反応しません。
「現在いずれかのボタンのクリック処理が実行中か」は、次のように取得できます。
SubscribeAwaitを使うとき、ボタンが無効の間は見た目を変える、などの処理で使えそうです。
// trueなら実行中、falseなら実行中でない
betterButton.IsAnyBeingExecuted
補足:ラムダ式の GC.Alloc 対策
以下は補足説明です。
サンプルプログラム(READMEにも記載)に書いてあるのですが、
ラムダ式で外部変数をキャプチャする際にGC.Allocが発生しないよう、以下の書き方を提供しています。(複数キャプチャしたい場合は、タプルにする)
個人的に、ラムダ式には全てstaticをつけた方が安心できていいと思います。
betterButton.SubscribeAwait(button, (Index: 0, Name: button.gameObject.name), static async (param, ct) =>
{
await UniTask.DelayFrame(64, cancellationToken: ct);
Debug.Log(param.Index + " by " + param.Name);
}, destroyCancellationToken);
締め
初投稿のため読みにくかったと思いますが、ここまで読んでくれてありがとうございます!
改善の指摘などあれば、コメントくださると大変嬉しいです。