Version: 2022.1
言語: 日本語
その他の Unity5.0 アップグレードノート
Unity 3.5 アップグレードガイド

4.0 へのアップグレードガイド

GameObject の active の状態

Unity 4.0 では GameObject のアクティブ(active)状態の操作の仕方が変わりました。GameObject のアクティブ状態は親子構造の子の GameObject へ引き継がれるので、非アクティブの GameObject の子はすべて非アクティブになります。新しい挙動は古いものよりも役に立つと思いますし、いつもこの方法にすべきです。また今後実装予定の新しい GUI システムではこの新しい挙動に依存し、それなしでは実現が不可能です。残念なことですが、新しい Unity 4.0 の挙動のせいで今まで作っていたプロジェクトを修正するためにいくつか作業が発生してしまいます。下記がその作業項目です。

旧仕様

  • GameObject がアクティブかそうでないかは .active プロパティで定義されます。
  • これは .active プロパティのチェックで判定と設定が可能です。
  • 一つの GameObject のアクティブ状態はその子の GameObject 群には影響しません。自分の子すべてに影響させたいのであれば GameObject.SetActiveRecursively を呼ぶ必要があります。
  • 親の GameObject で SetActiveRecursively を使うと、その前までに設定していた子の GameObject のアクティブ状態は失われます。親と子の GameObject に対し SetActiveRecursively を使って非アクティブ→アクティブにすると、それらはすべてアクティブになります。もし子のアクティブ状態を維持したいのであれば、それらを手動でアクティブに設定しなくてはなりませんでした。
  • プレハブはアクティブ状態を含まなかったので、Prefab からインスタンスを作った後は必ずアクティブでした。

新仕様

  • GameObject がアクティブかそうでないかは、それ自身とその上のすべての親の、.activeSelf プロパティで定義されます。もしそれ自身の .activeSelf プロパティとその親すべての .activeSelf プロパティが true ならば、GameObject がアクティブになります。もし親のいずれかが false ならば、その GameObject は非アクティブになります。
  • これは .activeInHierarchy プロパティを使って判定されます。
  • GameObject の .activeSelf 状態は GameObject.SetActive を呼び出すことで変更できます。その前まではアクティブだった GameObject で SetActive (false) を呼びだすと、その GameObject とその子がすべて非アクティブになります。その前までは非アクティブだった GameObject で SetActive (true) を呼び出すと、その GameObject とその子がすべてアクティブになります。子たちはその親すべてがアクティブになってはじめてアクティブなります。(例:すべての親の .activeSelftrue に設定)
  • これは次のことを意味します:アクティブ状態は親から引き継ぐものなので、もはや SetActiveRecursively は必要なくなりました。さらに次のことも意味します:ヒエラルキーあるヶ所でアクティブ/非アクティブは SetActive を呼んでも、子の以前のアクティブ状態は保存されます。
  • プレハブはアクティブ状態を含むようになったので、Prefab から作ったインスタンスはその状態に準じます。

3 つの GameObjectA、B、C があり、B と C は A の子であるとします。

  • C.SetActive(false) を呼び出すことによって、C を非アクティブにします。
  • ここでは、A.activeInHierarchy == trueB.activeInHierarchy == trueC.activeInHierarchy == false となります。
  • 同様に、A.activeSelf == trueB.activeSelf == trueC.activeSelf == false となります。
  • 同様に、A.activeSelf == trueB.activeSelf == trueC.activeSelf == false となります。
  • そうなると、A.activeInHierarchy == falseB.activeInHierarchy == falseC.activeInHierarchy == false となります。
  • 同様に、A.activeSelf == falseB.activeSelf == trueC.activeSelf == false となります。
  • ここで A.SetActive(true) を呼び出すことによって、再び親をアクティブにします。
  • そうなると、A.activeInHierarchy == true に戻り、B.activeInHierarchy == trueC.activeInHierarchy == false となります。
  • 同様に、A.activeSelf == trueB.activeSelf == trueC.activeSelf == false となります。

エディターでの新しいアクティブ状態

これらの変化を可視化するために、Unity 4.0 のエディターでは、非アクティブの GameObject は、Hierarchy で暗く表示されます(それ自身が .activeSelf プロパティが false 、またはその親がそうなっていれば)。Inspector でもアイコンは暗く表示されます。GameObject の自身の .activeSelf プロパティは active チェックボックスをオンにすると反映されます。親状態に関係なく切り替えることができます(ただし、すべての親がアクティブである場合、このチェックだけでその GameObject をアクティブになります)。

これは、既存のプロジェクトにどのように影響するか

  • GameObject.active プロパティと GameObject.SetActiveRecursively() 関数の廃止によって、あなたのコードの中に影響を与える可能性のあります。
  • しかし、それらはまだ機能しています。GameObject.active の値を読むことは GameObject.activeInHierarchy の値を読み取ると同等であり、GameObject.active を設定することと GameObject.SetActive() の呼び出しと等価です。GameObject.SetActiveRecursively() を呼び出すことは、その GameObject とそれのすべての子に GameObject.SetActive() を呼び出すことと等価です。
  • 3.5 からの引き継がれるシーンでは、シーン内のすべての GameObject の selfActive プロパティは、3.5 で設定していた active プロパティが引き継がれて、インポートされます。
  • 結果として、Unity の以前のバージョンからインポートされたプロジェクトは(コンパイラの警告はあるものの)期待通りに動作するでしょう。ただしそれは、( Unity 4.0 で利用できない)非アクティブの GameObject がアクティブの子 GameObject を持つことに依存していないことが前提です。
  • 結果として、Unity の以前のバージョンからインポートされたプロジェクトは(コンパイラの警告はあるものの)期待通りに動作するでしょう。ただしそれは、( Unity 4.0 で利用できない)非アクティブの GameObject がアクティブの子 GameObject を持つことに依存していないことが前提です。

アセット生成工程パイプラインの変更

4.0 の開発の過程で、当社のアセットインポートパイプラインは、パフォーマンス、メモリ使用量、安定性を向上させるために、内部のいくつかの重要な工程が変更されました。これらの変更はほとんどの部分については影響はありません。例外として、アセット内のオブジェクトは、インポートパイプラインの最後の最後まで以前にインポートされたバージョンのものが存続し、最後に完全に置き換えられます。

最初のパートでは、ポストプロセス時には、アセット内のオブジェクトへ正しい参照を取得することはできないことを意味し、次のパートでは、ポストプロセス中の変更を保存している間、前のインポートしたバージョンへ参照を使う場合、それらの変更が失うことを意味します。

永続的ではないという理由で、参照が失われる例

次の短いコード例でみてみます。

public class ModelPostprocessor : AssetPostprocessor
{
    public void OnPostprocessModel(GameObject go)
    {
        PrefabUtility.CreatePrefab("Prefabs/" + go.name, go);
    }
}


Unity3.5 では、これはメッシュ等の正しい参照を持ったプレハブが生成されるでしょう。これはすべてのメッシュがすでに永続化されているからです。しかし、Unity4.0 の場合ではそうならないので、同じポストプロセッサーでもメッシュへの参照が切れたプレハブを作成します。それは、Unity4.0 のはまだ元のモデルプレハブ内のオブジェクトへの参照を解決する方法を知らないという単純な理由です。正しく modelprefab をコピーするには、すべてのアセットのインポートをやり過ごす OnPostProcessAllAssets を使うべきです。そうすると modelprefab をみつけて、上記のように新しいプレハブを作成します。

前にインポートして、捨てられるアセットへの参照の例

二番目の例は少し複雑ですが、実際にあった、3.5 で正常に動いたものが 4.0 で動かなくなったケースです。ここでは ScriptableObject は簡単なメッシュへの参照を持っているとします。

public class Referencer : ScriptableObject
{
    public Mesh myMesh; 
}


モデル内のメッシュへの参照を持つアセットを作成するために、この ScriptableObject を使います。その後ポストプロセッサーで、その参照を持ってきて、別の名前を付け、モデルを再インポートした際にメッシュの名前は最終的な結果はポストプロセッサーが決定します。

public class Postprocess : AssetPostprocessor
{
    public void OnPostprocessModel(GameObject go)
    {
        Referencer myRef = (Referencer)AssetDatabase.LoadAssetAtPath("Assets/MyRef.asset", typeof(Referencer));
        myRef.myMesh.name = "AwesomeMesh";
    }
}


これは Unity3.5 でうまくいきましたが、Unity4.0 ですでにインポートされたモデルを完全に置き換えられますので、前回のインポートからメッシュの名前を変更しても影響はありません。ここでの解決策は、何か他の手段によってメッシュを見つけて、その名前を変更することです。注意するべきもっとも重要なことは、Unity 4.0 ではポストプロセッサーに与えられた入力を修正する「だけ」にするべきで、同じアセットの以前にインポートされたバージョンをあてにしないことです。

メッシュの読み取り/書き込みオプション

Unity 4.0は、モデルインポート設定に「Read/Write Enabled」オプションを加えました。このオプションをオフにすると、Unityはメッシュデータのコピーをゲーム内でアンロードできるため、メモリを節約します。

ただし、あなたは単にスケーリングしたり、や非線形なスケールを使用して実行時にメッシュをインスタンス化したりしている場合は、あなたはそれらのインポート設定で “Read/Write Enabled” を有効にする必要があります。その理由は、非線形なスケーリングはメッシュデータをメモリ内に保持する必要があるからです。通常、ビルド時にこれを検出しますが、メッシュは、実行時にスケーリングやインスタンス化されるときには、これを手動で設定する必要があります。そうしないと、ビルドされたゲームの中で正しくレンダリングされない場合があります。

メッシュの最適化

Unity 4.0 の Model Importer は、メッシュの最適化が改善されました。Unity 4.0 では Model Importer の “Mesh Optimization” チェックボックスがデフォルトで有効になっており、最適なパフォーマンスを出すためにメッシュ内の頂点の順序を変更します。あなたのプロジェクト用の、メッシュの頂点の順序に依存するポストプロセスのコードや効果は、この変更によって壊れる可能性があります。その場合には、Mesh Importer の “Mesh Optimization”はオフにしてください。SkinnedCloth コンポーネントを使用している場合は特に、このメッシュの最適化で、頂点ウェイトのマッピングが変更されることがあります。 3.5 から引き継いだプロジェクトで SkinnedCloth を使用しているのであれば、影響を受けるメッシュの “Mesh Optimization”をオフにするか、新しい頂点の順序と一致するように頂点ウェイトを再構成する必要があります。

モバイル入力

Unity 4.0 によりモバイルセンサー入力はプラットフォーム間の整合性が改善され、具体的にはモバイルプラットフォームで典型的な入力をハンドリングする場合にコードの記述する量が少なくなっています。改善により加速度センサーとジャイロセンサーの入力は iOS と Android で同じように画面の向きに従います。この変更を活用するには、入力に関わるコードのリファクタリングを行い、加速度センサーとジャイロセンサーの入力のハンドリングを行う際のプラットフォームと画面の向きに固有のコードを削除します。iOS で以前の仕様をそのまま使用したい場合は Input.compensateSensors を false に指定します。

その他の Unity5.0 アップグレードノート
Unity 3.5 アップグレードガイド