💃

第22回UE5ぷちコン 技術的な振り返り③ ~輪投げ:投げる処理編~

2024/09/22に公開

この記事について

株式会社ヒストリア様主催の第22回UE5ぷちコンに参加した技術的な振り返りを記録したものです。

今回ははじめてXRミートアップ鹿児島のメンバーと一緒にチームを組んで参加してみました。

提出した作品

https://www.youtube.com/watch?v=L5rYlT0Atkk

ツイートまとめ

https://togetter.com/li/2431939

その他の技術的な振り返り記事

この記事で紹介するもの

ゲーム本編に登場する輪っかを投げる処理を中心に、VRのPawn周りの実装についても、作成手順を記録しておきます。
(こちら↓のツイートの2/2の方に出てくるもの)

https://x.com/xrm_kagoshima/status/1833105284186972588

VRPawn

HMDなしで疑似的にVRのデバッグをできるように

VRアプリ開発をやるうえで最初にやるべき、開発効率の爆上げテクニックです。
HMDを使ってデバッグしていると、HMDの着脱やHMDのスリープ解除に数秒ずつ時間を消費するため、できるだけHMDを使わずに開発できた方が効率が良くなります。

詳しくは下の記事をご覧ください。
(参考になりましたら♡ボタンを押してください!)

https://qiita.com/abricheese/items/9ec6a51433eaee7f1bf9

今回は手の位置を下記のようにして、輪っかをかけやすいように調整しました。

また、今回は手や頭を動かす機能は作らず、後述する輪を出現させて投げる処理に使用するために、グラブボタンをキーボードのAキー(左手グラブボタンの代わり)とSキー(右手グラブボタンの代わり)に割り当てるのみにしました。

下記のように、VRテンプレートに最初から入っているContent>VRTemplate>Input>IMC_HandsにAキーとSキーを追加しました。

輪っかをスポーンする

下記のように輪っかのActorをスポーンする処理を作りました。
(輪っかのActorについては後述します。)
このやり方だとハード参照が付きますが、大したプロジェクト規模じゃないのと、できるだけ低コストに実装して開発期間確保したいので、マシンスペックで殴る方針で…

上記の輪っかをスポーンする処理をグラブボタン(VRの中指あたりで押すボタン、物を掴むときに使われる)で呼ばれる処理に追加しました。

ここの処理をグラブボタンに割り当てた意図としては、物を掴むときに使うボタンを押したタイミングで輪っかをスポーンさせることで、そのまま輪っかを手で掴めるようにしています。
そのため、ボタンを押した処理の一番最初にスポーン処理を追加して、その後の既存の掴む処理に続くようにしています。

さらに、ここの処理の後ろの方に放したときの処理を追加しています。
こちらは後述する放したときに輪っかに加速度を加える処理です。
(関数名が適当なのは許して)

手に持っている物体(Held Component Right/Leftの親=Get Ownerで取得されるActor)に対して処理を呼び出し、インターフェイスを持つものだけに実行したかったので、ここではインターフェイスの関数を使いました。

輪っかのActor

コンポーネント階層

詳しくは後述・別記事にて解説しますが、輪っかのActorは下記のようなコンポーネント階層にしました。

  • Circle
    輪っかのメッシュです。
    モデリング担当メンバーにフラダンスのレイをイメージして作ってもらいました。
    紐っぽく曲がるようにしたかったけど、時間とUEの技術が足りなくてできませんでした。
    あふれ出る鋭利感
  • GrabComponent
    VRテンプレートに付属している、掴めるようにする機能です。
    Grab TypeをSnapにして、掴みたい位置に配置しました。
    こちらの機能についてはUE5VRハンズオン本の中でもう少し詳しく解説していますのでご覧ください。
  • TeleportTraceNiagaraSystem
    VRPawnについているテレポート用のNiagaraをコピペして持ってきました。
    名前の変え忘れ 何を基に改造したかわかりやすい親切な設計)
    こちらは後述する輪っかを投げる予想線のためのものです。
  • Collision
    輪っかがターゲットにかかったか判定するためのコリジョンです。
    こちらは別の記事にて解説する予定です。

提出動画内では全然見せられなかったけど、ちゃんと花っぽく作られています。
(もう少し花の密度減らしても良かったかも)

輪っかを飛ばす

当初の計画では、輪っかを手で投げて物理挙動で的を狙う予定でした。
ところが、実際に作って試してみたところ、全然狙った場所に投げることができませんでした。

https://x.com/abricheese/status/1819749064793346387

このままでは苦行ゲームになってしまうので、輪っかに初速を与えて射出する方式に変更することにしました。
仕様としては、グラブボタンを長押しするほど遠くに飛ばせるようにしています。

初速のチャージ開始

実装としては下図のようにしました。
グラブボタンが押されたとき(=輪っかがスポーンしたとき=BeginPlayが呼ばれたとき)に時刻を変数に記録しておき、Tickをオンにして初速のチャージ開始。
(初めからTickオンにしておいても良かったのかも)

Tickで呼ばれる処理では、時刻からチャージ具合を算出し、最大値以下になるようにして変数に入れています。
(この辺の実装方法も他にいろいろありそう)

チャージは1秒くらいで終わるように、最大値と増加量を調整しました。

射出

前述のグラブボタンを放したときに呼ばれるインターフェイス関数の中で射出処理を呼び、その後一定時間後に輪っかを消滅させるようにしています。

射出処理の中では、Add Impulse関数で力積を与え、不要になった射出予想線(後述)の破棄とTickの停止、効果音再生を行なっています。

Add Impulseの部分に関して、初めはAdd Forceで力を加えて初速を生んでいました。
ところが、同じ値の力を与えているにもかかわらず、投げるたびに飛距離が異なるという問題が発生しました。

調べてみたところ、下記の情報が見つかりました。

一見同じように見えますが、AddForce が「力」を加えるのに対して、AddImpluse は「力積」を与えるという点で大きく異なります。

AddImpluse は、最終的に物体に設定したい速度が決まっている場合で、一瞬でその速度までもっていきたい場合に向いています。例えば、バットでボールを撃つとか、弾丸を発射するといった感じです。名前の通り、一瞬だけインパクトがかかるようなシチュエーションです。

一方の AddForce は、加わる力はわかっているけど、最終的に到達する物体の速度はわからないという場合に、継続的に物体に力を与えるような用途に向いています。例えば、重い金属の球をゆっくり押してだんだん加速させるとか、噴射しているロケットエンジンで飛翔体を加速させる、といった感じです。

https://qiita.com/mml/items/e614b441438ac9788d81#addforce-と-addimpulse-は何が違うのか

今回は一瞬で指定した速度に加速させたかったため、Add Impulseを使うことにしました。
(力積というワードを高校以来久しぶりに聞いた気がする)

ついでに、今後輪っかのモデルを変更して質量が変わった際にも同じ速度で射出されるように、Add Impulseの引数のVel ChangeフラグをTrueにしておきました。

射出の予想線

さて、これで輪っかを投げられるようになりましたが、さらなる問題が発生しました。

どのくらいチャージされていてどこに飛んでいくのかわからない…

https://x.com/abricheese/status/1820099491879616945

ジェットコースター感を出すために上下左右にコースターを動かしているだけでもだいぶ難しいうえに、どこに飛んでいくのかも分からない鬼畜ゲームが誕生しました…😇
(なお、このとき難しかったのは前述のAdd Forceを使っていたことも影響していた模様)

これを解消するため、VRテンプレートでワープ移動するときに使われているレーザーっぽいNiagaraを流用することにしました。
(余談ですが、下記映像はHMDを使わない方法でデバッグしているときの様子です)

https://x.com/abricheese/status/1828455345775411611

VRPawnを参考に下記処理を実装し、Tickで呼び出しました。
やっていることとしては、Predict Projectile Path~で、指定した初速で物体を射出したときの軌道の座標をベクトルの配列で作成し、Niagaraに渡してあげています。

おわりに

以上の作業により、輪っかを取り出して投げられるようになりました。
(こちら↓のツイートの2/2の方に出てくるもの)

https://x.com/xrm_kagoshima/status/1833105284186972588

VRアプリ開発ではVRPawnの改造は恒例行事になっていて、最近はちゃんと解説記事を書けてなかったため、久しぶりちゃんと書くようにしてみました。
分かりづらいところなどあれば教えてください。


皆様の応援が投稿のモチベーションになります。

記事が参考になりましたら、ぜひ♡ボタンを押したり、記事の拡散、X(Twitter)のフォローなどしていただけますと嬉しいです。

GitHubで編集を提案

Discussion