【VRChat】配列入門:3灯のライトを1つのコードで順番に切り替える

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

同じ処理をコピペしていた3つのライトを、配列でまとめます。添字が0から始まる理由、範囲外アクセスの防ぎ方、Inspectorで要素が未設定のときの事故を解説します。

部屋に3つのライトを置いて、順番に点けたい。素直に書くと、こうなります。

[SerializeField] private Light light1;
[SerializeField] private Light light2;
[SerializeField] private Light light3;

動きます。でも5個に増やすと5行、10個なら10行です。しかも処理のほうも同じだけコピーすることになり、直すときは全部を直す羽目になります。

この記事では、同じ種類のものをまとめて扱う配列 を使って、3灯のライトを1つのコードで切り替えます。

天井の3つのランプが順番に灯っていく

この記事でわかること

  • 配列でまとめると何が楽になるか
  • 添字が0から始まる理由
  • 範囲外アクセスを防ぐ書き方
  • Inspectorで要素が空のときに起きること

変数と参照 を試した状態から始めます。

Sponsored


配列は、仕切りのあるトレイ

配列は、同じ種類のものを、番号を付けて並べて入れる箱 です。

別々の変数と、仕切りのあるトレイに並べた配列の違い

変数を3つ別々に書くと、それぞれ独立した箱です。名前で呼び分けるしかありません。

配列にすると、仕切りのある1つのトレイになります。番号で選べる ので、「3番目のライト」という指定ができます。ここが決定的に違います。

書き方はこうです。

[SerializeField] private Light[] lights;   // Lightの配列

// 使うとき
lights[0].enabled = true;   // 1つ目
lights[1].enabled = true;   // 2つ目

Light[][] が「配列である」という印です。lights[0][0]添字(そえじ) で、何番目かを指します。

添字は0から始まります。 3個の配列なら 0 1 2 です。3 は存在しません。

最初は違和感がありますが、理由があります。添字は「先頭から何個ぶんずれた場所か」を表しています。先頭は0個ずれているので0番、その次が1番です。

配列が便利なのは、番号を変数にできる ことです。

int index = 2;
lights[index].enabled = true;   // 3つ目が点く

これができると、for で全部を順に処理したり、押すたびに次のライトへ進めたりできます。変数を3つ並べていたら、こうはいきません。

Sponsored

実践:3灯を順番に切り替える

ボタンを押すたびに、点灯するライトが左から右へ移っていきます。3つ目の次は最初に戻ります。

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

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

名前作り方と設定
Lamp0Point Light。(-1.5, 2.2, 1)、Range 4、Intensity 2、Mode「Realtime」
Lamp1Point Light。(0, 2.2, 1)、同上
Lamp2Point Light。(1.5, 2.2, 1)、同上
LampButtonCube。(0, 1, -1)、Scale (0.4, 0.4, 0.4)
3つのライトとボタンの配置

名前を Lamp0 から始めているのは、添字と対応させて混乱を減らすためです。

2. コードを書く

Assets/Scripts で「Create → U# Script」を選び、LampSequence を作ります。

using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class LampSequence : UdonSharpBehaviour
{
    [SerializeField] private Light[] lamps;   // 3つのライトをまとめて受け取る

    private int currentIndex;

    private void Start()
    {
        Apply();
    }

    public override void Interact()
    {
        // 次へ進める。最後まで行ったら0へ戻す
        currentIndex++;
        if (currentIndex >= lamps.Length)
        {
            currentIndex = 0;
        }

        Apply();
        Debug.Log("[LampSequence] index=" + currentIndex);
    }

    // 今の番号のライトだけを点ける
    private void Apply()
    {
        for (int i = 0; i < lamps.Length; i++)
        {
            if (lamps[i] == null) continue;   // 空の欄は飛ばす
            lamps[i].enabled = (i == currentIndex);
        }
    }
}

見どころが3つあります。

lamps.Length を使っています。 配列の要素数を返すプロパティです。3 と直接書くと、ライトを4つに増やしたときにコードも直す必要があります。Length なら、Inspectorで増やすだけで対応できます。

for で全部を回しています。 i が0から Length - 1 まで動きます。i < lamps.Length であって i <= lamps.Length ではないことに注意してください。ここを間違えると、次の節の範囲外アクセスになります。

1つずつ書くのと、配列とforでまとめるのの違い

lamps[i].enabled = (i == currentIndex); の1行で、点けると消すを同時にやっています。「いまの番号と同じなら true、違えば false」という意味です。全部の要素に対して実行するので、前に点いていたものは自動的に消えます。

3. Inspectorで割り当てる

LampButton に Udon Behaviour を追加し、LampSequence を指定します。

Inspectorに Lamps という欄が現れます。配列なので、まずサイズを決めます。

  1. Lamps を開いて、Size3 と入力する
  2. Element 0Lamp0 をドラッグする
  3. Element 1Lamp1Element 2Lamp2 をドラッグする

サイズを増やすと、空の欄(None)が現れます。 必ず全部埋めてください。埋め忘れると、次の節の事故が起きます。

Interaction Text は 次のライト にします。

4. 動かして確かめる

Playして、ボタンを押してみてください。

操作期待する結果
開始直後左のライトだけが点いている。index=0
1回押す真ん中に移る。index=1
2回押す右に移る。index=2
3回押す左に戻る。index=0

ライトを4つに増やしてみてください。 Lamp3 を作り、InspectorでSizeを 4 にして割り当てるだけです。コードは1文字も変えていないのに、4つを順に回るようになります。

これが配列の効果です。

範囲外に手を伸ばさない

配列でいちばん多い失敗が、存在しない番号を指すこと です。

Light[] lamps = new Light[3];   // 0, 1, 2 の3つ
lamps[3].enabled = true;        // 3は存在しない

3個の配列に 3 はありません。実行すると エラーが出て、そこで処理が止まります。 その先のコードは動きません。

0から2までしかない配列に、3は存在しない

防ぎ方は2つです。

1つ目は、Length を使うこと。 数字を直接書かず、常に lamps.Length を基準にします。

if (currentIndex >= lamps.Length)
{
    currentIndex = 0;
}

2つ目は、null を飛ばすこと。 Inspectorで空の欄があると、要素は null になります。そのまま使うとエラーになるので、確認してから使います。

if (lamps[i] == null) continue;   // 空なら飛ばす

continue は「この回はここで終わり、次へ進む」という意味です。空の欄があっても、残りは正しく処理されます。

Sizeを増やして埋め忘れる のが、いちばんよくある事故です。Inspectorで配列を触ったら、必ず全部の欄を見てください。

Sponsored

うまくいかないときは

  • 押しても何も起きない → Lampsのサイズが 0 になっていないか。要素が全部空になっていないか
  • 1つだけ点かない → その番号の要素が None になっています
  • エラーが出て止まる → 範囲外の番号を指しています。Length を使っているか確認します
  • 全部が同時に点くApply() の中で enabled = true を無条件に書いていないか。(i == currentIndex) の比較が必要です

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

  • foreach も使える: 全部を順に処理するだけなら foreach (Light lamp in lamps) と書けます。ただし何番目かが必要なときは for を使います
  • List は使えない: 通常のC#の List<T> はUdonSharpでは使えません。要素数が実行中に変わるデータを扱いたいときは、VRChatの DataListとDataDictionary を使います
  • 配列も同期できる: [UdonSynced] を付ければ配列も共有できますが、要素数が固定されていないと失敗します。使う前に必ず初期化しておきます
  • 配列の中身は参照: Light[] に入っているのはライトそのものへの参照です。片方を変えると、そのライトが変わります(変数と参照 で扱った話です)
  • 名前を0から付けると読みやすい: Lamp0 Lamp1 Lamp2 にしておくと、Inspectorの Element 0 と対応します。Lamp1 から始めると1つずれて混乱します

まとめ

配列は、同じ種類のものを番号で扱う仕組みです。

  • 変数を並べるのではなく、1つのトレイに番号を付けて入れる
  • 添字は0から始まる。3個なら0・1・2
  • 要素数は Length で取る。数字を直接書かない
  • 空の欄(None)はエラーのもと。使う前に確認する

増やしたくなったときの問いかけは、「コードを直さずに、Inspectorだけで増やせるか?」 です。増やせるなら、配列が正しく使えています。

次は、要素数が決まっていないデータを扱います。DataListとDataDictionary で、外部の設定を読み込んでみましょう。人数のような動くデータは プレイヤーイベント が入口です。

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