(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

Sorting Layer一覧を取得する【Unity】【エディタ拡張】【C#】


このエントリーをはてなブックマークに追加

Sorting Layers

簡単に言うとSorting Layersとは2D部分のLayersです。

設定はLayersやTagsと同じく、[Edit]-[Project Settings]-[Tags and Layers]から行えます。


f:id:kan_kikuchi:20150213033838j:plain


同じ場所で設定出来るLayersやTagsは以下の方法で一覧を取得出来るのですが、

何故かSorting Layersはこの方法では取得できません。

InternalEditorUtility.tags
InternalEditorUtility.layers


取得出来ない事は無いよな〜という事で調べてみたら、正攻法かは分かりませんが取得する事は出来たので、その方法のご紹介です!


How do you get a list of Sorting Layers via scripting?

ググっても日本語の情報ではそれらしいものが無かったのですが、

Unity Answersにピンポイントな質問がありました!

How do you get a list of Sorting Layers via scripting? - Unity Answers

これによると以下のコードで取得出来るとの事。

using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Reflection;
 
public class SomeClass {
 
  // Get the sorting layer names
  public string[] GetSortingLayerNames() {
    Type internalEditorUtilityType = typeof(InternalEditorUtility);
    PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
    return (string[])sortingLayersProperty.GetValue(null, new object[0]);
  }
 
  // Get the unique sorting layer IDs -- tossed this in for good measure
  public int[] GetSortingLayerUniqueIDs() {
    Type internalEditorUtilityType = typeof(InternalEditorUtility);
    PropertyInfo sortingLayerUniqueIDsProperty = internalEditorUtilityType.GetProperty("sortingLayerUniqueIDs", BindingFlags.Static | BindingFlags.NonPublic);
    return (int[])sortingLayerUniqueIDsProperty.GetValue(null, new object[0]);
  }
}


実際に試してみたら確かに出来ました…!


コード説明

取得出来たのいいのですが、たった3行しかないのに

コードの意味がサッパリだったのでちょっと調べてみました。


Type internalEditorUtilityType = typeof(InternalEditorUtility);

これはInternalEditorUtilityという

tagsとかlayersとかを取得したクラスのTypeを取得してるようです。


よく考えたら、そもそもInternalEditorUtilityって何?って話ですが、

基本的に便利メソッド集的なポジションに居るのがInternalEditorUtilityクラス


だそうで、設定されてる情報を取得出来るクラスのようです。


PropertyInfo sortingLayerUniqueIDsProperty

PropertyInfoはそのままプロパティの情報で、先ほどのInternalEditorUtilityから

GetPropertyする事で取得しています。


このGetPropertyをする時に、取得したいプロパティ名とそのプロパティのフラグを設定します。

このフラグがBindingFlags.NonPublicなのがミソな気がします(?)


NonPublicという事は通常では取得できないという事で、

このせいで、tagsやlayersと同様の方法では取得出来なかったようです。


また、これはC#のリフレクションという機能だそうで、

テスト時にPrivateなメソッドを実行したりも出来るらしいです。

C# には、クラス名やメンバー名などの情報を実行時に取り出したり、 あるいは、クラス名の文字列からクラスのインスタンスを動的に生成したりする機能(リフレクション)があります。

実行時型情報 (C# によるプログラミング入門)


sortingLayersProperty.GetValue

取得したPropertyInfoからGetValueする事でその設定値を取得しています。

ただ引数の意味がよく分からぬ…

GetValueメソッドの第1パラメータには(プロパティが含まれるクラスの)インスタンスを設定し、第2パラメータはそのプロパティが「インデックス付きプロパティ」(=インデクサ)の場合、そのインデックス値を指定する(インデックス付きプロパティではない場合には「null」や「Nothing」を指定する)。

@IT:.NET TIPS メソッドやプロパティの有無を確認して呼び出すには? - C# VB.NET


第1引数nullでもいいの?インデクサ??

ワカラナイ!アキラメタ!


Sorting Layer名を定数で管理するクラスを作成するエディタ拡張

せっかくSorting Layersの一覧が取得できたので、

ConstantsClassCreatorを使って、Sorting Layerの名前を定数で管理するクラスを作っちゃうエディタ拡張を作っちゃいました!

コードは以下の通りです。



これをEditorディレクトリに入れて、[Tools]-[Create]-[Sorting Layer Name]をすると以下のようなファイルができます。

/// <summary>
/// ソーティングレイヤー名を定数で管理するクラス
/// </summary>
public static class SortingLayerName
{
    public const string DEFAULT    = "Default";
    public const string NEW_LAYER1 = "New Layer 1";
    public const string NEW_LAYER2 = "New Layer 2";
}


便利!


おわりに

なんとなくC#使えるようになった気はして来てましたが、知らない事ばかりですね…

プログラムズカシイ!