PG日誌

各記事はブラウザの横幅を1410px以上にすると2カラムの見出しが表示されます。なるべく横に広げてみてください。

Unityで自動実装プロパティに表示名を指定する

作成した経緯的な話

結論を書く前に少し前提的な話をさせてくだい。十分という人はこの項目は読み飛ばして大丈夫です。

少し前に、Unityエディター上のインスペクター上へ自動実装プロパティが表示できるようになりました。

方法はインスぺクター上にこんな感じで自動実装プロパティに対してSrializeFieldを指定します。

fieldを付ける事で、「プロパティ」ついまりsetterとgetterメソッドではなくと背後で自動で作成される見えない変数(バッキングフィールド)に対しSerializedFiedを指定することができます。

[field: SerializeField]
public string Name_1 { get; set; }

[field: SerializeField]
public string Name_2 { get; set; }

で、インスペクター上にこんな感じに表示されます。

f:id:Takachan:20191207212418p:plain

「{xxxx}k_BakingField」と表示されています。C#が後ろで生成した変数がこのような名前なのでそのまま表示したという感じです。

それまではpublic変数を作るかプロパティでくるんでいたものが

// インスペクターに変数を表示するために今までやっていたこと

// (1) フィールドの変数をpublicにして公開(一般的に禁じ手とされている
public int[] Nubers_1 = new int[] { 100, 200, 300 }

// (2-1) 非公開のフィールド変数にSerializedFiedl属性を付ける
[SerializedField]
pribate int[]  Numbers_2 = new [] { 400, 500, 600 }

// (2-2) ただこれだと外部からアクセスできないので
// 外に公開する場合こうやってプロパティを宣言していた
public int[] Numbers_2
{
    get => this.Numbers_2;
    set => this.Numbers_2 = value;
}

とやっていたのですが特に(2)の方は大したことしない変数へのアクセスを提供するだけの場合記述が冗長で面倒でした。

そこで、先述の通り自動実装プロパティにSerialzedFieldを付与してprivateな変数の宣言をなくそうとしたのですが、今度はそうするとインスペクター上の表示がおかしくなるという状態でした。

そこでここのブログに紹介されている

baba-s.hatenablog.com

元々はこっちのフォーラムの投稿ですが、の通りスクリプトを書くと名前がちゃんと表示できるよ!って話だったのですが…

C# 7.3 [field: SerializeField] support

このスクリプトちょっとバグってない?

問題点(1)

一つ目の問題点は、複雑な構造(具体的には「リスト」とか「配列」、「オブジェクト」)を展開すると展開してもインスペクターで正しく表示されません。

// こうやって配列を宣言したり…
[field: SerializedField]
[RenameField("Messages")]
public List<string> Messages { get; private set; }

// ほかのオブジェクトを指定すると…
[field: SerializedField]
[RenameField("Sample")]
public Sample Sample { get; private set; }

そうするとこんな感じに表示が崩れます。

f:id:Takachan:20191207214321p:plain

インスペクター上の折りたたみの三角形を展開すると表示が潰れて内容が見えません。内容が重なって表示されています。一番最後の項目はエディター上の項目が重なって見えないというか存在しません。

問題点(2)

2つ目の問題点は、2階層目以降の要素は名前がちゃんと表示されない。です。

上記の問題を解決したとして次に問題になるのがこれです。

f:id:Takachan:20191207215300p:plain

通常Element0, Element2という風に名前がなるところがプロパティの名前に差し替えられています。

表示名を指定できる「InspectorAttribute」スクリプト

で、上記問題を修正し「InspectorAttribute」を作成したので公開したいと思います。

github.com

ここからダウンロードした中身の「InspectorAttribute.cs」を適当に自分のフォルダに配置します。

そして自動実装プロパティにこんな感じで名前を指定します。

[field: SerializeField]
[field: Inspector(nameof(Sei))] // ★★★ここ
public string Sei { get; private set; }

[field: SerializeField]
[field: Inspector(nameof(Mei))] // ★★★ここ
public string Mei { get; set; }

// リスト and 配列はヘッダー表示名指定しても変な名前のまま…
[field: SerializeField]
[field: Inspector(nameof(MyList))] // ★★★ここ(意味無いけど
public List<Test2> MyList { get; private set; } = new List<Test2>();

使うとこんな感じに表示されます。

f:id:Takachan:20191207221236p:plain

ただ、2つ問題がありこのアセットを使用しても配列やリストの名前は正しく表示されません。残念ながら配列の親要素の名前はどうやっても指定できないのでこれ以上の改善は無理のようです。また、ゲームオブジェクト上に関連付ければ正しく動作しますがスクリプトを直接ヒエラルキーから選ぶとやはり表示が変なままです。

あとリストを展開するときちょっとエディタが重いです。

インスペクターに表示するためだけに通常のC#のコードを冗長にする必要無いと思いますが表示が変なのは気になりますね…

結局Unityエディタ側での正式な対応が無いと完全には解決しないのだ思いました。

スニペット

最後に、上記コードの属性は毎回イピングするのが面倒なのでスニペットを作成しました。

ファイルに保存してVisualStudioからスニペットマネージャーでインポートしてください。

// propu.snippet

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>propu</Title>
      <Shortcut>propu</Shortcut>
      <Description>Unity用のプロパティ生成</Description>
      <Author>Takap</Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>property</ID>
          <ToolTip>プロパティ名</ToolTip>
          <Default>MyProperty</Default>
        </Literal>
        <Literal>
          <ID>type</ID>
          <ToolTip>プロパティの型</ToolTip>
          <Default>int</Default>
        </Literal>
      </Declarations>
      <Code Language="csharp"><![CDATA[[field: SerializeField]
[field: Inspector(nameof($property$))]
public $type$ $property$ { get; private set; }$end$]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>