【Unityあるある】C#スクリプトの初期値がなぜか反映されない…(Inspector優先の罠)

Unity

スクリプトの初期値が反映されない? それ、Inspectorのせいかもしれません

Unityで開発していて、変数の初期値をコードで設定したのになぜか反映されない!
「ちゃんと int i = 100; って設定してるのに…」となったことはありますか?
私はたまに忘れた頃にやらかして、数分〜10分程度を無駄にすることが何度かありますw

結論から言うと、これは Inspectorにすでに保存された値が優先される という、Unity特有の仕様が原因です。
しかもこの仕様、一度でもInspector上で値が設定された変数は、コードの変更を無視するという仕組みなんです。

そう!これはUnityの仕様!たまに忘れる私が悪い!w


なにが起きてるのか?

たとえばこんなコードを書いたとします。

public class TestEnemy : MonoBehaviour
{
    public int hp = 100;
}

この状態で TestEnemy をアタッチした GameObject を作ると、Inspectorには「hp = 100」と表示されます。
さて、この後スクリプトを変更して、hpの初期値を 200 に変えてみます。

public int hp = 200; // ←ここを変更!

だがしかし!
ゲーム実行時も、Inspector上でも、hpは「100」のまま。

Unityの「シリアライズ優先」の仕様

Unityは、一度でもInspector上で変数が保存されると、コード上の初期値を無視してInspector側の値を使い続ける仕様になっています。

つまり、

public または [SerializeField] 付き変数
→ 初めてInspectorに表示された時点で、その値が「保存」される
→ 以後、スクリプトの初期値を変更してもInspectorには反映されない

コードで hp = 200 にしても、Inspectorが「100」を覚えてるからそっちが使われるんですね。
=Inspectorが勝つ ということです。

解決方法:リセットする or 設計を変える

方法①:Resetを使う

GameObjectを選択して右クリック → Reset を押すと、Inspectorに保存された値がリセットされ、コード上の初期値が反映されます

ただし、他の変数まで全部初期化されてしまうので注意。


方法②:Inspectorの値を直接変更する

手動で値を変えればOKですが、意図せず「コードと違う値」が残り続ける危険があります。


方法③:初期値の管理を Awake() や Start() に寄せる

例えばこんなふうにします:

csharpコピーする編集する[SerializeField]
private int hp;

void Awake()
{
    if (hp == 0) hp = 200;
}

このように 初期化をコードで強制する方法もあります。
ただし「本当に0の可能性がある値」は注意が必要(boolやfloatなど)。


方法④ : そもそもInspectorに表示させない(変更方法を統一する)

public や SerializeField を使わず、コードだけで設定するようにする。
どうしてもpublicにしないといけない設計なら、[HideInspector]などで非表示にしちゃう。

もしくは逆に Inspectorの設定のみにして、コードの変数初期化は使わない、と決めてしまう。
どちらかに統一されてれば間違う可能性は下がりますね。


私は方法④のコードのみの設定になることが多いです。
そもそも外に出さない作りにしちゃえば、こんな問題遭遇することはないんですよ…!←

まとめ

個人的にこの「Unityあるある」は開発時に遭遇してイラつくことNo.1です。
(え?遭遇しますよね?私だけ?)

デフォルト値を変えたのに動かない
→ デバッグに時間を使う
→ よく見たらInspectorに前の値が残ってるじゃねぇか!
ってので時間を無駄にするのが本当に嫌いです。

初心者のこと引っ掛かってた系で言うと、「シーン再生時、再生していることを忘れてInspector変更→変更内容が消える」もあるあるかな…

もし何か他にもあるある系のネタをお持ちであれば、ぜひ教えてくださいw

コメント

タイトルとURLをコピーしました