UdonSharp日記~道の動的生成~


やったこと

前回プレイヤーの座標を取得しました。
UdonSharp日記~ローカルプレイヤーの座標の取得~
今回はPlaneにオリジナルの当たり判定を作成し、
VRCInstantiateを使用して、道の動的生成を行います。

参考文献

やぎりさんのUdonSharpコード走り書きメモ・・・VRCInstantiate

やり方

最初にスポーンするPlaneの横に、これからどんどんコピーしていく予定のPlaneを置きます。

ここにUdonBehaviourをつけて、UdonSharpを適用します。
そして次のコードを作成します。

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メモによると・・・

VRCInstantiateのあれこれ(2020/04/11現在)
現在同期的にインスタンス化を行う方法がない?
インスタンス化したオブジェクトではUdonBehaviourが死ぬ。
SendCustomNetworkEventで同期的にインスタンス化出来ているようにみえるが、PickupとUdonBehaviourが死ぬ。
プレハブの座標とは違う場所からインスタンス化される。

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

後日談

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