Unityでインスペクタから変更できて、外部classから参照はできるが変更はできない便利な変数を一行で書く方法

手っ取り早く方法だけ知りたい方は「2」からどうぞ


1:順を追って説明

一般的な変数の作り方はこう

string name = "名前";
int age = 10;

でもこれじゃインスペクタから変更できませんよね🤔
なのでインスペクタから変更できるようにするにはこうです

[SerializeField] string name = "名前";
[SerializeField] int age = 10;

先頭に[SerializeField]をつけました
これでインスペクタから変更できるようになってニッコリ😇
が!これでは外部classから値の参照も変更もできません
じゃあ外部classから参照も変更もできるようにしましょう

public string name = "名前";
public int age = 10;

[SerializeField]をpublicに変えました
これでインスペクタから変更できるうえに外部classから参照も変更もできるようになって再度ニッコリ😇
が!!参照はいいとして外部classから変更されると困る場合がありますよね
じゃあ外部classから参照はできるが変更はできないようにしましょう

[SerializeField] string name = "名前";
[SerializeField] int age = 10;

public string Name{
    get{ return name; }
}

public int Age{
    get{ return age; }
}

publicを[SerializeField]に戻しゲッター(get)を書きました
これでインスペクタから変更できるうえに外部classから参照はできるが変更はできないように…
なったのはいいが急に記述が増えました!😫
しかも同じ変数名のまま使えないから頭文字を大文字にしたり違う名前にしないといけない!😫
同じ変数名のまま使いたいしもっとシンプルにしたい!😫
じゃあその要望にこたえましょう

public string name {get; set;} = "名前";
public int age {get; set;} = 10;

//ちなみに以下のようにgetだけしか書かない場合は自分のclassからも代入できなくなります
public string name {get;} = "名前";
public int age {get;} = 10;

やはり[SerializeField]をpublicに戻し変数名をそのまま使えるように一行で対応しました
いわゆる自動実装プロパティというやつですね
でもこれだとセッター(set)も書いているので参照も変更もできるからpublicだけの時とほぼ変わらんよね?🤔
その通りなので外部classから変更だけできないようにしてみましょう

public string name {get; private set;} = "名前";
public int age {get; private set;} = 10;

setだけprivateにして自分のclassからしか変更できないようにしました
これで全ての願いが叶った!やったね!!😇

いや、これpublicやのにインスペクタに出てないから!😫
ハイ、自動実装プロパティにしてしまうとインスペクタから変更できません
ほなどないしたらええんじゃい!😡
と、お嘆きのアナタ
やっとここでこの記事のタイトルを回収しましょう

2:書き方

[field: SerializeField] public string name {get; private set;} = "名前";
[field: SerializeField] public int age {get; private set;} = 10;

自動実装プロパティの先頭に[field: SerializeField]を追加しました
これならインスペクタから変更できるうえに、外部classから参照はできるが変更はできず、それでいて変数名は同じまま使えるので一行で書ける!
めちゃくちゃ便利になりましたね!
じゃあもう全部これでええな😇

いや、ちょっと待ってください
なんやねん!まだ何かあるんか!しんどいしんどい!😫
という気持ちもわかるんですが、一応メリット・デメリットがあるんで聞いておいてもらいたいなと

3:メリットとデメリット

▼メリット
・インスペクタから変更できる
・外部classから参照はできるが変更はさせない
・それでいて変数名は同じまま使える
・一行で書ける
▼デメリット
・普通に定義するだけの変数よりも記述が長い
・直上にアトリビュートが使えない
・Unityのインスペクタ上での表示ルールが無視される

デメリットについてもうちょっと詳しく書いておきます

1つ目の「普通に定義するより記述が長い」はそのままですね
単純に「int age = 10;」だけで済むのを長くする意味はないですよね
外部classから何もする必要がないならなおさらです😤

2つ目の「直上にアトリビュートが使えない」というのは以下の通りです

[Header("プレイヤー名")]
[field: SerializeField] public string name {get; private set;} = "名前";
[Range(0, 100)]
[field: SerializeField] public int age {get; private set;} = 10;

アトリビュートはインスペクタにわかりやすい名前をつけたり値の制限をしたりする等々の便利な機能ですが、「field:」を使った場合は直上にアトリビュートを書くとエラーが出ます
ただ、これに関しては一応逃げ道があります

[field: SerializeField, Header("プレイヤー名")] public string name {get; private set;} = "名前";
[field: SerializeField, Range(0, 100)] public int age {get; private set;} = 10;

「field:」より後ろに「,」で区切って書けば機能します
RangeはともかくHeaderを後ろに書くのは個人的には気持ち悪いですが…🙄
また、他所様の「field:」説明記事に「変数名の変更をする時に値を引き継ぐFormerlySerializedAsが使えない」というのを見かけますが、基本的にそれもアトリビュートなので「field:」の直上に書けばエラーですが、後ろに書けば問題なく機能します(確認済み)
要するに直上に書くアトリビュート全般が効かないという事のようです
ちなみに直上にアトリビュートを書く場合、間に何か記述があればエラーは出ません(空白や改行やコメントはダメですが)

3つ目の「インスペクタ上での表示ルールが無視される」ですが、Unityでは「iPad」や「x64」など一部の特殊なケースを除き、変数名によってインスペクタに表示されるルールが決まっています
例をあげると

  • 先頭から始まる「m_」は削除されて表示

  • 先頭から始まる「k」は削除されて表示

  • 先頭から始まる「_」は削除されて表示

  • 先頭の文字を大文字にして表示

  • 小文字と大文字の間にスペースを加えて表示

  • 頭文字と次の単語の先頭にある大文字の間にスペースを加えて表示

「field:」の場合はこれらのルールが無視されます
なので、「field:」をつけた変数は打った文字がそのまま表示されます
個人的には普通の変数もそうしてくれる方が好みなんですけどね🙄

以上、これらはすごく厳しいデメリットではないけど、便利だから多用するというようなもんでもないです
外部classから操作しないなら[SerializeField]だけで十分ですし、ちゃんとゲッターやセッターを実装しておいた方がいい場面もあるし、なんなら自動実装プロパティの方がよく使うまであるし、そのあたりは状況に応じて使い分けするのがいいと思います
そしてここぞという時には思い出してぜひ活用してみてください😇

4:あとがき

私が作ってUnityアセットストアで販売しているキャラクターコントローラー「FPController」でも一部これを利用しています
どういう場面で使っているかはぜひ買って確かめてみてください😇
キャラクターコントローラーとしてもめちゃくちゃ便利だと思いますし、なによりプログラムの処理全てに日本語で解説コメントを書いているのでプログラムの学習にもなります(たぶん)😇😇😇

ちなみにこの「FPController」を使って作られたゲーム「44 Minutes in Nightmare」も面白いのでぜひ遊んでみてください!😎(ダイレクトマーケティング)


この記事が気に入ったらサポートをしてみませんか?