スパイダーマン
今秋最後の三連休は台風が来たり行楽日和だったりと天候がめまぐるしく変わる休日でしたが、私は安定した休日ニートなので部屋に引き篭もって過ごしていました。台風で公共交通機関ガー、とか、行楽日和で各所で渋滞ガー、とか、運動会で早朝から場所取りガー、とか、アベガー、とか、まったく関係なくスパイダーマンとして街の平和を守っていました。楽しすぎてヤバイ。
サクッと閑話休題
以前、Koreographerを使ったLaunchPadみたいなオブジェクトを製作中のゲームに搭載してみたら、実機動作が重くなってニッチモサッチモ、みたいな話をしたのですが、元来もったいない精神溢れる人間なので何とか使える方法がないか探っていました。
動作が重くなる最大の要因はBatch数の増加で、通常は複数のオブジェクトが同じマテリアルを使用しているとBatch数は1となりますが、各オブジェクトがマテリアルのColorをそれぞれで変更したりすると、その分Batch数は増加するみたい(当然といえば当然)
なので、キューブが6*12で構成されているオブジェクトを一気に表示すると最大で72増加することになるので、100前後が目安らしいモバイルでは致命的な数になります。
このため、各キューブを必要な時にだけ表示するようにして、通常は非表示状態とするように対応したかったのですが、それをSetActiveを使って実装しようとするとちょっとした問題が発生しました。
SetActiveによる非表示化
オブジェクトを非表示化する最もスタンダードな方法はSetActiveにfalseを設定して、オブジェクトを非アクティブ化する方法ですが、これはあくまでも非アクティブ化ということなので、ちょっとした制約を受けます。
例えば
- GameObject.Find()で検索して取得することが出来ない
- Animatorのステート(状態)がリセットされる
- 動作中のコルーチンが停止する
などがあります。
その中でも「動作中のコルーチンが停止する」は面倒くさい問題で、コルーチンでの処理中にSetActiveをfalseにしてしまうと、処理中の状態は破棄されてしまうので重大なバグの原因になります。
この辺の話とその対処法は別の記事でも書いたのですが、今回のケースでは非表示状態でも内部処理のコルーチンは動作してもらう必要があったので、SetActiveによる非表示化は使えないなぁ、という結論に。
ん~、では、どうするか
Rendererのenabledによる非表示化
オブジェクトを非表示化するもう一つの方法がオブジェクトのRendererのenabledにfalseを設定する、という方法です。
要はオブジェクトの描画をしない、ということなので、コンポーネントの内部処理はコルーチンを含めそのまま動作します。
ソース的にはこんな感じ、SetActiveを使用する方法と比べると1ステップ増えるだけ。
Renderer rend = gameObject.GetComponent<Renderer>();
rend.enabled = false;
で、これがBatch数の増減に有効なのか分からなかったのですが、実際に試してみるとアッサリ削減されました。(まぁ、これも当然といえば当然か・・・)
内部処理を行ったまま非表示化するには有効な方法かと思いますが、ただSetActiveを使った方法と違って子オブジェクトに対しては非表示化の状態が適用されないことに注意が必要です。描画されないのはあくまで当該のオブジェクトのみ。
つまり、複数のオブジェクトで構成されるモデルをRendererで非表示化しようとすると、そのすべてのオブジェクトのRendererに対してenabledにfalseを設定する処理が必要になります。
その辺は用途に応じて使い分ける必要があります。
で、結局こんな感じになったよ
Android端末(Nexsu6p)でも動作させてみましたが、それほど遅延することはありませんでした。
ただ、この演出が本当に必要なのかどうかはまた別の話で・・・