VRChatはDesktop操作があるため、VR必須だと公言しておかなければDesktop(腕1本)+VR(腕2本)それぞれで動作するワールドを制作する必要があります。
今回はそのことを踏まえ、どのように作ると良いかを思い悩んだ事を書きます。
制作ワールド
【[Unofficial] 765PRO VR Live Theater】
— ひょろも (@hyoromo) 2021年12月11日
公式YouTubeチャンネルにあるミリシタMVを観て楽しむ動画視聴ワールド作りました🥳
操作性周りを頑張ったので「ミリオン知らない」って人も見に行ってフィードバック頂けると嬉しいです#VRChatワールド紹介#VRChat_world紹介 pic.twitter.com/l0yYsPvEwz
Interact/uGUIをどう使い分けるかこだわって作ったワールドで、今回はこのワールドでの話がベースとなります。
実装に対して実際どうなったかはワールドへ一度足を運ばれるのが早いです。だから行って!
開発環境
- Unity2019.4.31f1
- VRCSDK3-WORLD-2021.11.24.16.19_Public
- UdonSharp_v0.20.3
InteractとuGUIの違いについて
VRor Desktop | 種類 | 操作GIF |
---|---|---|
Desktop | Interact | |
VR | Interact | |
Desktop | uGUI | |
VR | uGUI |
それぞれ発火までの手順を挙げてみましょう。
種類 | イベント発火までの操作手順 |
---|---|
Interact | 1. 対象物の近くへ手を近づける 2. トリガーを引くことで発火 |
uGUI | 1. World座標に配置されたCanvasの方を向く 2. プレイヤーがその方向へ手をかざすとRay(レーザー)の先にポインタ表示 3. 発火可能なUI上でトリガーを引くと発火 |
それを踏まえた特徴も挙げます。
種類 | 特徴 |
---|---|
Interact | ・360度どこから近付くことで発火 ・近付くというのがプレイヤーに分かりにくく、隣接すると操作しにくい印象を与える*1 ・距離が離れると操作不能なため、距離に対して工夫は必要なケースが少ない |
uGUI | ・Canvasのある方向から距離に関係なく発火 ・マウスポインタのような操作感覚で狙ったUIのイベントを発火しやすい*2 ・そのまま配置すると遠い距離からも操作可能なため、間にColliderを配置する等の工夫が必要 |
といったものが特徴です。
ここまでDesktopでの話を一切してきませんでした。ではDesktop/VRでの差は何なのか?
種類 | DesktopとVRの差 |
---|---|
Interact | ・Desktopはカメラからrayが飛び、カメラとの距離が近いと触れる |
uGUI | ・Desktop/VRに差は無い*3 |
そう。InteractでのみDesktop/VRで差が生じてしまうのです。
なので普段Desktopで開発してInteractを並べて配置してしまうと・・・いざVR操作する時に触れたい対象に触れられない!なんて事が発生します。
どういったケースでInteractとuGUIをどちらを使うべきか?
ここからは私見です。現時点の私の考えであって未来で変わる可能性がありますし、世間一般的な考えでない事を留意ください。
Interactを使うパターン
Interact最大の良さは "VRらしさ" です。
手を伸ばして、触れて、発火させる。uGUIだとほぼ手を動かずコントローラーの傾きだけで済んで味気なく感じてしまいます。
それとCanvasと違って特定の方向に向けるとRayが飛ぶ訳では無いため、発火対象物が常に固定座標に無い場合はInteractの方が使い勝手が良いです。
例えばPickup可能なObject上にuGUIを配置した場合、手から離した状態がどういう向きになるかも分からないためRayが出続けるような鬱陶しい状況になる可能性があります。
まとめると...
- Interactの方がVRっぽい操作ができる
- 動く物に配置しやすい
それでもInteractを多用してVRらしさを追求したい!
PickupもInteractなのでそうは言ってもInteractを並べて使いたいケースがあります。
そうした時に「[Unofficial] 765PRO VR Live Theater 」ワールドではどう対処したかを書いていきます。
作成ワールドには動画情報を表示するタブレットを配置しています。
タブレットは中央にPickup、上/左/右/左下/右下それぞれにInteractを設定しています。
この場合、中央に近い位置で外のInteractに触れると 中央のPickupに反応して外のInteractを触れません。
その解決策は2つあります。
1つ目はColliderとInteract/Pickupのproximityを小さくする事です。
Colliderを小さくすると単純に手と距離が近付き難くなったり、他Interactと隙間が大きく取りやすくなります。
proximityは手とInteractが反応する距離で、小さくすればするほど近付かないと反応しなくなります。
2つ目はタブレットのPickupに付けたColliderを覆うColliderを配置する事です。
そしてPickupは初期状態ではpickupableをfalseにしてPickup不可状態とし、覆っているColliderに手が入ってきたらpickupableをtrueにしてPickup可能状態にします*4。
[SerializeField] VRC_Pickup _pickup; [SerializeField] Collider _pickupAreaCollider; // Pickup周囲を覆っているCollider void Start() { // 非VRであればエリアは不要 if (!Networking.LocalPlayer.IsUserInVR()) { _pickup.pickupable = true; Destroy(gameObject); } } public void Update() { // 手の座標を取得してエリアCollider内にあるか/ないかでPickup可不可を設定 var trackingRightHandData = Networking.LocalPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.RightHand); var trackingLeftHandData = Networking.LocalPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.LeftHand); if (_pickupAreaCollider.ClosestPoint(trackingRightHandData.position) == trackingRightHandData.position || _pickupAreaCollider.ClosestPoint(trackingLeftHandData.position) == trackingLeftHandData.position) { // Collider範囲内にどちらかの手が存在 if (!_pickup.pickupable) { _pickup.pickupable = true; } } else { if (_pickup.pickupable) { _pickup.pickupable = false; } } }
こうする事でタブレットぎりぎりまで手を近付けないとPickup要求される事はありません。
Interactの場合は試したことありませんが UdonBehaviour#DisableInteractive あたりで制御できそうです。
本当は1つ目だけで解決したいところですが、Collider/proximityが小さすぎると今度は単体でInteractし難くなります。
まとめ
自分の中での整理が一旦出来て満足でした。
他の方の理想的なInteract/uGUI使い分け方法も聞いてみたいのでコメントか、VRChatで直接会った時か、同じテーマで書いて頂けると興味深く読まさせて頂きます。