原カバンは鞄のお店ではありません。

Unityを使ったゲーム制作のあれこれを綴っていきます。

【Unity】Animator付きのGameObjectの非アクティブ化について

強炭酸ブームらしい

どちらかといえば微炭酸な人生を歩んできた人間なので気づかなかったのですが、巷では強炭酸がブームらしいです。バカリズム似の作家センセイがそんなTweetをしていて知りました。調べてみると昨今のハイボール人気から炭酸の需要が拡大し、強炭酸水のブームにつながったようです。なんでもウィルキンソンは前年比22・1%増の販売量だとか。

 

そういえば最近は居酒屋には必ずハイボールやサワーのメニューはあるし、乾杯の一杯目でもビールではなくハイボールを頼む人が多いですしね、あ、でもビールも炭酸か、なんだ、根っから炭酸好きじゃん日本人。

 

新しい発見

そんな感じで新しい発見に出会えたり出会えなかったりする日常を過ごしているわけですが、Unity関連で最近発見したことといえば、前回のブログで取り上げた性能対策を行っていたときに直面した問題だったりします。

 

www.karvan1230.com

前回のブログではBatch数を削減すために『使用しないUIはCanvasごと非アクティブにする』対策を行ったのですが、この非アクティブにする前後でUIのアニメーションが変わってしまう不具合を発見

 

非アクティブ状態にする前のUIアニメーション

f:id:Karvan:20181120235302g:plain

 

非アクティブ状態からアクティブ状態に戻した後のUIアニメーション

f:id:Karvan:20181120235353g:plain

 

見て分かるようにアクティブ状態に戻した後だと、右側の四角が半分切れた状態で表示され、途中で表示される白線も上に移動しています。

 

UIアニメーションはUnity標準のAnimationを使用しているのですが、アクティブ状態の切り替えでこんな影響がでるとは想定外でした。

 

原因?

まったく原因がわからないので、エディタウィンドウに表示される右の四角の設定を通常時とおかしくなった後で比較して確認。
すると、PivotのY位置が通常時は0.5になっているのに、おかしくなった後では0になっていることを発見、
つまりアクティブ状態の切り替えによってこの設定が0になるらしい、んー。

 

f:id:Karvan:20181120235502p:plain

 

次にAnimationエディターで右の四角の動作を確認。
AnimationではPivotのX位置についての設定はあるものの、Y位置について設定は特に行っていません。

 

f:id:Karvan:20181121000631p:plain

 

つまりAnimationではPivotのY位置は動かしていない。

 

f:id:Karvan:20181120235919p:plain

PivotのY位置が変わっているのにAnimationにはY位置の設定はない・・・

 

f:id:Karvan:20181120235938p:plain

だけどAnimationを動作させるとPivotのY位置が0になる・・・
それもアクティブ状態を切り替えた後にだけ・・・

 

f:id:Karvan:20181120235957p:plainわからん!!

 

当初はまったくお手上げでした。

 

たぶん、たぶん、きっと

で、改めてAnimationエディターで設定を確認。

 

f:id:Karvan:20181121000042p:plain

 

PivotのY位置について『DefaultValue』の記述があります。

『Default』ってことは初期位置(=0.5)だと思ったのですが、もしかするとアクティブ状態の切り替えによって『Default』値が変わっているのかもしれない・・・

 

そう思って、PivotのY位置について0.5となるように設定を追加すると・・・

 

f:id:Karvan:20181120235302g:plain

 

ちゃんと動いたー

こんな簡単なことで一日潰れたりする・・・

 

類似記事の紹介

ここら辺の話をよくよく調べてみると毎度お世話になっているテラシュールブログにて似たような記事がありました。

 

tsubakit1.hateblo.jp

つまり、Animatorを含むGameObjectの非アクティブ化はできるだけ避けたほうが良い、という事みたいです。

 

ん~、とは言ってもなぁ・・・

 

 

 

【Unity】使われないuGUIはCanvasごと非アクティブにした方が良い?

腰痛い

基本的に休日ニートな人間なので、休みの日は部屋に閉じこもることが多いのですが、先日は地元でADAM atのライブがあったので重たい腰を上げて参戦してきました。

 

www.jvcmusic.co.jp

ADAM atはピアノ・インストゥルメンタル・ユニットでCDショップなどではジャズ系に分類されることが多いのですが、ジャズスウィングの横ノリというよりはロックな縦ノリ曲が中心で、ライブではヘドバンするような曲も演奏されます。その所為かMCでは『ジャズなのにジャズ系のフェスに呼ばれない』とぼやいてました(笑)

 

実は、現在製作中の「Dull Things No Life」はADAM atの「共鳴ディストラクション」という曲を聴いた時のイメージがベースになっています。ゲーム画面のデザイン中はずっと聴いてたし。

 

なので、早々にチケット取りウキウキしながら参戦してきたのですが、結果腰が痛い。

なにせ前述のように激しい曲が中心で、ライブ中はほぼずっと飛び跳ねていたので、そりゃ腰を痛めるわ、って感じ。座っても立っても腰が痛い。

 

まぁ、ライブが楽しかったからいいけど

 

性能対策に頭が痛い

そんな感じで痛めた体を庇いながらもゲーム製作は進んでいくのですが、前々回の記事で報告したメニューウィンドウを実際のゲームSceneに取り込んでみたら、実機での動作がまたモッタリするような感じに何度目だ。

 

スマホ向けゲームを作るうえでは避けて通れない性能対策に頭を痛めながらStatisticsを確認すると、確かにBatch数が常時130オーバーな状態になっている。んー、これはいかん。

 

f:id:Karvan:20181113211319p:plain

 

メニューウィンドウを追加する前だとBatch数は100を切っていたので、これは明らかに追加したメニューウィンドウの所為だと分かります。


まぁ確かに、実行前のゲーム画面はこんな感じでゴチャゴチャしているし、起動後はマスクによって非表示状態になっているだけなので、いくら見えないとはいってもBatch数は軽減されないのかもしれない。

 

f:id:Karvan:20181113211421p:plain

(テキスト部分は分かりやすいように文字を入れています)

 

uGUIに関する性能対策

uGUI周りの性能対策について広く知られているのは

  • SpriteをAtras化する
  • 動くUIと動かないUIでCanvasを分ける

等があります。詳しくは下記リンクを参照してください

 

siguma-sig.hatenablog.com

「Dull Things No Life」でも同様の対策を行っていて、Canvasも通常(動かない)UI、メニュー系UI、メッセージ系UI、トランジッション系UIで別々のCanvasに分けています。

Canvasが増える分、SetPassが増える=Batch数が増える、ことは覚悟していたのですがここまで増えるとは予想外でした。

 

とはいえ、今更同じCanvasに纏めるのは馬鹿らしいし、違うところで負荷が増えることになるので対策にはならない。
なので試しに、マスクによって非表示状態になっている時はCanvasごと非アクティブにしてみようと思ったわけです。

 

で、結果として・・・

f:id:Karvan:20181113211833p:plain

おお、見事にBatch数が減っている!

 

んー・・・使われないGUIはCanvasごと非アクティブにしたほうが性能的にはいいのかな?

 

 

 

 

 

 

 

・・・とか思ったのですが、ここでまた別の問題が発生、はぁー、頭痛い・・・詳細は次回の記事で

 

 

【Unity】パーティクルを使って動くオブジェクトの軌跡を描く

11月

11月にもなると気温もぐっと低くなり、年末も差し迫ってきた感じがして、私の周りでも忘年会をどこで開こうか、みたいな話がチラホラ聞えて来ます。忘年会に限らず年末年始は飲み会の多いシーズンなので出費と胃腸の心配をされる方も多いかと思いますが、私の場合は全くその心配がないので安心です。別に私が金持ちだから健康優良児だからというのではなく、単に誘われないからなんですけどね。「辛れー、昨日一時間しか寝てないから辛れーわー、オールで飲んでたから辛れー」は私の中で一度声に出して読みたい日本語の第五位くらいにいます。

 

いきなり進捗報告

とはいえ今週末は体調があまり優れなかったので寝ている時間も多かったのですが、それでも製作を細々と続けてやっと演出部分がここまで出来ました。

 

f:id:Karvan:20181106223626p:plain

 

演出を強化したい

ゲームでは良くある演出の一つに「キャラクターが移動した軌跡を表示する」ってのがあります。
車の土煙とか、ミサイルの噴煙とか、その物体が高速で移動していますよ!みたいなことを上手く表現する手法です。

 

ご多分にもれず「Dull Things No Life」でもプレイヤーの主機となるバイクに噴煙みたいなパーティクルをつけて、バイクが高速で動いているように見せようと努力しています。

 

f:id:Karvan:20181106223759g:plain

 

こんな感じで

 

だが、なんか物足りない。噴煙がカメラ方向に伸びているだけで、ちょっと地味。
なので週末はバイクの左右の移動によってそれっぽい軌跡を表示する演出部分を作っていました。

 

出来上がりの図(二度目)

f:id:Karvan:20181106223626p:plain

 

赤い軌跡の部分はTrailRendererで表示しているのですが、タイヤ横の青い軌跡はParticleSystemで表現しています。

 

上の図でも分かるようにTrailRendererだと一つの線として軌跡が表示されますが、ParticleSystemを使うと段階的に軌跡が表示されるのでちょっとカッコイイ、こちらのほうが高速に動いて見える感じがします。

 

軌跡を表示する

参考にしたのは、毎度お世話になっているテラシュールブログさんです

tsubakit1.hateblo.jp

リンク先ではCubeを使用していますが、今回は四角形のSpriteです。
これをParticleSystemを使ってタイヤの横から放出されるようにします。

 

まず基本部分の設定

f:id:Karvan:20181106224100p:plain

 

Simulation SpaceにWorldを指定してWorld座標でパーティクルを生成します。

この指定により放出したParticleが親オブジェクト(今回の場合はバイク)にくっついて移動することがなくなります。


またPrewarmフラグをONにしておくとループの途中から再生されたかのように一気にパーティクルが発生します。

 

次にEmissionの項目

f:id:Karvan:20181106224154p:plain

 

ここでRate over TimeでなくRate over Distanceに値を設定することがポイントです。


Distanceということは、時間ではなくParticleSystemの親オブジェクトが動いた距離によってパーティクルが発生します。
つまり、軌跡に沿ってパーティクルが生成される、ということになります。

 

併せてサイズの指定で、Size Over Lifetimeで最大値から一気に縮むように設定。残影っぽく見えるように。

 

最後にRendererのModeにBillboardを指定します。

f:id:Karvan:20181106224317p:plain

 

これによりカメラが移動してもパーティクルが正面を向くように表示され、形がゆがむ事はありません。

 

これらを設定して実際に動作させると、こんな感じに

 

f:id:Karvan:20181106224343g:plain

 

GIFの解像度が悪いですが、実際は綺麗に表示されます。

 

11月中には仕上げたい

でも無理っぽい。もっと効率的に動ける能力がほしいですね。頭の中の仕様をぱっと実装できるような才能が、それも努力無しに。
「あれ?俺またなんかやっちゃいました?」は私の中で一度声に出して読みたい日本語の第二位くらいにいます。

 

 

あ、ちなみに第一位は「アレクサ、大さじ4杯は何カップ?」です。

その前に目分量で0.3カップを測る能力を身につける必要がありますが。

 

たまには進捗報告をしよう

寒暖差が激しい

晩秋の候にもなると朝夕の寒暖差が激しくて体調を崩す方も多いと聞きますが、私もご多分に漏れず、風邪を引いたようで鼻づまりがひどい状況となっています。前回の記事でも書いたのですが、どうもここ最近は巡り合わせ悪いターンに差し掛かっているようで、思うように事が運ばずテンションが上がらない、ここ最近で面白かった事といえば、台湾事故で発生当初は『大変だー、心配です。・・・車両は日本製だけど』とウキウキでTweetしたいたのに、事故原因が人為的ミスだと明らかになるにつれてピタリと話題に触れなくなった平野啓一郎ぐらいで、これといった楽しい話もありません。あー、鼻水が辛い

 

UI周りの進捗

そんなわけで、今回は「Dull Things No Life」のメニュー周りができたのでその動画を載せて、後はゆっくり寝ます。あー、本当に鼻水辛い。

 

f:id:Karvan:20181030234447g:plain

 

あ、メニューができただけで、実際にScene遷移処理はこれから作成します。

 

 

Scriptableobjectを使ってScene間でデータを共有する

上手く廻らない期間

私だけかもしれませんが年に数回、物事が上手く廻らない期間というものがあり、どうも最近はその期間に突入したようで、風邪気味で体調が優れないとか、仕事で想定外のバグが発覚したとか、応援しているサッカーチームが負けたとか、お気に入りの店員がいるコーヒーショップが閉店するとか、文学界のバカリズム(主に顔)が台湾の脱線事故で嬉しそうとか、小規模ながら欝になりそうなことばかりが続いてテンションが上がらないのですが、かと言って他にやることもないのでシコシコとゲーム製作を続けています。

 

ScriptableObject

そんな愚痴はさておいて、UnityにはScriptableObjectなるデータ格納用のオブジェクトが用意されています。
主にゲーム内で使用する静的なパラメータ(キャラクターの初期ステータス、表示メッセージ用のテキストデータ等)をアセット化していろいろな場面で参照することを目的に使用します。

 

まぁ、参照用のパラメータとするするだけなら、定数クラスを作ってそこにまとめてもいいし、CSVやJSON等のファイルにしてもいいし、何ならGameObjectを使っても構いません。

 

ただ、ScriptableObjectを使用するとメモリの節約になり、高速でデータにアクセスできる、などの利点があります。
これらは以下のkan.kikuchiさんのブログに詳しく纏められていますので参照してください。

kan-kikuchi.hatenablog.com

Scene間でデータを共有する

私も最初は「ScriptableObjectとか良く分からんからGameObjectに保持して参照すればええやろ」的に考えて、ScriptableObjectは使っていなかったのですが、ゲーム製作の途中、Scene間でデータを受け渡す必要がでてきて、色々悩んだ挙句、ScriptableObjectを使うことにしました。

 

UnityでScene間でデータを共有する方法は主に次の3つあります

  1. static変数でやり取りする
  2. データを持つGameObjectを破壊せず(DontDestroyOnLoad)に保持する
  3. PlayerPrefsのようなセーブ機能を使う

 

このうち、1の方法を説明すると、クラスのメンバ変数をpublic staticで宣言して、getter関数で他から参照する方法です。

 

設定側(シーンAで設定)

public class SceneScriptA : MonoBehaviour {
    public static int score = 0;

    // getter
    public static int getScore() {
        return score;
    }
}

 参照側(シーンBで参照)

public class SceneScriptB : MonoBehaviour {
 
    int b;
    void DispFunction () {
        b = SceneScriptA.getScore ();
    }
}

 

勿論このままでも使用可能なのですが、うら干物さんのブログでこの方法を応用して、ScriptableObjectをstaticのInstance化して使用する方法が紹介されていました。

 

www.urablog.xyz

ScriptableObjectは使用する際に、Inspectorからアタッチするか、ResourceLoadで読み込む処理が必要だったのですが、上記ブログで紹介されているParameterTableのスクリプトを使用すると、全てParameterTable.Instance経由でScriptableObjectに定義したパラメータの参照・更新が可能になります。
(ソースの転記はしません、あしからず)

 

勿論、前述のようにstatic宣言しているのでScene間を跨いでデータを使用することもできるし、更新することもできます。

 

ただ、ブログ内でも触れられていますが、ScriptableObjectクラスにはパラメータのみ記述し、取得用のstaticクラスを別に作成し、そちらから参照・更新する方がScriptableObjectの正しい使い方なのかもしません。

 

他人の褌で・・・

他人の褌で相撲を取るような記事で申し訳ないのですが、私のような面倒くさがり屋には最適な方法だったので紹介してみました。

 

ただ今回の方法はゲーム実行中の間だけ保持され、ゲーム終了後に全データが初期値に戻ってしまうことに注意が必要です。
永続的なデータで保持したい場合はPlayerPrefsのようなセーブ機能を使う方法をとる必要があります。

 

私はEasySaveを使ってParameterTableの中身をファイルに保持するようにしています。ここら辺の話は別の機会に記事にしようと思っています。

 

f:id:Karvan:20181023213130p:plain

以上です。

 

UnityのImageマスクでマスク側だけサイズを変える

行楽シーズンなので・・・

コンサートを観にいったら斜め後ろに頭に鉢巻を巻いたセーラー服姿のオッサンがいて、めっちゃ気になるけど見ちゃいけない、いや、やっぱり気になるけれど万が一、目が合ったら怖い、、云々で、ステージより斜め後ろのオッサンの動向のほうが気になって仕方ない、みたいな集中力が散漫になる週末を過ごしたのですが、終演後に振り返ったらそのオッサンの姿はどこにもなかったのであれは幻だったのかもしれない。

 

まぁいいでしょう

 

UIデザインについて

元よりデザイン系の才能については全般的に自信がないのでキャラクターやオブジェクト、イメージに関してはほぼ購入したものを使っている(前作はロゴも発注したし)のですが、特にUIのデザインについては毎度頭が痛いです。

 

色々と試行錯誤を繰り返して、作っては変え、作っては変え、とゲームのメイン部分のコーディングよりも時間が掛かったりします。

 

現在製作中の「Dull Things No Life」でも同様でステージ選択の画面とかどうやっても厨二病っぽい仕上がりになっちゃう。

 

仕方ないので画面を表示する時にお洒落っぽいアニメ動作を入れて誤魔化そう、と考えて、前々回でも照会したUIアニメーションのテンプレートアセットを使用することに

www.karvan1230.com

で、今回は

こんな感じでメニュー画面を表示するようにしました。

f:id:Karvan:20181016232536g:plain

 

アニメ動作的には簡単な動作で、メニュー画面の親となっているマスクのサイズを変えているだけなのですが、そこでちょっとしたヒントを発見。

 

Spriteマスクと違ってImageのマスクは、マスクをかけるImageはマスクの子オブジェクトでなくてはいけません。

 

f:id:Karvan:20181016233535p:plain

 

このため、マスク側のサイズをScaleで変更しようとすると当然、子オブジェクトのImage側もサイズが変更されてしまいます。

 

なので、これまではマスク側は不動で、Image側を動かして表示するようにしていたのですが、今回のアニメ動作の場合はImage側(メニュー画面)は不動で、マスク側のサイズが変更される動作となっています。

 

マスク側のサイズを変える

これはAnimation画面をみればわかるのですが、マスク側のDeltaSizeの値を変えています


今回の場合、マスクのサイズは520*360なので、最初のDeltaSizeには「-520,-360」を指定、それを徐々に変えていくことでマスクのサイズを大きく=メニュー画面が徐々に表示される、仕組みとなっています。

 

これが

f:id:Karvan:20181016233744p:plain

 

これに代わる

f:id:Karvan:20181016233813p:plain

 

ただ、マスクやImageのサイズはAnchorsPositionも関ってくるので一概にDeltaSizeの値だけ注目すればいい、ということもないので注意が必要です。

 

ここら辺の話はRectTransfromについて纏めた以下の記事が参考なると思います。

 

tsubakit1.hateblo.jp

 

 

Unityオブジェクトを表示したり非表示したりラジバンダリ

スパイダーマン

今秋最後の三連休は台風が来たり行楽日和だったりと天候がめまぐるしく変わる休日でしたが、私は安定した休日ニートなので部屋に引き篭もって過ごしていました。台風で公共交通機関ガー、とか、行楽日和で各所で渋滞ガー、とか、運動会で早朝から場所取りガー、とか、アベガー、とか、まったく関係なくスパイダーマンとして街の平和を守っていました。楽しすぎてヤバイ。

 

サクッと閑話休題

以前、Koreographerを使ったLaunchPadみたいなオブジェクトを製作中のゲームに搭載してみたら、実機動作が重くなってニッチモサッチモ、みたいな話をしたのですが、元来もったいない精神溢れる人間なので何とか使える方法がないか探っていました。

 

動作が重くなる最大の要因はBatch数の増加で、通常は複数のオブジェクトが同じマテリアルを使用しているとBatch数は1となりますが、各オブジェクトがマテリアルのColorをそれぞれで変更したりすると、その分Batch数は増加するみたい(当然といえば当然)

 

なので、キューブが6*12で構成されているオブジェクトを一気に表示すると最大で72増加することになるので、100前後が目安らしいモバイルでは致命的な数になります。

 

このため、各キューブを必要な時にだけ表示するようにして、通常は非表示状態とするように対応したかったのですが、それをSetActiveを使って実装しようとするとちょっとした問題が発生しました。

 

SetActiveによる非表示化

 

オブジェクトを非表示化する最もスタンダードな方法はSetActiveにfalseを設定して、オブジェクトを非アクティブ化する方法ですが、これはあくまでも非アクティブ化ということなので、ちょっとした制約を受けます。

 

例えば

  • GameObject.Find()で検索して取得することが出来ない
  • Animatorのステート(状態)がリセットされる
  • 動作中のコルーチンが停止する

などがあります。

 

その中でも「動作中のコルーチンが停止する」は面倒くさい問題で、コルーチンでの処理中にSetActiveをfalseにしてしまうと、処理中の状態は破棄されてしまうので重大なバグの原因になります。

 

この辺の話とその対処法は別の記事でも書いたのですが、今回のケースでは非表示状態でも内部処理のコルーチンは動作してもらう必要があったので、SetActiveによる非表示化は使えないなぁ、という結論に。

www.karvan1230.com

ん~、では、どうするか

 

Rendererのenabledによる非表示化

オブジェクトを非表示化するもう一つの方法がオブジェクトのRendererのenabledにfalseを設定する、という方法です。


要はオブジェクトの描画をしない、ということなので、コンポーネントの内部処理はコルーチンを含めそのまま動作します。

 

ソース的にはこんな感じ、SetActiveを使用する方法と比べると1ステップ増えるだけ。

 

Renderer rend = gameObject.GetComponent<Renderer>();
rend.enabled = false;

 

で、これがBatch数の増減に有効なのか分からなかったのですが、実際に試してみるとアッサリ削減されました。(まぁ、これも当然といえば当然か・・・)

 

内部処理を行ったまま非表示化するには有効な方法かと思いますが、ただSetActiveを使った方法と違って子オブジェクトに対しては非表示化の状態が適用されないことに注意が必要です。描画されないのはあくまで当該のオブジェクトのみ

 

つまり、複数のオブジェクトで構成されるモデルをRendererで非表示化しようとすると、そのすべてのオブジェクトのRendererに対してenabledにfalseを設定する処理が必要になります。

 

その辺は用途に応じて使い分ける必要があります。

 

で、結局こんな感じになったよ

f:id:Karvan:20181009231945g:plain

 

Android端末(Nexsu6p)でも動作させてみましたが、それほど遅延することはありませんでした。


ただ、この演出が本当に必要なのかどうかはまた別の話で・・・

◇プライバシーポリシー

●個人情報の利用目的

当ブログでは、メールでのお問い合わせ、メールマガジンへの登録などの際に、名前(ハンドルネーム)、メールアドレス等の個人情報をご登録いただく場合がございます。

これらの個人情報は質問に対する回答や必要な情報を電子メールなどをでご連絡する場合に利用させていただくものであり、個人情報をご提供いただく際の目的以外では利用いたしません。

●個人情報の第三者への開示

当サイトでは、個人情報は適切に管理し、以下に該当する場合を除いて第三者に開示することはありません。

・本人のご了解がある場合
・法令等への協力のため、開示が必要となる場合

個人情報の開示、訂正、追加、削除、利用停止
ご本人からの個人データの開示、訂正、追加、削除、利用停止のご希望の場合には、ご本人であることを確認させていただいた上、速やかに対応させていただきます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。

●免責事項

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。

当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。

当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

●プライバシーポリシーの変更について

当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。

修正された最新のプライバシーポリシーは常に本ページにて開示されます。