U#でオブジェクトの表示/非表示

目次
１．準備
２．スイッチの処理を書く
３．動作確認する
４．解説
？．おまけ（Nullチェック）

VCCバージョン2.1.3、Unityバージョン2019.4時の状況で解説してますが、VCCの大規模アプデが来ない限り2022になっても大して変わらないと思います。

プロジェクトの準備やU#の準備がそもそも分からないという方は、以下の記事を参考にしてみてください。

https://qiita.com/sabamame_vrc/items/4e263d532162e4f915c0

https://qiita.com/sabamame_vrc/items/0252df9ca228743693c6

# １．準備
### スイッチ用のキューブを設置

まず前回の記事同様に、`Cube`をワールドに置きます。
このCubeはスイッチとして扱うので、大きさはXYZ共に0.2くらいにしましょう。

### ミラーの設置
Projectフォルダで`mirror`と検索すると「VRCMirror」というプレハブが見つかるのでこれをシーンに置きましょう。
![MirrorAsset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/ba5812a6-a972-b768-25d7-1de9c097d38f.png)

:::note warn
検索しても見つからない時はVRCWorldプレハブの時同様、`Search：`の右が`All`になっていることを確認しましょう。
:::

![スクリーンショット 2023-10-02 231407.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/5c7d00fc-327e-b729-8bec-8ab6687ad791.png)

### スクリプトの作成
今回はオブジェクトの切り替え役を作るので、ファイル名は`ObjectSwitch`などにしましょう。

# ２．スクリプトを書く
ObjectSwitch.cs の中身を書いていきます。
後から解説するので、一旦コピペで良いです。
```C#:ObjectSwitch.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class ObjectSwitch : UdonSharpBehaviour
{
    // 対象オブジェクト
    [SerializeField] private GameObject _targetObject = null;


    // スイッチが押されたら動作する
    public override void Interact() 
    {
        // 表示/非表示を切り替える
        _targetObject.SetActive(!_targetObject.activeSelf);
    }
}
```
書き終わったら、`Ctrl + S`で保存です。毎回言います。

# ３．動作確認する
### 処理をスイッチにアタッチする

前回の記事でやったように`Cube`に`Udon Behaviour`というコンポーネントを追加し、`Program Source`にObjectSwitchをアタッチします。

ここまでは前回と同じです。

`ObjectSwitch (U# Script)`の下側にある`TargetObject`に、`VRCMirror`プレハブをアタッチします。
![VRCMirrorAttach.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/02ce3c7a-e45a-a748-014c-43d8f0244bb4.png)
これで準備完了です。再生ボタンを押して動作確認してみましょう。
スイッチをクリックするとミラーの表示を切り替えれるはずです。
![スクリーンショット 2023-10-02 233512.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/54eee94b-67f6-c978-7e47-c8cbdd43232d.png)
![スクリーンショット 2023-10-02 233519.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/db29ddae-e65a-4131-0b69-5942d35c679c.png)

# ４．解説
### 変数

ではまず上から...
```C#
    // 対象オブジェクト
    [SerializeField] private GameObject _targetObject = null;
```
長ったらしく書いてますが、ここはGameObjectを入れる箱を用意しています。
GameObjectを入れる為の箱を用意するよ。箱の名前は_targetObjectね。
ってかんじです。

:::note
このような箱のことを、変数といいます。
整数ならint、少数ならfloat、文字列ならstring、オブジェクトならGameObject型といった、型が必ず必要です。
:::

その先頭に [SerializeField] を付けると、インスペクターにこの箱が空の状態で現れます。
試しに [SerializeField] を消してUnityEditorに戻ると、TargetObjectの欄は消えてると思います。

:::note warn
↑を試した人は、忘れずに削除した文字を書き直し、UnityEditorに戻って、`VRCMirror`をアタッチする作業をしなおしてください。
:::

ちなみに以下の書き方でも同じことができますが、個人的には [SerializeField] private ... の方が好きです。
（ゲーム開発者の人はそうですよね？？）
```C#
    // 対象オブジェクト
    public GameObject _targetObject = null;
```

### Interact
続いて実際のスイッチの処理です。
```C#
    // スイッチが押されたら動作する
    public override void Interact() 
    {
        ...
    }
```
Interact() の中は、このオブジェクトがUseされた時に処理されます。
この中にオブジェクトの表示/非表示の処理を書けば、スイッチとして動作させることが可能です。

```C#
    // 表示/非表示を切り替える
    _targetObject.SetActive(!_targetObject.activeSelf);
```

### SetActive
gameObject.SetActive()には、trueかfalseを入れることでそのオブジェクトのアクティブ状態を変えることができます。

:::note
trueかfalseかが入る変数の型を「bool型」と言います。
ON/OFFの切り替えでよく使われます。
:::

アクティブにする場合
```C#
gameObject.SetActive(true);
```
非アクティブにする場合
```C#
gameObject.SetActive(false);
```

 __アクティブ状態って何？__ というと、みなさんがUnityでよく見るこのチェックマークです。
![MirrorActive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/ec7be4e0-295b-6724-92ee-c6a14af438a2.png)
チェックが付いてると表示。何もなかったら非表示になるアレです。
動作確認をしながら`VRCMirror`のインスペクターを見てると、ここのチェックが切り替わっているのが分かると思います。

gameObject.activeSelf は、そのオブジェクトのアクティブ状態をbool型で教えてくれます。
それの先頭に` ! `をつけると、bool型を反転してくれます。

これで表示/非表示を切り替える仕組みになっています。


# ？．おまけ
### Nullチェック

今回は初心者がよくしがちな、あるあるなエラーとその対処について書きます。

アタッチし忘れ。です。

まず、スイッチ役のCubeのTargetObjectにアタッチされているミラーを外しましょう。
![MirrorNone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/0d7bed4f-7045-27b6-bb80-262b35c64f4c.png)

そして実行してスイッチを押してみると、ミラーのアクティブが切り替わりません。
Consoleウィンドウにはエラーが出ています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/403ff7c7-6bfc-3380-3c78-2c50c1a5b4c8.png)
Udonがこのようにエラーを吐くと、そのギミックは二度と動きません。
試しにスイッチをもう一回押しても、エラーはこれ以上増えません。

今回のような簡単な処理ではあまり気になりませんが、今後大きいギミックを作る際には、途中でエラーを吐いても動作はし続けるようにする必要があります。

今回のエラーの内容は、「SetActiveしようとしたけど、その対象のオブジェクトがNullだよ（無いよ。）」です。

じゃあ、オブジェクトが無くても処理が動くようにしましょう。

### Nullでも動くように、コードを修正
```C#
    // スイッチが押されたら動作する
    public override void Interact() 
    {
        // _targetObjectの中身がnullじゃない時に処理する
        if (_targetObject != null)
        {
            // 表示/非表示を切り替える
            _targetObject.SetActive(!_targetObject.activeSelf);
        }
        else
        {
            // ログを出力する
            Debug.Log("TargetObjectがアタッチされていません。");
        }
    }
```
以下の書き方でも同じ動作になります。
```C#
    // スイッチが押されたら動作する
    public override void Interact() 
    {
        // _targetObjectの中身がnullだったら、ここで処理を終える。
        if (_targetObject == null)
        {
            // ログを出力する
            Debug.Log("TargetObjectがアタッチされていません。");
            return;
        }
        
        // 表示/非表示を切り替える
        _targetObject.SetActive(!_targetObject.activeSelf);
        
    }
```

コピペしたら`Ctrl + S`。絶対。

これで実行すると、エラーの代わりに自分で書いたログが出力されます。
エラーで止まることも無いので、何回押してもログが出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884829/00b3ce9b-3742-f932-2aa4-6ac208ab3ebe.png)

:::note
Debug.Log()はEditorでしか確認できませんが、処理がどこまで走っているかを確認したり、変数の動きを確認したりできます。
便利なので最初のうちはガンガン使いましょう。
慣れてきたと思ったら、偶に使うくらいが良いかも。
:::