Unity を検索

取り上げているトピック
シェア

たくさんの輝く新機能の数々のなかで、Unity 5.3のリリースノートにぽつりと1行書かれているもののとても役にたつ機能があったので、多分皆さんにも役にたつだろうと思い紹介することにしました。それは、カスタムコルーチン…正式には CustomYieldInstruction クラスです。これは何かといういうと、自分でコルーチンのyieldオペレーションをとても簡単に実装することができるようにしてくれるものです。早速実際の使用例を見てみましょう。

実例 - バグ修正

わたしは最近、Unity 5.2で追加されたUIのドロップダウンコンポーネントのバグについて調べていました。Time.timescaleが0に設定されているとドロップダウンコンポーネントは最初の1回だけ動作し、そして以降timescaleが0以外に設定されるまで表示されない、というものです。

多少のデバッグの後、問題はShow 関数の中にあることがわかりました。

2
m_Dropdown がnullにならないため、ドロップダウンの表示をせずにメソッドが返ってしまいます。

一度表示されると、 m_Dropdown コンポーネントは最小化されて破棄されます。…えーと、破棄されるべきなんですが、timescaleが0の時は破棄されないのです。

破棄を実際に行う関数を確認して、問題が特定できるか見てみましょう。

1

このブログ記事のタイトルからもうお察しかもしれませんが、犯人はWaitForSecondsでした。WaitForSecondsはスケールされた時間を使います。これはつまりWaitForSeconds に1秒待つように指定した時、timescaleが0.5になっていれば、実世界では2秒(1 / 0.5 = 2)待つことになるということです。もしWaitForSecondsをtimescaleを0に指定しながら使用したら、(timescaleが0以外に再び戻るまで) 永遠に待ち続けることになるのです。まとめると、WaitForSecondsのyieldがずっと終わらずに待ち続けるので、ドロップダウンは最初の使用から全く破棄されないままになるわけです。

解決策

この問題を解決するには、スケールされていない時間で待つ必要があります。もっともエレガントなアプローチはここに新しいyieldの処理、つまりWaitForSecondsRealtimeクラスを導入することでしょう。はっきりしていることが一つあって、Unity自身の開発者でも WaitForSeconds がスケールされた時間を使うということに気がつかないのであれば、それ自体をどうにかして解決しなければなりません。WaitForSecondsRealtime が存在することはWaitForSecondsが想定とは違う動作をするかもしれないということを気がつかせる、一つのメッセージにはなるでしょう。また、WaitForSecondsのドキュメントも更新する必要があります。現状のドキュメントではスケールされた時間についての記述がまったくないので!

これが、わたしが最近追加された独自のyield処理を作るための機能である CustomYieldInstruction を発見した経緯です。

新しいyield処理を追加するのはとても簡単です。上記の問題であれば次のように解決できます:

3

すべてのカスタムyield処理はkeepWaiting プロパティをオーバーライドする必要があります。そして、yield処理を抜けて次に進んで欲しい状況になったら、単にfalseを返せばいいだけです。

こちらが修正されたコードです:

4

この例では、毎回スケールされていない実時間を取得してチェックします。これ以上ないほど簡単です - と思ったら、そんなことはありませんでした!実は、さらに新しく WaitUntilWaitWhile yield関数が追加されているからです。これらを使えば、delegateを使ってyield処理を組み立てることができます。

こちらが今回の問題に対するもう一つの解決方法です。ここでは5秒間待ちたいという前提で書いています。

5

今回紹介したものは簡単な機能ですが、多くのポテンシャルを持っています。ここで学んだ教訓は、「リリースノートを読もう。何か有用なものが見つかるかもしれない!」ということでしょうか。もしカスタムコルーチンが気に入ったら、ぜひ UnityEventsも見てみてください。ちょっと見過ごされがちな機能ですが、わたしのもう一つのお気に入りです。

2015年12月1日 カテゴリ: テクノロジー | 3 分 で読めます
取り上げているトピック