概要
ディナー
https://twitter.com/hatsuca_vr/status/1069619612612841474
タワーディフェンス
https://twitter.com/hatsuca_vr/status/1069617279535505408
上記の動画で使用した、FireSpawnWelding と私が勝手に呼んでいる手法について解説します。
これを使う事で接触した任意のオブジェクト同士の結合や、動的なターゲット指定を実装する事が出来ます。
(※ある程度VRChatのギミック作成に慣れた人向けの記事となっております。)
ExplosionFireAndDebris
中心となるのは StandardsAssets の PerticleSystems フォルダにある、
ExplosionFireAndDebris(と ParticleSystemMultiplier )というスクリプトです。
まずはこちらのスクリプトの内容を簡単に解説します。
ExplosionFireAndDebris は爆発の際の破片の生成と、それらや周囲に発生する炎を表現するスクリプトです。
コルーチンで実装されており、2フレームに渡って DebrisPrefab の生成と、FirePrefab の生成を行います。
また、コンポーネントとして同フォルダの ParticleSystemMultiplier を使用しており、
これの変数 Multiplier がPrefabの生成数や生成範囲に関わってきます。
DebrisPrefab を生成するコルーチン1フレーム目の処理を DebrisSpawn、
FirePrefab を生成する2フレーム目の処理を FireSpawn と呼ぶことにします。
DebrisSpawn
オブジェクトから半径[3 × Multiplier]内のランダムな地点に DebrisPrefab を[numDebrisPieces × Multiplier]個生成します。
生成する DebrisPrefab はリストからランダムに選ばれます。PrefabのRotationはランダムです。-
FireSpawn
- 1.半径[10 × Multiplier]内の、最大[NumFires]数のコライダにオブジェクトからRayを飛ばして、接触点から0.5浮かした地点に FirePrefab を生成します。角度はIdentityです。 この時生成された FirePrefab はRayが接触したオブジェクトの子になります。
- 2.NumFires の数よりコライダ数が少なかった場合、オブジェクトのY+1の位置から-Y側のランダムな方向にRayを発射、接触点に親無しのFirePrefabを生成します。 この処理一回毎にRayの距離を[Multiplier]だけ伸ばして、 FirePrefab を生成する度に減算される NumFires が無くなるか、10回処理を繰り返したら終了します。
イメージとしては1フレーム目でランダムに破片をばら撒いて、2フレーム目でそれらや周囲の地面に火を点ける感じですね。
FireSpawnWelding
FireSpawnWeldingでは、FirePrefab がRayの接触したオブジェクトの子として生成されるのを利用します。
FirePrefab にHierarchy上のオブジェクトを指定する事で、生成元のオブジェクトと接触オブジェクトとの間を
FirePrefabで繋いでしまおうと言うのがFireSpawnWelding(FireSpawn溶接)の考え方です。
https://drive.google.com/open?id=1L8i_j-rrwUbtwgbgSJnfD8LlpXS3cpYZ
GoogleDriveにPrefabを用意したので、ここからはインポートして実際に構成を見ながらお読みください。
(別途StandardAssetsとVRCSDKのインポートが必要。Unity5.6.3p1で作成。)
このPrefabでは、
BodyとPartsのJunctionコライダが接触する事で、最終的にPartsが FirePrefab を経由してBody側のJunctionの子になります。
1. FirePrefab の生成
Junctionコライダ同士が接触する事でSpawnEventがアクティブとなり ExplosionFireAndDebris が起動します。
ExplosionFireAndDebris はコルーチンのため、SendMessage関数を使ってStartを呼び出します。
FirePrefab が付着する範囲を最小限にするため、[Multiplier × 10] の値がコライダ半径と同じくらいになるように適当に設定します。
Partsに干渉できるように FirePrefab の生成元(Welding)はPartsと兄弟関係にしています。
2.CallとCallback
ExplosionFireAndDebris実行の際、関係ないオブジェクトにも FirePrefab が付着してしまうので、正しいオブジェクトに付着したかどうかを確認するため生成された FirePrefab から親に信号を送り、それが帰ってこなければ削除するようにします。
確認信号にはLegacyのAnimationコンポーネントで使える階層の上方向への相対パスを利用します。
(参考:https://twitter.com/kaisya_no/status/1044894667622342658)
Parts側で生成された FirePrefab はBody側のJunctionの子になっているはずなので、『../CallEvent』と指定する事でBody側のCallEventを起動、同じ方法でParts側のCallbackEventまで信号を返します。
この際、生成された FirePrefab の名前には最後に(Clone)が付く事に注意します。
3.オブジェクトの接続
Callbackが送られてきたら削除用スクリプトである TimedObjectDestructor の削除タイマーをCancelInvoke関数で止め、Parts本体をSetParent関数で FirePrefab の子に設定します。
これで Body - Junction - FirePrefab - Parts という形でBodyとPartsを親子関係で繋ぐことが出来ました。
ディナーではフォークやナイフがBody、フルーツがPartsの役割です。
タワーディフェンスでは応用してタワーの射程内のイーサンに FirePrefab を付着させ、それをターゲットに射撃を行っています。
取り合えずの課題
当然それぞれのローカル上でしか FirePrefab は発生しないので同期取るのがくっそ難しいです。
出来ればMasterとか、一人のプレイヤー上だけで処理したいです。
そういう訳にもいかない場合は…頑張るしかないですね。(白目)
おわりに
扱いの難しさはあれど、これまでのVRChatギミックでは困難だった動的なオブジェクト取得がある程度可能になるので、出来る事の幅が大きく広がる技術だと思います。
この構成を叩き台にして、新たな楽しいワールドが生まれてくれることを願っています。
さぁ、これを読んだあなたも今日からLet's溶接!
PS. uGUIイベント弄る時のストレスが半減するので、ギミック作るなら絶対これ使った方が良いです。
https://twitter.com/naqtn/status/1059162082434662400
VRChat 技術メモ帳
http://vrcworld.wiki.fc2.com/