[VRChat]ワールド製作よく使うメモ

# なにこれ
自分がワールド製作でよく使うメモです。
スクリプトの記載などもありますが、基本適当な記載です。
要望があれば追記していきます。
# 非スクリプト系
## 移動速度・ジャンプ力変更
<dl>
<dt>jumpImpulse</dt>
<dd>ジャンプ力</dd>
<dt>warkspeed</dt>
<dd>歩く速度</dd>
<dt>runSpeed</dt>
<dd>走る速度</dd>
<dt>strafeSpeed</dt>
<dd>走る速度</dd>
</dl>

:::note warn
移動速度を上げると酔いやすくなるので注意してください。
:::

※[JP]Tutorial Worldの設定は以下の通り。
　ジャンプ力がデフォルトよりも強く設定されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399875/75e02bbd-b34a-cf90-5fe5-eda7af40f1f0.png)

## 物を複製したい
Ctrl+D

## ピックアップ出来る物を作りたい（非同期・ローカル）
・持ち上げたいオブジェクトに「VRC Pickup」を設定する。（Add Component）
→「Rigidbody」が自動的に追加される。
・コライダーを設定する。
<dl>
<dt>Use Gravity</dt>
<dd>チェックを入れると重力落下します。</dd>
<dt>Is Kinematic</dt>
<dd>物理演算を受け付けなくなります。</dd>
<dd>（離しても飛んでいかなくなる）</dd>
</dl>

:::note warn
「Use Gravity」「Is Kinematic」両方チェック外すと永遠に飛んでいきます。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399875/77eaf4bf-b432-06ef-0a50-c51c8fddfc89.png)

## ピックアップ出来る物を作りたい（同期・グローバル）
基本はローカルと同じ
・「VRC Object Sync」を設定する。（Add Component）
・「Allow Collision...」はチェックを外しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399875/9abde45f-655c-4eb8-f834-c50c7eaa26c9.png)

# スクリプト系
## 表示・非表示のスイッチ（インタラクト）
鏡とかのスイッチ。
よく消し忘れたままアップロードしてしまうので、開始時に強制オフにしてる。
```C#:
    // 対象のオブジェクト
    [SerializeField] private GameObject TargetObj;
    void Start()
    {
        // 開始時、強制オフ
        TargetObj.SetActive(false);
    }

    // 触ったとき（インタラクトした時）
    public override void Interact()
    {
        // 表示非表示を切り替え
        TargetObj.SetActive(!TargetObj.activeSelf);
    }
```
ソースを修正すると、「Udon Behaviour」の中に枠が出てくるのでオブジェクトを設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399875/811664f4-8dae-f221-457e-fd4543585a14.png)

## 表示・非表示のスイッチ（エリア）
特定エリアに入ったら自動でOnになりますよ的なやつ
「自分だった場合」をつけ忘れて暴走したり、出た時にOffにするのを忘れやすいので注意。
```C#:
    // 対象のオブジェクト
    [SerializeField] private GameObject TargetObj;
    void Start()
    {
        // 開始時、強制オフ
        TargetObj.SetActive(false);
    }
    // エリアに入ったとき
    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        // 入ったプレイヤーが自分だった場合
        if (player == Networking.LocalPlayer)
        {
            TargetObj.SetActive(true);
        }
    }
    // エリアから出たとき
    public override void OnPlayerTriggerExit(VRCPlayerApi player)
    {
        // 出たプレイヤーが自分だった場合
        if (player == Networking.LocalPlayer)
        {
            TargetObj.SetActive(false);
        }
    }
```

・**同じ**オブジェクト内にコライダーを設定する。
・設定したコライダーの「Is Trigger」にチェックを入れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399875/0aee80f2-365a-9b0d-687d-e202ae784602.png)

## テレポートさせたい
```C#:
    // テレポート先（オブジェクト）
    [SerializeField] private GameObject teleportPointTo;

    // 触ったとき（インタラクトしたとき）
    public override void Interact()
    {
        // プレイヤーをテレポートさせる
        Networking.LocalPlayer.TeleportTo(teleportPointTo.transform.position, teleportPointTo.transform.rotation);
    }
```
テレポート先に設定したい場所にオブジェクトを配置し、設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399875/5d54d715-f794-449d-b072-c26493d45173.png)

## 音を流す
```C#:
audio.Play();
```
# 改造クライアント対策
あいつら勝手に他人のメソッドを叩いたりします。正直迷惑。
## 勝手に鏡を付けられたりテレポートさせられたりの対策
ワールドのインタラクト出来るもの等に距離制限を設ける。
「指定された距離よりも遠くにいる為、何もしない」を実現する。
```C#:[JP]Tutorial Worldの鏡のスイッチ
    [SerializeField] private GameObject TargetObj;

    public bool IsTinyDistance(Vector3 objPlace)
    {
        // プレイヤーの座標を取得
        var player = Networking.LocalPlayer;
        var playerPosition = player.GetPosition();

        // 各座標の差異を取得
        var differenceX = playerPosition.x - objPlace.x;
        var differenceZ = playerPosition.z - objPlace.z;

        // 指定距離にいる場合、true
        if((distance * -1) < differenceX && differenceX < distance && (distance * -1) < differenceZ && differenceZ < distance)
        {
            return true;
        }
        return false;
    }

    public override void Interact()
    {
        // 距離チェック
        if (IsTinyDistance(this.gameObject.transform.position))
        {
            // 表示非表示を切り替え
            TargetObj.SetActive(!TargetObj.activeSelf);
        }
    }
```

```C#:[JP]Tutorial Worldのはしご
    [SerializeField] private GameObject TargetObj;

    public bool IsTinyDistance(Vector3 objPlace)
    {
        // プレイヤーの座標を取得
        var player = Networking.LocalPlayer;
        var playerPosition = player.GetPosition();

        // 各座標の差異を取得
        var differenceX = playerPosition.x - objPlace.x;
        var differenceZ = playerPosition.z - objPlace.z;

        // 指定距離にいる場合、true
        if((distance * -1) < differenceX && differenceX < distance && (distance * -1) < differenceZ && differenceZ < distance)
        {
            return true;
        }
        return false;
    }

    public override void Interact()
    {
        // 距離チェック
        if (IsTinyDistance(this.gameObject.transform.position))
        {
            // プレイヤーをテレポートさせる
            Networking.LocalPlayer.TeleportTo(teleportPointTo.transform.position, teleportPointTo.transform.rotation);
        }
    }
```

## Publicメソッドを呼ばせない
正確には、「呼ばれても何もしなくする」
バカみたいなやり方ですが、なんと効果があります。
```C#:呼ばれる側
    public void runSeq(int checkNum)
    {
        if (checkNum == 9999)
        {
            /*
                各種処理
            */
            // 改造クライアントは最後に呼ばれた時のパラメータ値を使用している様なので、
            // 正常動作時の最後に正常に動作しない形で一度呼び出す。
            runSeq(0);
        }
    }
```
```C#:呼ぶ側
    public override void Interact()
    {
        // checkNumが9999の時のみ正常に動作する
        hogehoge.runSeq(9999)
    }
```