devlog [naru design]

プログラミングやテクニカルな内容の覚え書き。

ParticleSysmte.Play()を何度か繰り返し呼び出すとパーティクルが発生しなくなる不具合に遭遇。
Unity上では問題なく動いていたが、実機(iPhone)で動かすと不具合が発生する。

問題の発生したスクリプト

検索でUnityAnswersに以下の投稿を発見。

ParticleSystem.Play() does not play particle.

http://answers.unity3d.com/questions/513517/particlesystemplay-does-not-play-particle.html

上記を参考にしてスクリプトを変更。

変更後のスクリプト

パーティクルの発生をPlay()ではなく、(Play on Awakeを有効にした上で)ゲームオブジェクトがEnableになった時に行うように変更。実機で動作を確認、不具合が解消された模様。

Unity4.5.0f6

一斉に風船が飛んで行くイメージをパーティクルで作ってみました。

設定は以下の様な感じ。

スクリーンショット 2014-12-20 1.56.53

RendererのMaterialに、Mobile/Particles/Alpha Blendedシェーダー(風船のPNG画像を適用)で作ったマテリアルを適用してます。

iPhoneクラスのgenerationプロパティからデバイス情報を知ることができます。

Debug.Log(iPhone.generation);

特定の機種を判別したいときには

※判別可能なデバイスは、ドキュメントのiPhoneGenerationを参照

スクリーンサイズからデバイスを判定する方法は
Unity3D:iOSデバイスの判定

ほとんど触っていなかった Shuriken でクラッカー風のパーティクルを作ってみました。

設定は以下の様な感じ。

スクリーンショット 2014-12-11 16.03.38

以前、アプリを開発している時、Random.Range()で取得した乱数の偏りが気になりました。
※厳密に調べたわけでないので本当に偏っているかは分かりません

今は以下の様なRandomControllerクラスを用意して乱数を取得しています。

使用方法は

int n = RandomController.getNumber(128);

で、0以上128未満のランダムな数を取得します。

Random.Range()よりはバラけている感じがします(自分調べ)。

モバイル向けのアプリを開発している時も、ついついOnMouseXXX()を使ってしまいます。
実は公式のドキュメントにはOnMouseXXX()はiOSやAndoridではサポート外と書かれています。

Features currently not supported by Unity iOS

http://docs.unity3d.com/Manual/iphone-unsupported.html

Scripting

– OnMouseDown, OnMouseEnter, OnMouseOver, OnMouseExit, OnMouseDown, OnMouseUp, OnMouseDrag events are not supported.

Features currently not supported by Unity Android

http://docs.unity3d.com/Manual/android-unsupported.html

Scripting

– OnMouseEnter, OnMouseOver, OnMouseExit, OnMouseDown, OnMouseUp, and OnMouseDrag events are not supported on Android.

問題なく動いている間は良いけど、動かなくなった時に「サポート外」と書かれてるので文句も言えません。
潜在的なバグを抱えることにもつながるので、OnMouseXXX()を使わないでタッチデバイス向けのコードを書いた方が良いかな…。

Unity4.5.5

NullReferenceException: Object reference not set to an instance of an object

オブジェクトがセットされていない状態(nullな状態)で、メソッドを実行したりプロパティにアクセスした時に発生するエラーです。

自分の場合は、Awake()やStart()の中身に原因があることが多いです。厄介なことに、エディターで実行している時には発生せずにXcodeプロジェクトとしてビルド&実行した後で発生することがあります。おそらく、自分でスクリプトの実行順を指定しない限り、MonoBehaviourの同じメソッドの実行順は確定していないんだと思います。

エラーが発生するケースの例

CardOnStageクラスのAwake()で、子オブジェクトにアタッチされたLabelOwnerコンポーネントを取得し、続けてSetLabelメソッドを実行しています。

LabelOwnerクラスのAwake()で、UILabelコンポーネントを取得しています。
SetLabelメソッド内では、Awake()で取得済みのUILabelコンポーネントのtextプロパティへ値を設定しています。

上記2つのクラスのAwake()が
 1. LabelOwnerクラス
 2. CardOnStageクラス
の順番に実行されていればNullReferenceExceptionは発生しません。

実行順が逆になると問題が発生します。

CardOnStageクラスのAwake()のGetComponentは問題なく実行されますが、次のSetLabelメソッドの呼び出しで問題が発生します。この時点ではLabelOwnerクラスの_uiLabel変数にはUILabelコンポーネントが設定されていません(Awakeが実行されていない)。SetLabelメソッド内でtextプロパティに値を設定しようとした時にNullReferenceExceptionが発生してしまいます。

エラーを防ぐには

CardOnStageクラスのAwake()にあったSetLabelメソッドの呼び出しをStart()へ移動すれば問題は起きません。

スクリプトの実行順を指定するか、実行順が変わった時に問題が起きないように注意してコードを書く必要があります。

現在のステートの情報はAnimatorクラスのGetCurrentAnimationStateInfo()で取得する。
取得した値(AnimationStateInfo)には、現在のステートに関する幾つかの値が含まれている。
ただし、この値からステートの名前は直接知ることは出来ない模様。

ss_2014-12-02

予め比較対象のステート名からハッシュを取得しておき、nameHashプロパティの値と比較することで、どのステートに居るかを知る。

7, 8行目 2つのステートのハッシュをレイヤー名とステート名から取得。
13行目 現在のステート情報を取得。
16, 22行目 現在のステートのハッシュと予め取得してあったステートのハッシュと比較。