VRChatでデスクトップでも遊べるボードゲームを考える(スナップ)
せっかくブログを作ってのでたまには更新していきたい。というわけで最初は自分が作ったボードゲームワールドでデスクトップ勢(というか自分)が円滑にプレイできるようにするために考えたことについて。
何故デスクトップだとボードゲームのプレイが難しいか
これは自分でいろいろとゲームワールドを巡った際に感じたことだけど
・Pickupオブジェクトの操作に対する自由度が低すぎる
これに集約されると思う。
デスクトップだと任意のものを任意の場所に置く際に調整ができない。オブジェクトを持つと常に手は伸びきった状態で視点とオブジェクトの距離を変えることが出来ないし、オブジェクトを自由に回転させることもできない。なのでマス目があるタイプのゲームの場合マス目の位置にコマを動かすことが難しい上にそのマス目にコマが立つように置くのはさらに難しい。特にオブジェクトのXZ軸移動は自分が動くことによって調整できるけど、手が常に伸びきったままでしか動かせないのでY軸方向への移動はできないのが辛い。
もちろんこれはある程度コンポーネント全体を大きくすれば解決する問題ではあるんだけど、そうするとプレイ中にプレイヤーが動き回ることになり、不便さにつながるので避けたかった。
どう解決するか
とりあえず私のワールドでは
・コマの座標スナップ(コマを離散的な位置にしか置けないようにする)
・コマの回転無効
・gravity有効
を行っている。これでボード上の任意の場所に置くのがある程度楽になる。座標スナップはJasonさんのツイートから作った。天才かよ。すごい。
スナップはね、浮動小数点では大きい数字で精度が低いことで作りあげました。例えば10000000.4という値は浮動小数点で10000000になります。
— Jason Lim (@JasonL663) May 29, 2018
親→子
という関係で、親オブジェクトのXYZ位置を10000000にして、そして子オブジェクトを-10000000にすることで、この振る舞いが原点の辺に使う事が出来ます
本当は角度のスナップもできればよかったんだけど綺麗に出来る方法が見つからなかった。コライダの向きもきれいにスナップできる方法があったら教えてください。
実装
空のGameObjectのtransformを(x,y,z)=(10000000,10000000,10000000)にして、その子に入れた空のGameObjectのtransformを(x,y,z)=(-10000000,-10000000,-10000000)にすると孫に入れたGameObjectは表示上xyz軸方向に1m間隔に座標スナップされる。これからPositionの値を変えたりScaleの値を変えたりすることで各軸ごとに任意のスナップ間隔に調整できる。
上の画像ではY軸もスナップさせているけど、ボードゲームを作るうえでコマを二次元的に操作したいだけならY軸のスナップを入れる必要はない。好きにしたらいいと思う。
これでスナップ自体はうまくいくんだけど、それだけだとpickupした際にオブジェクトがぶれまくって操作できない。iskinematicをonにすればぶれなくなるけど重力が働かなくなるのでY軸調整ができないデスクトップではコマをボードに置けない。
これを解決する第一案として、実際に持つコマと表示するコマを分けたうえでJointで接続して、表示するコマの方だけスナップを適用した。これでぶれずに操作できるようになったが実際に持つオブジェクトの位置と表示位置がずれてしまうので操作するときに違和感を感じるようになった。drop時に位置を同期させることもできたけどやっぱり不自然なのでボツ。
第二案ではpickupした際にiskinematicをonにしてdropした際にiskinematicをoffにした。これでうまくいったのでうちのワールドはこれを採用していたんだけど、いつの間にかmasterとそれ以外でiskinematicの状態の同期ずれが発生するようになった。おそらく2017になった際にpickupオブジェクトかObjectsyncの仕様が変わったんだと思う。困る。
第三案はない。困った。これから考える。VRC運営はクソ。
※追記
pickup時にコライダーを消したらぶれなくなった?VRCのアップデートによるものなのかは分からないけど現状はこれで安定してそう
コマの回転無効は最初RigidbodyのFreeze Rotationにチェックを付けてみたけど普通に回転した。pickupオブジェクトには意味がないらしい。なのでAnimationでRotationの値を固定した。
コマのタイプによってはいろいろな向きで置きたい場合がある。その場合は必要となる回転の向きごとにanimationを用意して、それをPickupUseからAnimatorで切り替える様にした。切り替える状態が多すぎると不便さを感じるけど2~4程度ならあまり問題にならないみたい。
rotationの値を固定する方法として今の私にはAnimationの常時再生による固定、Animatorの支配下に置くことによる固定、Jointによる固定が考えられるけども対象が大量に存在する場合の負荷はどれが一番低いんだろう? VRChatでのAnimationなどの負荷を調べる方法が知りたい。CPU負荷を見ればいいのかな?
その他
デスクトップだと持っているオブジェクトが視点の向きによって動く。俯瞰図を見ながらコマの置く場所を決めるタイプの設計だと、置く場所と上空カメラのモニタを同時に見るのが難しいので視点とおなじ高さにモニタを表示する様にしてみた。今後これを使ってみて有効だと感じたら更なる改良を重ねていきたい。
他にもデスクトップ操作のために改良できるポイントはいくつもあると思うが、いかんせん私自身が操作に慣れてしまったので問題点を見つけ出すことが難しくなってきた。今後他のボードゲームワールドなどを参考にしながらこの記事を更新していくつもり。