Unity UIのイベントの無限ループ対策 コードからUI変更するイベントをフラグで止める対策パターン | Unity入門の森 ゲームの作り方

Unity UIのイベントの無限ループ対策 コードからUI変更するイベントをフラグで止める対策パターン

Unity技術ブログ・開発テクニック

現場レベルのゲーム制作が、すべてここで学べます。

【永久会員チケット】

永久会員チケット|Unity入門の森

全講座を見放題で学ぶ

ソースコード・素材・プロジェクトすべて公開。
Unityの基礎から応用まで、一生使えるスキルを体系的に習得。

UnityでUIを開発したり、スクリプトでUIを操作していると「コードで値を変えたら意図しない関数が連鎖して無限ループしてしまう」という経験をしたことはないでしょうか。

この問題を解決するのが suppressCallbackパターン です。

Unity・C#の具体例を5つ使って丁寧に解説します。

【ゲームの作り方講座プレゼント中!】

suppressCallbackとは

suppressCallbackとは、コールバック(イベント処理)を一時的に抑制するためのbool型フラグ変数です。

このフラグを true にしている間は、イベントハンドラの冒頭で早期リターンさせることで、不要な処理の連鎖を防ぎます。

なぜsuppressCallbackが必要なのか

UnityのToggleやSliderなどのUIコンポーネントは、値が変わると自動的にイベントを呼び出します。これはプレイヤーが操作したときには便利ですが、コードから値を書き換えたときにも同じイベントが発火してしまいます。

「プレイヤーの操作」と「コードによる内部的な書き換え」を区別する仕組みがsuppressCallbackです。

実例1:経営シミュレーションの強制OFF処理

所持金が不足したときに施設を強制OFFにするケースです。これは特に重要な実装パターンで、安全に停止させるための処理が複数組み合わさっています。

suppressCallbackがない場合の危険な流れ

NG:suppressCallbackなし
  • お金不足を検知
  • StopBilling()
  • toggle.isOn = false(普通にOFFにする)
  • OnToggleChanged(false) が発火! また呼ばれる
  • StopBilling() がまた呼ばれる… 二重処理・ループ

suppressCallbackがある場合の安全な流れ

OK:suppressCallbackあり
  • お金不足を検知
  • StopBilling()
  • suppressCallback = true(フラグを立てる)
  • SetIsOnWithoutNotify(false)(UIだけ更新)
  • suppressCallback = false
  • ApplyActive(false)(1回だけ意図通りに実行)

SetIsOnWithoutNotifyだけでは不十分な理由

Unityには SetIsOnWithoutNotify() というAPIがあり、これ自体はUnityの標準イベントを発火させません。しかし、ゲーム独自のロジックまでは止められません。

suppressCallbackは独自処理も含めて止める二重の安全装置として機能します。

関連記事:【Unity】SetIsOnWithoutNotifyの使い方|onValueChangedを発火させずにToggleを変更する

【Unity】SetIsOnWithoutNotifyの使い方|onValueChangedを発火させずにToggleを変更する
Unityでトグルを操作するとき、コードから値を変えているだけなのにonValueChangedが呼ばれてしまうという場面はないでしょうか。そんなときに使えるのが SetIsOnWithoutNotify() です。このメソッドを使うと、o...

実例2:スライダーと入力欄の相互連動

音量設定画面など、スライダーと数値入力欄が連動しているUIは無限ループの典型的な発生源です。

suppressCallbackがないと、スライダーを動かすたびに OnSliderChanged → OnInputChanged → OnSliderChanged… という無限ループが発生します。

実例3:セーブデータのロード時

ゲーム起動時にセーブデータをUIに反映する処理でも必須です。

セーブデータの読み込みはあくまで「UIの復元」であり、「プレイヤーが操作した」わけではありません。フラグがないと、ロードのたびにBGM処理・難易度変更処理が実行されてしまいます。

実例4:「全選択」ボタン

チェックボックスが多数ある画面に「全選択」ボタンを実装するケースです。

 

チェックボックスが100個あれば、フラグなしでは OnSelectionChanged が100回呼ばれます。通信処理やDB更新を伴う場合は致命的なパフォーマンス問題になります。

実例5:Undo / Redo(やり直し機能)

やり直し機能の実装でも、suppressCallbackは欠かせません。

フラグがないと、Undoで値を戻したときに「Undoした操作」が新たな履歴として積まれ、Redoが完全に壊れます。

場面別まとめ

場面 フラグなしで起こる問題
スライダー ↔ 入力欄の連動 無限ループ
セーブデータのロード ロードのたびに処理が走る
全選択ボタン 重い処理が N 回呼ばれる
Undo / Redo 履歴データが壊れる
強制OFF処理(残金不足など) 二重処理・ループの危険
共通するパターン:「プレイヤーの操作」ではなく、「コードによる値の書き換え」のときにイベントを止めたい場面で必要になります。

suppressCallbackのベストプラクティス

try-finallyで確実にフラグをリセットする

例外が発生してもフラグが残らないよう、try-finallyを使うとより安全です。

フラグの意図をコメントで明記する

後から読む人(未来の自分も含む)のために、なぜフラグを使うのかを残しましょう。

規模が大きくなったら専用クラスに切り出す

管理対象が増えたら、フラグ管理を専用クラスに委ねることも検討しましょう。

よくある質問:suppressCallbackってUnityに用意されてる変数とかじゃないですよね?

その理解で正しいです。
suppressCallback という名前自体もUnityが用意したものではなく、開発者が自分で付ける変数名です。

isUpdatingUI とか isSyncing とか何でもよくて、要は「今はイベントを無視してね」というフラグを自前で管理するパターンの総称です。

Unityが用意しているのは SetIsOnWithoutNotify() のような「通知なしで値を変える」APIだけで、suppressCallbackはそれとは別の自前の安全弁です。

整理すると:

  何が止まるか 誰が用意するか
SetIsOnWithoutNotify() Unityの標準イベント(onValueChanged等) Unity
suppressCallback 自分で書いたゲーム独自のロジック 自分

だから記事中で「二重の安全装置」と書いたのはそういう意味で、両方組み合わせることで完全に制御できます。

suppressCallbackは Unityに限らず、React・Vue・WinForms などあらゆるUIフレームワークでも応用できる汎用パターンです。

シンプルなboolフラグ一つで、無限ループ・二重処理・データ破壊を未然に防ぎましょう。

【ゲームの作り方講座もプレゼント中!】

現場レベルのゲーム制作が、すべてここで学べます。

【永久会員チケット】

永久会員チケット|Unity入門の森

全講座を見放題で学ぶ

ソースコード・素材・プロジェクトすべて公開。
Unityの基礎から応用まで、一生使えるスキルを体系的に習得。

コメント

タイトルとURLをコピーしました