UdonSharp日記～道の動的生成～

#やったこと
前回プレイヤーの座標を取得しました。
[UdonSharp日記～ローカルプレイヤーの座標の取得～](https://qiita.com/sadimensions/items/6789f6e0d0c8d2836f5f)
今回はPlaneにオリジナルの当たり判定を作成し、
VRCInstantiateを使用して、道の動的生成を行います。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">んでもってそれの発展形でPlaneの動的生成を実験。<br>UdonSharpをアタッチしたGameObjectをVRCInstantiateで生成した場合、再帰的にUdonSharpが機能するか不安でしたが、機能しました。<br>ただしこの方法は非同期なのが問題。 <a href="https://t.co/7DqeYgJlBU">pic.twitter.com/7DqeYgJlBU</a></p>&mdash; はんちょ (@sadimensions) <a href="https://twitter.com/sadimensions/status/1254705147164323840?ref_src=twsrc%5Etfw">April 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#参考文献
[やぎりさんのUdonSharpコード走り書きメモ](https://yagiri000.hatenablog.com/entry/2020/04/04/162312)・・・VRCInstantiate

#やり方
最初にスポーンするPlaneの横に、これからどんどんコピーしていく予定のPlaneを置きます。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627563/c8526704-d19c-86f1-a6bb-40293e1cf1a4.png)
ここにUdonBehaviourをつけて、UdonSharpを適用します。
そして次のコードを作成します。

```C#:Floor.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using UnityEngine.UI;

public class Floor : UdonSharpBehaviour
{
    public GameObject prefab;
    public Text debugText;
    bool is_stillGiveBirth = false;
    void Update()
    {
        var player = Networking.LocalPlayer;
        if (player != null)//Unityの再生ボタンで実行すると変数がnullになるらしいよ
        {
            //playerの位置を取得（位置は頭の位置を使用）
            var headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

            debugText.text = string.Format("Head-Pos: {0}\r\n", headData.position.ToString());
            if (is_In(headData.position) && is_stillGiveBirth == false)
            {
                //当たり判定があり、まだPlaneを生成していない場合、Planeを生成する。
                var go = VRCInstantiate(prefab);
                go.GetComponent<Transform>().position = new Vector3(0.0f, 0.0f, prefab.transform.position.z + 2.0f);
                is_stillGiveBirth = true;
            }
        }
    } 
    //入力されたVector3(座標)が自身の中にあるかどうかを判定する
    //使用するのはx,zの2次元座標のみ
    private bool is_In(Vector3 pos)
    {
        float myX = this.transform.position.x;
        float myZ = this.transform.position.z;
        float scaleX = 5.0f*this.transform.localScale.x;
        float scaleZ = 5.0f*this.transform.localScale.z;
        //x chexk
        if(myX - scaleX < pos.x && pos.x < myX + scaleX)
        {
            //z check
            if (myZ - scaleZ < pos.z && pos.z < myZ + scaleZ)
            {
                debugText.text = string.Format("ON: x{0}, z{1}, sx{2}, sz{3}\r\n", myX, myZ, scaleX, scaleZ);
                return true;
            }
        }
        return false;
    }
}
```

設計方針としては以下の通り。
1.プレイヤーの座標を得る
2.自身(Plane)の座標と幅・高さを考慮したものと比較して当たり判定をとる
3.当たる場合、自身をクローンして先の座標に生成する。
4.何度も生成しないようにフラグを立てる

難しくないのだけど、当たり判定を使わずにコライダーを使ったらどうか？とか
クローンに使用する関数は何を使うべきか？とか
幅と高さはscaleを使ってるけど、絶対座標系との対応が取れなくてどうしようとか
（今回は実験なのでマジックナンバーとしました）
そんなこんな考えていたら、5時間くらいかかっています。

知識がないところからスタートすると時間かかりますね。

#課題
今回使用したVRCInstantiateは動機が取れないとのこと
（本当に非同期化は調べていない）
解決策を考えなくては・・・
一つ気になることといえば
[黒鳥さんのUDONメモ](https://kurotori4423.github.io/KurotoriMkDoc/VRChat/UDON%20%E3%81%A7%E3%82%AE%E3%83%9F%E3%83%83%E3%82%AF/)によると・・・
>VRCInstantiateのあれこれ（2020/04/11現在）
>現在同期的にインスタンス化を行う方法がない?
>インスタンス化したオブジェクトではUdonBehaviourが死ぬ。
>SendCustomNetworkEventで同期的にインスタンス化出来ているようにみえるが、PickupとUdonBehaviourが死ぬ。
>プレハブの座標とは違う場所からインスタンス化される。

とあり、インスタンス化したPlaneでUdonBehaviourが動かないことが報告されており、
今回の実験とは結果が違うので、慎重に調査をしないといけません。
今回の実験はローカル上でのテストなのでVRChatにアップすると挙動が違うかもしれない。

###後日談
Udonが抱えているバグとして、インスタンス化したオブジェクトでは”時々”UdonBehaviorを失ったり、トリガーが機能しなくなるとのこと。
今回の記事で作成したものは、インスタンスがどんどん次のインスタンスを作成していくコードとなっていたので現時点（2020/4/27）では良くない設計例ですね。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ローカルではなくVRChat上へアップロードしてテストしたら挙動が違いました。<br>難しいね <a href="https://t.co/FGx92jFotl">pic.twitter.com/FGx92jFotl</a></p>&mdash; はんちょ (@sadimensions) <a href="https://twitter.com/sadimensions/status/1254762525905702912?ref_src=twsrc%5Etfw">April 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>