見出し画像

UdonSharpを使ったインタラクト作例5つ

VRChatでUSEしたときにInspector上の設定した値に基づいてどのような動きをするのか切り替えできるプログラムをご紹介します。実際に動かしてプログラムの動きを確認ができれば幸いです。

今回紹介する5つの動作は下記のとおりです。
・回転の変更
・大きさの変更
・色の変更
・表示非表示の切り替え
・移動


作例5つ

回転の変更

まず前回の記事で作ったキューブの回転を行うプログラムを見てみます。
UdonSharp導入までの解説も前回の記事にまとめていますので、導入がまだの場合はこちらから進めてみてください。



using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class Cube : UdonSharpBehaviour
{
    [SerializeField]
    float rotationSpeed;

    bool isRotateInvert;

    void Start()
    {
        
    }
    
    void FixedUpdate()
    {
        if (isRotateInvert)
        {
            transform.localEulerAngles += Vector3.up * Time.deltaTime * -rotationSpeed;
        }
        else
        {
            transform.localEulerAngles += Vector3.up * Time.deltaTime * rotationSpeed;  
        }
    }

    public override void Interact()
    {
        isRotateInvert = !isRotateInvert;
    }
}

今回はこのプログラムを発展させていきたいと思います。Inspector上からどの動きをするのか決められれば何度もプログラムを作り直す必要がなく、値を切り替えるだけですぐに動きを確認できます。

下記のようにしてみました。これでInspector上にコントロールが表示されますので、このコントロールから対応した数字のプログラムが動くようになります。


using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class Cube : UdonSharpBehaviour
{
    // このように表記するとInspectorに1~10までの数字を選べるスライダー表示されます。
    [SerializeField]
    [Range(1, 10)]
    int type;

    [SerializeField]
    float rotationSpeed;
    
    bool isRotateInvert;

    void Start()
    {

    }

    void FixedUpdate()
    {
        // switchは()の中の変数の値を見て、どの処理を行うか選べる処理です。
        switch (type)
        {
            // 例えば以下の case 1: という書き方をすると typeの値が1のときにRotationメソッドを実行するということになります。
            case 1:
                Rotation();
                // このbreakというのはどこまでがcase 1:の範囲なのかを決めるための宣言です。
                break;
            case 2:
                break;
            case 3:
                break;
            case 4:
                break;
            case 5:
                break;
            case 6:
                break;
            case 7:
                break;
            case 8:
                break;
            case 9:
                break;
            case 10:
                break;
            default:
                break;
        }


    }

    public override void Interact()
    {
        isRotateInvert = !isRotateInvert;
    }

    // メソッド化してみました。処理を一つのまとまりにしてあげることで、直すところがわかりやすくなるのと影響する範囲を切り分けることができます。
    // プログラムはよく「あ、ここ直せばよかったな」とか出てきやすいのでその時に処理をまとめていないと何処を直せばよいのかわかりにくくなりがちです。
    // 私もよくまとめるのを忘れて大変な目になっていることが多々あります・・・。
    void Rotation()
    {
        if (isRotateInvert)
        {
            transform.localEulerAngles += Vector3.up * Time.deltaTime * -rotationSpeed;
        }
        else
        {
            transform.localEulerAngles += Vector3.up * Time.deltaTime * rotationSpeed;
        }
    }
}

大きさの変更

void ScaleChange()
    {
        if (isScaleChanged)
        {
            // 大きさの変更をするにはVector3の値をセットします。
            // 今回は固定で2倍の大きさにしてみました。
            transform.localScale = new Vector3(2, 2, 2);
        }
        else
        {
            transform.localScale = defaultScale;
        }
    }

色の変更

void ColorChange()
    {
        if (isColorChanged)
        {
            // 色を変えるためには、色情報を設定してあげます。ここの色はInspectorから設定した色です。
            material.color = changeColor;
        }
        else
        {
            // あらかじめ設定しておいた色を設定しています。今回はもともとの色情報を取得してセットしています。
            material.color = defaultColor;
        }
    }

表示非表示の切り替え

void ShowHide()
    {
        if (isHide)
        {
            // Rendererを有効、無効化して表示と非表示を切り替えています。
            // SetActive(false) でも消すことはできますが、当たり判定が消えてしまい触ることができなくなるので今回は見た目上だけ消しています。
            meshRenderer.enabled = false;
        }
        else
        {
            meshRenderer.enabled = true;
        }
    }

移動

void Move()
    {
        if (isMove)
        {
            // Vector3.right つまり (1,0,0) をもともとのCubeの位置に足しています。
            transform.position += Vector3.right;
        }
        else
        {
            transform.position = defaultPosition;
        }
    }

5つのプログラムを切り替えできるように

紹介した5つのプログラムを実際に動かして見れるように作成してみました。


using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class Cube : UdonSharpBehaviour
{
    // このように表記するとInspectorに1~10までの数字を選べるスライダーが表示されます。
    [SerializeField]
    [Range(1, 10)]
    int type;

    [SerializeField]
    float rotationSpeed;

    // こちらは色選択用のピッカーがInspectorに表示されます。
    [SerializeField]
    Color changeColor;

    Color defaultColor;
    Material material;
    Vector3 defaultScale;
    Vector3 defaultPosition;
    MeshRenderer meshRenderer;
    bool isRotateInvert;
    bool isScaleChanged;
    bool isColorChanged;
    bool isHide;
    bool isMove;

    void Start()
    {
        // このスクリプトが割り当てられているCubeから、それぞれ要素を取得しています。
        // 毎回GetComponentとすると大変なので、最初に取得して変数に入れておきます。
        material = gameObject.GetComponent<Renderer>().material;
        defaultColor = material.color;
        meshRenderer = gameObject.GetComponent<MeshRenderer>();
        defaultScale = gameObject.transform.localScale;
        defaultPosition = gameObject.transform.position;
    }

    void FixedUpdate()
    {
        // Rotationだけは継続して実行してほしい処理なのでFixedUpdateに入れています。
        if (type == 1)
        {
            Rotation();
        }
    }

    public override void Interact()
    {
        isRotateInvert = !isRotateInvert;
        isScaleChanged = !isScaleChanged;
        isColorChanged = !isColorChanged;
        isHide = !isHide;
        isMove = !isMove;

        // switchは()の中の変数の値を見て、どの処理を行うか選べる処理です。
        switch (type)
        {
            // 例えば以下の case 2: という書き方をすると typeの値が2のときにRotationメソッドを実行するということになります。
            case 2:
                ScaleChange();
                // このbreakというのはどこまでがcase 2:の範囲なのかを決めるための宣言です。
                break;
            case 3:
                ColorChange();
                break;
            case 4:
                ShowHide();
                break;
            case 5:
                Move();
                break;
            // このdefaultというのは上記のcaseいずれでもない場合に実行する処理となります。
            // 1~10まで選択できるようにしていますが、1~5までの処理しか作成していませんので6以降は処理を行いません。
            // よろしければここにcase6以降を追記してオリジナルな処理を作成してみてください。
            default:
                break;
        }
    }

    // メソッド化してみました。処理を一つのまとまりにしてあげることで、直すところがわかりやすくなるのと影響する範囲を切り分けることができます。
    // プログラムはよく「あ、ここ直せばよかったな」とか出てきやすいのでその時に処理をまとめていないと何処を直せばよいのかわかりにくくなりがちです。
    // 私もよくまとめるのを忘れて大変な目になっていることが多々あります・・・。
    void Rotation()
    {
        if (isRotateInvert)
        {
            transform.localEulerAngles += Vector3.up * Time.deltaTime * -rotationSpeed;
        }
        else
        {
            transform.localEulerAngles += Vector3.up * Time.deltaTime * rotationSpeed;
        }
    }

    void ScaleChange()
    {
        if (isScaleChanged)
        {
            // 大きさの変更をするにはVector3の値をセットします。
            // 今回は固定で2倍の大きさにしてみました。
            transform.localScale = new Vector3(2, 2, 2);
        }
        else
        {
            transform.localScale = defaultScale;
        }
    }

    void ColorChange()
    {
        if (isColorChanged)
        {
            // 色を変えるためには、色情報を設定してあげます。ここの色はInspectorから設定した色です。
            material.color = changeColor;
        }
        else
        {
            // あらかじめ設定しておいた色を設定しています。今回はもともとの色情報を取得してセットしています。
            material.color = defaultColor;
        }
    }

    void ShowHide()
    {
        if (isHide)
        {
            // Rendererを有効、無効化して表示と非表示を切り替えています。
            // SetActive(false) でも消すことはできますが、当たり判定が消えてしまい触ることができなくなるので今回は見た目上だけ消しています。
            meshRenderer.enabled = false;
        }
        else
        {
            meshRenderer.enabled = true;
        }
    }

    void Move()
    {
        if (isMove)
        {
            // Vector3.right つまり (1,0,0) をもともとのCubeの位置に足しています。
            transform.position += Vector3.right;
        }
        else
        {
            transform.position = defaultPosition;
        }
    }
}

以上となります。アイデア次第ではほかにも色々できますが、今回は5つご紹介いたしました。お疲れさまでした。

無料アイテムも御座いますので、よろしければプログラミングの参考までによろしくお願いいたします。


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