【VRChat】UdonSharpの変数と参照:Inspectorでライトの設定を変える

作成: 2025-12-19最終更新: 2026-09-09

値と参照の違いを「メモ」と「指差す指」でつかみ、ライトの明るさを切り替えます。コードを直したのにInspectorの値が変わらない理由と、Noneのまま動かない定番の詰まりも解説します。

UdonSharpのスクリプトを付けると、Inspectorに設定欄が出てきます。数字を入れる欄と、シーンのオブジェクトをドラッグする欄。見た目は似ていますが、この2つはまったく別のものです。

ここを分けて考えられると、コードを書き換えずに設定だけを変えられるようになります。曖昧なままだと、「コードは正しいのに動かない」に何度もぶつかります。

この記事では、値と参照の違い をつかみ、Inspectorからライトの明るさを切り替えられるようにします。

Inspectorのパネルからデスクランプへ線がつながっている

この記事でわかること

  • 「値」と「参照」の違い
  • コードの初期値とInspectorの値、どちらが使われるか
  • [SerializeField] private を使う理由
  • 参照が None のまま動かないときの気づき方

床のあるシーンと、最初のUdonSharp の内容を試した状態から始めます。

Sponsored


値はメモ、参照は指差す指

変数には2種類あります。この区別が、これから何度も効いてきます。

値はノートに書いたメモ、参照はワールドの実物を指差す指

は、自分のノートに書いたメモです。「明るさ 2.0」「点灯している」「色はオレンジ」。数字や真偽をそのまま持ちます。ノートを書き換えても、ワールドの中のライトはまだ何も変わりません。

参照 は、「あのランプ」を指差す指です。指の先にある実物をいじると、ワールドの見た目が変わります。指が誰も差していなければ、どれだけノートに数字を書いても何も起きません。

VRChatの場面に置き換えると、こうなります。

スイッチのスクリプトは「明るさの数字」を持っている。でも数字だけでは部屋は明るくならない。Inspectorで どのライトを指すか を決めて、初めて押したときに照明が変わる。

もう1つ大事な性質があります。同じライトを、複数のスイッチが指せます。 入口のスイッチも非常口のスイッチも、同じ天井のライトを指していれば、どちらを押しても同じ実物が点きます。値をコピーしているのではなく、実物を共有しているからです。

この記事で使う型を並べておきます。

種類この記事での用途
int押した回数
floatライトの明るさ
bool明るい状態かどうか
stringログに出す名前
Colorライトの色
Light参照操作するライトそのもの
Sponsored

実践:ライトの明るさを切り替える

ボタンを押すたびに、部屋のライトが暗い(0.2)と明るい(2)を行き来します。数値はコードではなくInspectorから変えられるようにします。

1. ボタンとライトを置く

床のあるシーンに、2つ置きます。

名前作り方と設定
VariableButtonCube。Position (0, 1, 1)、Scale (0.4, 0.4, 0.4)
VariableLampLight → Point Light。Position (0, 2, 1)、Range 5、Mode「Realtime」
ボタンとランプの配置

ライトのModeは Realtime にします。Bakedだと、実行中に明るさを変えても見た目が変わりません(照明とベイク で扱った話です)。

違いを見やすくするため、シーンにDirectional Lightがあれば一時的に無効にしておくと分かりやすくなります。

2. 設定を持つスクリプトを書く

Assets/Scripts で「Create → U# Script」を選び、VariableLightSwitch という名前で作ります。

using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class VariableLightSwitch : UdonSharpBehaviour
{
    [SerializeField] private Light targetLight;        // 参照:どのライトを操作するか
    [SerializeField] private float dimIntensity = 0.2f; // 値:暗いときの明るさ
    [SerializeField] private float brightIntensity = 2f; // 値:明るいときの明るさ
    [SerializeField] private Color lightColor = Color.white;
    [SerializeField] private string logLabel = "VariableLight";

    private bool isBright;   // いま明るい状態か
    private int pressCount;  // 押された回数

    private void Start()
    {
        if (targetLight == null)
        {
            Debug.LogWarning("[VariableLight] Target Lightが未設定です。");
            return;
        }
        ApplyLight();
    }

    public override void Interact()
    {
        if (targetLight == null) return;

        isBright = !isBright;
        pressCount++;
        ApplyLight();
        Debug.Log("[" + logLabel + "] count=" + pressCount + " bright=" + isBright);
    }

    // 「いまの状態」を、実際のライトへ反映する
    private void ApplyLight()
    {
        targetLight.color = lightColor;
        targetLight.intensity = isBright ? brightIntensity : dimIntensity;
    }
}

[SerializeField] が付いた5つがInspectorに出ます。付いていない isBrightpressCount は、実行中に内部で使うだけなので出しません。

[SerializeField] private を使う理由 があります。public にしてもInspectorには出ますが、public は「他のスクリプトからもこの変数を触ってよい」という宣言でもあります。ワールドの設定として使いたいだけなら、外から書き換えられない [SerializeField] private のほうが安全です。

ApplyLight() は、状態をライトへ反映する処理をまとめたものです。Start()Interact() の両方から呼ぶので、1か所にまとめておくと片方だけ直し忘れる事故が防げます。

3. 参照と値を割り当てる

VariableButton に Udon Behaviour を追加し、Program Source に VariableLightSwitch を指定します。すると設定欄が出ます。

指定するもの
Target LightHierarchyの VariableLamp
Dim Intensity0.2
Bright Intensity2
Light Color
Log LabelVariableLight
Interaction Text明るさを変える
ドラッグで入れる欄と、��数値を直接書く欄

Target Lightだけが参照 です。ここには数字ではなく、シーンにあるライトそのものをドラッグします。

ここで一度、あえて失敗を見てみてください。Target Lightを None のままPlayすると、Consoleに「Target Lightが未設定です」と出て、押しても何も起きません。コードは正しいのに動かない、の正体がこれです。

確認できたら、VariableLamp をドラッグして入れます。

4. 動かして確かめる

Playして、Gameビューをクリックしてから VariableButton を押します。

操作期待する結果
開始直後ライトの Intensity が 0.2。部屋が暗い
1回押す2 になって明るくなる。Consoleに count=1 bright=True
2回押す0.2 に戻る。Consoleに count=2 bright=False

Play中にInspectorで VariableLamp を選ぶと、Intensityの数字が実際に切り替わるのが見えます。コードが値を書き込んでいる、という実感が持てます。

5. コードを触らずに変える

ここが今回のいちばんの成果です。Playを止めて、Inspectorの Bright Intensity を 5 にしてみてください。

コードは1文字も変えていないのに、押したときの明るさが変わります。設定はコードではなくInspectorにある ということです。

Light Colorをオレンジにすれば、ランプの色も変わります。同じスクリプトを別の部屋のボタンにも付けて、それぞれ別のライトを指させば、部屋ごとに違う明るさのスイッチが作れます。

コードを直しても、Inspectorの値は変わらない

ここで、多くの人が一度は引っかかる現象を先に説明しておきます。

コードの初期値とInspectorの値。一度でも触るとInspectorが勝つ

こういう流れです。

  1. コードに brightIntensity = 2f と書いて、ボタンに付ける
  2. Inspectorに 2 が出る。試しに 8 に変えたら、ちょうどよかった
  3. 後日「やっぱり 3 にしよう」とコードを 3f に直して保存する
  4. Playしても 8 のまま。コードを直したのに変わらない

原因はこうです。一度オブジェクトに付いた変数は、Inspectorに保存された値が本体になります。 コードに書いた数字は「初めて付けたときの初期値」に近いもので、あとから変えても、すでに保存された値は上書きされません。

直し方は3つあります。

  • Inspectorの欄を直接直す(いちばん安全)
  • Inspectorのコンポーネント名を右クリックして Reset(そのコンポーネントの全設定が初期値に戻るので注意)
  • スクリプトを外して付け直す(参照も消えるので、初心者にはおすすめしません)

普段は1つ目で足ります。設定を変えたいときはInspectorを触る、と覚えてしまうのがいちばん早いです。

Sponsored

うまくいかないときは

  • 起動時に「未設定です」の警告が出る → Target Lightが None です。ライトをドラッグします
  • 押したログは出るのに、部屋が変わらない → 指しているライトが違うか、ライトのModeがBakedになっています。Realtimeにします
  • コードを直したのに反映されない → Inspectorの値が優先されています。上の節を参照してください
  • Play中に設定を変えたら、止めたときに戻った → Play中の変更は保存されません。停止してから入れ直します

おまけ:先に知っておくと良いこと

  • 参照は実物を共有する: 2つのボタンが同じライトを指していれば、どちらを押しても同じライトが変わります。片方だけ変えたいときは、別のライトを指すか、スクリプトを分けます
  • UdonSyncedはまた別の話: [SerializeField] はInspectorに出すための印で、他のプレイヤーには何も伝えません。全員に伝えるには [UdonSynced] という別の仕組みが必要です。ネットワーク同期入門 で扱います
  • Inspectorを見やすくする印もある: 変数が増えてきたら、見出しや説明、スライダーの範囲を付けられます。属性でInspectorを整える を参照してください
  • UdonSharpでは書けない書き方がある: 普通のC#で使うプロパティやジェネリクスは、そのままでは通らないことがあります。まずは変数と if で足りる範囲から始めるのが確実です
  • nullチェックは早めに書く癖を: if (targetLight == null) return; の1行があるだけで、参照忘れがエラーではなく警告で済みます

まとめ

変数には、持つものと指すものの2種類があります。

  • 値はノートのメモ、参照はワールドの実物を指差す指
  • 参照が None なら、コードが正しくても何も起きない
  • Inspectorに出したいだけなら [SerializeField] private
  • コードの初期値は「初めて付けたとき」だけ。以後の本番の値はInspectorにある

迷ったときの問いかけは、「これは数字か、それとも実物を指しているか?」 です。ここを分けて考えられると、動かない原因の切り分けが速くなります。

次は、複数のボタンから同じライトを操作します。メソッドとカスタムイベント で、処理を分けて使い回す方法へ進みましょう。処理が動くタイミングを知りたいなら イベントと実行順 が先です。

VRChat このセクションのノート63