Editorで編集中に気づくと何故かNullReferenceExceptionのエラーが出ている件
Editorで編集中に気づくと、たまに、
NullReferenceException: Object reference not set to an instance of an object
というエラーが出ていて、編集中に?何故?Editor拡張周りに何かバグが?って思っていたのですが、違いました。
理由は、Reset関数のせいでした。
以下、引用。Reset関数とは、
デフォルト値にリセットします
Reset はインスペクターのコンテキストメニューにある Reset ボタンやコンポーネントを初めて追加するときに呼び出されます。 この関数はエディターモードのみで呼び出されます。Reset はインスペクターでデフォルト値を設定するときにもっともよく使用されます。
ということです。そんな特別な関数になるとはつゆ知らず。普通にResetという名前の関数を作っていました。
例えば、以下の様な関数
public void Reset() { cachedTransform.localPosition = startPosition; }
cachedTransformは以下のようにStart関数で与えるようにしていたので問題が。
void Start()
{
cachedTransform = transform;
}
当然、Editorで編集中はStart関数が呼ばれていないのでcachedTransformはnullなわけです。とほほ。
というわけで、Reset以外に良い名前はないかと考えてみたんですが、なかなかよい名前が思い浮かばない... 妥協してResetParamsという関数名に変更して対処しました。
それにしても、今回のResetもそうだけど、Unityの、StartとかUpdateとかAwakeとか、仮想関数でも無いのに勝手に呼ばれるのが怖い。
処理高速化のためとはいえ、なんとかならんものか。せめて命名規則とかでそれっぽくしておいて欲しい。全部頭にOnをつけて、
OnStart
OnUpdate
OnAwake
OnReset
ってするとか。
MonoBehaviourのAwake、Start、Updateという関数が呼ばれる仕組み
MonoBehaviourを継承してAwake、Start、Update等という関数を作るとUnity側で勝手に呼んでくれますが、これがいったいどういう仕組で動いているのかが謎でした。
最初、MonoBehaviour側にvirtualな関数、もしくはabstractな関数で定義されているのかとも思ったのですが、overrideしなくても書けますし、定義を書かなくてもコンパイルエラーにもなりません。
C#にはReflectionという機能があり、これを使うと実行時にクラス名やメンバ名などが取得できます。これを使っているのではという説もあったのですが、どうもそうではないようです。
答えは、ここにありました。
一部引用すると、
任意の型のMonoBehaviourが初めてその基底のスクリプトにアクセスしたときに、スクリプティングランタイム(MonoもしくはIL2CPP)によって何かのマジックメソッドが定義されているかを調査され、この情報がキャッシュされます。もしMonoBehaviourが特定のメソッドを持っていたら所定のリストに追加されます。例えばスクリプトがUpdateメソッドを持っていたら「毎フレームUpdateを呼ぶべきスクリプトのリスト」に追加されるわけです。
ゲーム中は、Unityは短にこのリストをイテレーションしてメソッドを呼んでいきます – シンプルです。また、これがUpdateメソッドのアクセス権がpublicであろうとprivateであろうと関係ない理由でもあります。
ということです。言い方は悪いですが、Unityのコンパイラが言語規約に無いことを勝手にゴニョゴニョやっているということみたいです。
これは無駄な仮想関数呼び出しを避けるためのようです。
例えば、もしMonoBehaviour の中身が
public abstract class MonoBehaviour { protected virtual void Update() {} }
というものであった場合、Updateをoverrideしていないクラスに対しても空のUpdateを呼び出すことになってしまい、結構な処理時間を食います。
これを避けるための仕組みなわけですね。ゲーム作っている人としては非常にありがたい仕組みです。
しかし、Unityが.Net Foundationに参加したことで、この辺りももしかしたら変わってくるかもしれませんね。
Unity+iOSでitunes connectにアップロードする際にERROR ITMS-90086が出た時の対処
先日、itunes connectにアプリをアップロードしようとしたら以下の様なエラーが出ました。
ERROR ITMS-90086: "Missing 64-bit support. iOS apps submitted to the App Store must include 64-bit support and be built with the iOS 8 SDK or later. We recommend using the default "Standard Architectures" build setting for "Architectures" in Xcode, to build a single binary with both 32-bit and 64-bit support."
64bitもサポートせなあかんよと言われているようです。
Unityの方で、
Player Settings -> Other Settings -> Scripting Backend を IL2CPP に、
Player Settings -> Other Settings -> Architecture を Universal に変更することで対処できました。
play.google.com
ゲームビューでの見え方を確認しつつシーンビューでパラメータ調整する方法3つ
1, シーンビューとゲームビューを並列に並べて作業する
一番シンプルな方法。編集画面が狭くなりがちなのが難点です。
2, シーンビューの見え方をゲームビューと同じにする
- Cameraを選択する
- 「GameObject」->「Align View to Selected」を選択する
こちらはシーンビュー自体がプレビュー代わりになるので、好きな位置にビューを動かして編集する、ということができないのが難点です。
3, Camera Previewを出しっぱなしにする
直接的にCamera Previewを出しっぱなしにするような方法はないようなのですが、
1. HierarchyからCameraを選択する
2. Inspectorと書かれたところ右クリックしてLockする
3. Inspectorと書かれたところ右クリックして、「Add Tab」でもう一個Inspectorタブを追加し、そっちで編集する
という方法で実現可能です。
個人的にはこの方法が一番使い勝手が良いですね。
UnityのInputFieldでちょっとハマったこと
文字を入力するUIとして便利なInputFieldを使っていてちょっとハマったのでメモ。
入力された文字は、InputField以下のTextオブジェクトに入り表示されます。
しかしTextオブジェクトが十分に大きくない場合は、最初に入力した文字が削られたものしか入っていません。
下画はInputFieldに"123456789"という文字列を入れたところですが、Textには56789しか入っていません。
実際に入れた文字列"123456789"を取得するには、InputField自体が持つtextプロパティにアクセスすれば取得できます。
つまり
inputField.text != inputFieldの子供のText.text;
ということです。
後から考えると当たり前みたいな話ですが、ちょっとハマったのでメモしておきます。
play.google.com
Hierarchyに、オブジェクトのアクティブを変更するチェックボックスと、オブジェクトの編集可能不可能を変更するアイコンと、無効なコンポーネントがアタッチされているかどうかを表示。
長いタイトルですいません。
下記のスライドの中でHierarchyに関数エディタ拡張の例がいくつか紹介されていたのですが、
http://www.slideshare.net/shotababa359/unity-49731764
この中から自分的に使いそうだった
の3つをピックアップしてまとめただけです。。。
こんな感じになります。
以下、ソース。
play.google.com
Unity5.4.0にしたら、Pluginが重複してるっていうエラーがでた
Unity5.4.0にしてiOSのビルドをしようと思ったら以下の様なエラーが、
Plugin 'GoogleMobileAds.framework' is used from several locations: Assets/Plugins/iOS/GoogleMobileAds.framework would be copied to <PluginPath>/GoogleMobileAds.framework Assets/Plugins/Android/GoogleMobileAds.framework would be copied to <PluginPath>/GoogleMobileAds.framework Please fix plugin settings and try again.
どうも、GoogleMobileAds.frameworkが重複しているよーとのこと。
おかしいな。Plugin以下のiOSフォルダには、GoogleMobileAds.frameworkは一個しか無いのに...
他にもあるのは、Androidフォルダ以下だし...
っと見てみると、Androidフォルダ以下のGoogleMobileAds.frameworkの設定はAny Platformになっていた。
どうも、これが原因らしい。
Anyのチェックを外してAndroidにチェックを入れるようにしたら無事ビルドできました。
Unity5.4.0になって、この辺りをよりしっかりチェックするようになったみたいですね。