usingステートメントを活用して、見通しの良い入力阻止を実装しよう【Advent Calendar 12/16】
はじめに
この記事は Colorful Palette アドベントカレンダー 12/16 の記事です。
こんにちは、株式会社Colorful Paletteでクライアントエンジニアをやっている「もっさん」です。
本記事では「Unityで特定の処理の間、画面の入力を阻止する処理」を実装します。
実装
InputBlockerを用意しよう
通信処理中や、リソースの非同期ロード中などユーザーに画面操作をして欲しくないタイミングが多く存在します。
対策として、画面への入力を阻止する仕組みが必要になります。
今回は画面全体を覆うImageを配置して、その有効/無効を切り替える事で入力を防ぐ仕組みを実装します。
まず、画面への入力を阻止するクラスを作成します。
// 入力を制御するクラス
public class InputBlocker
{
private Image _blockImage;
// 入力阻止を有効にします
public static void Enable()
{
_blockImage.raycastTarget = true;
}
// 入力阻止を無効にします
public static void Disable()
{
_blockImage.raycastTarget = false;
}
}
InputBlockerを呼び出してみよう
次に、usingステートメントを使わず入力阻止を制御するコードを書いてみます。
LongLongMethod()という関数があるとして、その呼び出しをInputBlockerでサンドイッチします。
private void SampleMethod()
{
InputBlocker.Enable();
LongLongMethod();
InputBlocker.Disable();
}
private void LongLongMethod()
{
// 長ーーい処理
}
短い関数内で、同期処理の場合はこれでも問題ありません。
ですが、LongLongMethod()が非同期になって途中でキャンセルされたり、
今後メンテナンスが進んでいく内に**InputBlocker.Disable()に辿り着かなくなると、入力阻止が有効になったまま**になってしまいます。
usingステートメントと組み合わせてみよう
入力阻止の開始と終了がセットになっていない事がわかりました。
usingステートメントを活用して必ず入力阻止の開始と終了が呼ばれるように修正してみましょう。
usingステートメントは、本来リソースを自動開放するための仕組みで、
処理の終わりに必ずIDisposable.Dispose()を呼びだしてくれるので安心です。
まず、Dispose()可能なオブジェクトを実装します。
using System;
// 入力阻止を紐づけるオブジェクト
// usingステートメントはIDisposableを継承したオブジェクトを渡すことが出来ます。
public class InputBlockObject : IDisposable
{
// コンストラクタ。インスタンスが作られた時に入力阻止を有効にします。
public InputBlockObject()
{
InputBlocker.Enable();
}
// 破棄処理。入力阻止を無効にします。
public void Dispose()
{
InputBlocker.Disable();
}
}
次に、先ほどの処理をusingステートメントで囲って…。
...
using()
{
InputBlocker.Enable();
LongLongMethod();
InputBlocker.Disable();
}
先程実装したInputBlockObjectを渡しましょう。
...
using(new InputBlockObject())
{
InputBlocker.Enable();
LongLongMethod();
InputBlocker.Disable();
}
InputBlockObjectに入力阻止の呼び出しが移動したので、手動で開始~終了を書いていた部分は取り除けます。
...
using(new InputBlockObject())
{
LongLongMethod();
}
完成!
処理順番の解説
処理順としては、以下のようになります。(*番号が実行順番)
using(new InputBlockObject()) // *1, *4
{
LongLongMethod(); // *2
} // *3
*1 InputBlockObjectインスタンスが作られ、コンストラクタ内でInputBlocker.Enable()が呼ばれる。
*2 LongLongMethod()が実行される
*3 usingステートメントのスコープを抜ける
*4 InputBlockObjectインスタンスのDispose()が呼び出され、InputBlocker.Disable()が呼び出される。
まとめ
singステートメントを活用する事で、見通しよく安全な入力阻止を実装出来る
ステートメント内のスコープを抜けるとDispose()が呼び出される
例外が発生したときも自動でDispose()が呼び出される
おわりに
次回は週明けの12/19日(月)、クライアントエンジニアの山上さんが担当します。
いかがだったでしょうか。
駆け足気味となりましたが、参考になれば幸いです!
他にも、usingステートメントを複数組み合わせたり、色々な活用方法があるので是非チャレンジしてみてください!
次回は週明けの12/19日(月)、クライアントエンジニアの山上さんが担当します。
Colorful Palette アドベントカレンダー は12/25までの平日+α更新となっております。
ぜひ引き続きご覧ください!