🛏️

UdonSharpメモ ~コードの付箋~

2021/08/17に公開

記事の内容

結論に至るまで長時間を要したコードとかを載せておくところ。

プレイヤーの移動入力をアバターの移動と言うことがありますがお気になさらず...

ScrollできるUI

標準のScrollViewを使えばすご~~~くお手軽だが、レティクルやレイキャストがあたった状態でアバターを移動するとスクロールまで移動しやがるので微妙に良くない。
同じような動作をするスクリプトを書いてみた

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

public class ScrollView : UdonSharpBehaviour
{

    public RectTransform viewport,content;
    public Scrollbar scrollbar;

    void LateUpdate(){
        // content: 中身
        // viewport: 表示領域
        Vector2 viewport_vec2 = viewport.rect.size, content_vec2 = content.rect.size;
        scrollbar.size = Mathf.Min(viewport_vec2.y / content_vec2.y, 1);
        scrollbar.gameObject.SetActive(scrollbar.size < 1);
        if(content_vec2.y >= viewport_vec2.y){
            Vector2 pos = content.anchoredPosition;
            pos.y = (content_vec2.y - viewport_vec2.y)*scrollbar.value;
            content.anchoredPosition = pos;
        }
    }
}

<RectTransform>.rect.sizeでUIの大きさを取得できる。
スクロールバーの大きさを高さ同士で割って求める。
1を超えないようにMathf.Minで抑制してる。

位置の計算は、表示領域の超過分をどれだけy軸に加算するかをスクロールバーのvalueで求める。valueは0~1で取得できるので都合が良い。

...とか思ってたけどScroll ViewのMovement TypeClampedにして、
Scroll Sensitivityを0にすればいいっぽい。どこに書いてあるんだそんなの

トラッキングをトラッキング(?)

HMDやコントローラの位置を取得できる。

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

public class TrackingTrace : UdonSharpBehaviour
{
    private VRCPlayerApi targetPlayer;
    public GameObject playModeObject;

    public VRCPlayerApi.TrackingDataType type;
    void Start()
    {
#if !UNITY_EDITOR
        targetPlayer = Networking.LocalPlayer;
#endif
    }

    void Update(){
        Vector3 pos = targetPlayer != null ? targetPlayer.GetTrackingData(type).position : playModeObject.transform.position;
        Quaternion rotate = targetPlayer != null ? targetPlayer.GetTrackingData(type).rotation : playModeObject.transform.rotation;
        transform.position = pos;
        transform.rotation = rotate;
    }
}

playModeObjectはプレイヤーが存在しないUnityEditor上でのPlayMode時に代わりに追従するオブジェクト。
#if系は、エディタ上で動かした時にエラーが出ないようにするプリプロセッサ ディレクティブって言われてるやつ。
プレイヤーのトラッキングデータは<VRCPlayerApi>.GetTrackingData(<TrackingDataType>)で取得できる。
こいつはpositionとrotationの両方を持ってるので、必要に応じて取り出す必要がある。

VRChat上でのキーボード入力

通常のUnityと同様にInput.GetKey(<KeyCode>)から取得できる。
正直にUpdate系に書くとボタンを押している間毎フレーム処理される。
そのため、次離すまで処理させないようにする(OneShotにする)には、
自前でboolで既に押されているかを保持しておく必要がある。

void LateUpdate()
{
    if (Input.GetKey(KeyCode.I))
    {
        if (!isPushed)
        {
            isPushed = true;
            // 処理...
        }
    } else {
        isPushed = false;
    }
}

Discussion