【UE5】初心者向け オブジェクトを任意の場所まで持ち運ぶ仕組みを作ろう
1.初めに
今回は、ワールド上にあるオブジェクトを持ち運びできる仕組みを作っていきたいと思います。筆者自身が開発を進める中で躓いたポイントや各ノードの役割について筆者なりの解釈を交えながら説明を行っているため少し長い記事となっていますが、最後までご覧いただけるとありがたいです。なお、説明ではUE5のテンプレートの一つであるFirstPersonテンプレートを使っています。
2.実装イメージ
実装イメージは以下の動画の通りです。 動画のようにオブジェクトを運んで足場にする、といった応用も考えられるため、ゲーム制作などにおいて操作の自由度が一気に増します。
3.オブジェクトの作成
まず、持ち運ぶオブジェクトを作成しましょう。コンテンツブラウザで右クリックを押して、
ブループリント → Actor
を選択します。


分かりやすいように名前を「BP_CarryObject」としておきます。

次に、作成した「BP_CarryObject」をダブルクリックで開きます。そして、左側の「コンポーネント」タブの「+追加」から「キューブ」を選択してCubeを追加します。

続いて、先ほど作成したCubeを選択した状態で右側の「詳細」タブから
物理 → Simulate Physics
を見つけ、チェックボックスにチェックを入れます。この時、「詳細」タブの上部にある検索バーから探すと簡単に見つけられます。

また、同じく「詳細」タブの
コリジョン → コリジョンタブ
にある「Object Type」が「PhysicsBody」になっている事を確認します。初期設定では「PhysicsBody」になっているはずですが、もし違っていた場合は「PhysicsBody」に設定して下さい。

最後に、編集画面を閉じてオブジェクトをワールドに配置します。

4.持ち運び機能の作成(ビューポート)
続いて、持ち運ぶ機能を作成します。今回は、FirstPersonテンプレートにある「BP_FirstPersonCharacter」に機能を追加していきます。こちらは
All → コンテンツ → FirstPerson → Blueprints
の中に入っています。

まず、「BP_FirstPersonCharacter」を開いて左側の「ビューポート」タブから「+追加」で「Scene」を追加します。

この場所がオブジェクトを掴む場所になりますので、分かりやすいように名前を「Grab_point」に変更しておきます。そして、「詳細」タブのトランスフォームから「Grab_point」の位置を下の画像のように変更しておきます。

ビューポートで見ると下の画像のようになります。少しプレイヤーから離しているのは、持ち運ぶときにオブジェクトが見えるようにするためです。カメラに近すぎるとオブジェクトがカメラに映らず、運んでいるか確認できないので注意が必要です。

5.持ち運び機能の作成(BP)
続いて、ブループリント(BP)を作成していきます。「ビューポート」タブから「イベントグラフ」タブに切り替えると、すでにいくつかブループリントが書かれていると思いますが、それらには変更を加えず、右に新しく追加していきます。作成するBPの全体図は以下の通りです。

まず、イベントグラフの何もない場所で右クリックを押して「Mouse Events」の「Left Mouse Button」を選択します。検索バーで「Left Mouse」と入力すると出てくるかと思います。

次に、「Left Mouse Button」の「Pressed」からドラッグして「Branch(if)」ノードを配置します。

続いて、「Branch」ノードの「Condition」に繋げる変数を作成します。左側の「マイブループリント」タブにある「変数」の右側の+マークから変数を追加して名前を「bool_carry」、型を「Boolean」にします。この変数は「オブジェクトを持っているかどうか」を保存しておくための物になります。

作成した変数を「Condition」に接続しておきます

5.1 False側の処理
続いて、False側の処理を作っていきます。False側はオブジェクトを持ち上げる機能が入ります。「False」からラインを伸ばして「Line Trace For Objects」ノードを追加します。
このノードは「Start」から「End」に向けて光線を飛ばし、光線に当たったオブジェクトの情報などを返すノードになります。ここに今から付け足していきます。

まず、「Start」からラインを伸ばして「Get World Location(First Person Mesh)」を選択します。

これは、「First Person Mesh」から光線を飛ばす事を意味しています。

次に、「First Person Mesh」ノードからラインを伸ばして「Get Forward Vector」ノードを追加します。このノードは「First Person Mesh」の前方の単位ベクトルを取得するノードです。

続いて、「Get Forward Vector」ノードの「Return Value」からラインを伸ばして「multiply」ノードを追加します。

そして、「multiply」ノードのBの部分(下画像)にカーソルを合わせて右クリックを押して
ピンの変換 → 浮動小数点数(単精度)へ
を選択します。


すると、ピンの色が緑色になって入力できる場所が一つになると思いますので、その入力の場所に「1000」と入力します。
これは、光線の届く距離、つまりオブジェクトの検出距離を示しています。

続いて、「Get World Location」ノードの「Return Value」からラインを伸ばして「add」ノードを選択します。

そして、「multiply」ノードの「Return Value」と「add」ノードの「B」を接続し、「add」ノードの「Return Value」を「Line trace for object」ノードの「End」と接続します。
ここで2つの値を足したものを「Endに繋いでいる理由としては、現在地点(Get World Location)からの距離を出したいからです。もし足し算をせずに「multiply」ノードの「Return Value」と「End」を繋いでしまうと、どの場所から1000cmを測るのかが命令として伝わらず、全て原点方向に向かって光線が向かってしまいます。

次に、「Line Trace For Objects」ノードの「Object Types」からラインを伸ばし、「Make Array」ノードを追加します。

そして、「Make Array」ノードの「WorldStatic」の場所を押すと選択肢が表示されるので、「PhysicsBody」を選択します。
これは、先ほどオブジェクトを作った際に確認していただいた、「Object Type」と連動しており、光線が当たったオブジェクトのObject Typeと一致すれば値を返す仕組みです。

では次に、「Actors to Ignore」からラインを伸ばし、「Make Array」ノードを追加し、「[0]」からラインを伸ばして「self」を追加します。
これは、光線を飛ばすときにプレイヤー自身の当たり判定を無視して飛ばす事を意味しています。

次に、「Line Trace For Objects」ノードの「Draw Debug Type」を「None」から「For Duration」に変更しておきます。これで光線を視認できるようになり、オブジェクトに光線が当たっているか確認することができます。

続いて、「Line Trace For Objects」ノードの「Out Hit」からラインを伸ばして「Break Hit Result」ノードを追加します。
これは、「Out Hit」に含まれる各要素を抽出したものであり、下矢印を押すと全ての要素を確認できます。

次に、「Line trace for object」ノードからラインを伸ばして、「Cast to BP_CarryObject」ノードを追加します。「Cast to BP_CarryObject」ノードの「Object」には「Break Hit Result」ノードの「Hit Actor」を接続しておきます。
この「Cast to 〇〇」は「Object」に繋いだものが〇〇(今回の場合はBP_CarryObject)かどうかを確認して、正しければ上、違っていれば下(Cast Failed)が実行される。今回は光線が当たったオブジェクトが「BP_CarryObject」であれば持ち上げる、というプログラムのため、下のCast Failedは使用しません。

次に、新たに変数を作成します。この変数は当たったオブジェクトの名前を保存するために使います。左側の「マイブループリント」タブから「変数」の右側にある+から変数を追加し、名前を「carry_object_name」、型を「Actor(オブジェクト参照)」にします。

そして、変数「carry_object_name」をドラッグしながら「Cast to BP_CarryObject」に接続し、「As BP Carry Object」と「Carry Object Name」を接続します。

続いて、その先に「Set Simulate Physics」を追加します。赤枠の物であればどれを選択しても大丈夫です。説明では「First Person Mesh」を選択しました。

そして、「Target」に繋がった「First Person Mesh」を削除し、新たに「Cast to BP_CarryObject」の「As BP Carry Object」を接続します。

接続すると自動的に「Target Cube」というノードができると思います。
「Set Simulate Physics」ノードでは、「Simulate Physics」のオンオフができます。今回は、持ち運ぶときに重力などの影響を無視したいので、「Simulate」のチェックは外したままにします。

次に、「Set Collision Enabled」ノードを接続して「Target」に先ほど自動生成された「Target Cube」ノードを接続します。
「Set Collision Enabled」ノードはコリジョン判定を制御するもので、コリジョンをそのままにしているとプレイヤーの動きと干渉してしまったため、「No Collision」にしておくことでプレイヤーの動きに干渉しないようにしています。

続いて、「Attach Component to Component(Grab_point)」ノードを接続します。
似たようなノードに「Attach Actor to Component」ノードがありますが、今回はコンポーネント(Cube)とコンポーネント(grab_point)を接続したいのでAttach Component to Componentを用いています。

作成すると上の画像のようになりますが、今回は親を「Grab_point」にして子を「持ち運びたいオブジェクト」にすることで、「Grab_point」に「持ち運びたいオブジェクト」がくっついて動く形にしたいので、「Grab_point」を「Target」ではなく「Parent」に接続します。そして「Target」には「Target Cube」ノードを接続します。

そして、「Location Rule」と「Rotation Rule」を「Snap to Target」に、「Scale Rule」を「Keep World」に変更します。
「Scale Rule」だけ「Keep World」にしている理由は、もし「Snap to Target」にしていると、持ち運ぶオブジェクトのサイズを拡大(縮小)している場合に、そのサイズの変更がリセットされてしまったからです。「Keep World」にしておけば、オブジェクトの大きさは置かれていた時のサイズを基準にするため、持ち運んでもオブジェクトのサイズが変更されなくなります。

最後に「Attach Component to Component」ノードに変数「bool_carry」をドラッグして接続し、チェックボックスにチェックをつけてFalse側の処理は完成です。

ここまでで、一度動かしてオブジェクトを持ち上げられるか確認しておきましょう。

オブジェクトに向かって左クリックを押して、オブジェクトがプレイヤーに追従するようになれば成功です。
5.2 True側の処理
続いて、True側の処理を実装していきます。「Branch」ノードまで戻って「True」からラインを伸ばし、「Is Valid」ノードを選択します。

「Input Object」には作成した変数「carry_object_name」をドラッグして接続します。
この「Is Valid」ノードは「Input Object」に接続されたものに中身が入っているのか否かを判定し、入っていれば「Is Valid」、入っていなければ「Is not Valid」を実行するノードです。今回はこのノードが無くても動きますが、万が一のエラーを起こさないために入れています。

次に、「Cast to BP_CarryObject」ノードを接続し、「Object」には変数「Carry Object Name」を接続します。

そして、「Cast to BP_CarryObject」ノードに「Detach From Component(Cube)」ノードを接続します。


「Target」に繋がっている「Target[self] Cube」ノードは「Cast to BP_CarryObject」ノードの「As BP Carry Object」と接続します。
このノードは「Attach Component to Component」で親子付けした関係をリセットするためのものであり、もし「Target」が「grab_point」などになっていると、親:grab_point/子:Cubeの親子関係が解消されず、2回目以降の持ち運びが出来なくなってしまうので注意が必要です。

また、「Location Rule」「Rotation Rule」「Scale Rule」は全て「Keep World」に変更しておきます。「Keep World」にする事で、運んだ先にオブジェクトを置くことができます。もし、「Keep Relative」のままになっていると、置いた瞬間にどこかにいってしまいます。

続いて、「Set Simulate Physics」を追加します。先ほどと同じく赤枠の物であればどれを選択しても大丈夫です。説明では「First Person Mesh」を選択しました。

そして、「Target」に接続されたノードを削除し、新たに「Target Cube」ノードを接続します。

オブジェクトを置くときはSimulate Physicsをオンにしたいので、「Simulate」にチェックを入れておきます。

次に、「Set Collision Enabled」ノードを接続し、「Target」に「Target Cube」ノードを接続します。また、オブジェクトのコリジョンを元に戻したいので「New Type」を「Collision Enable(Query and Physics)」に変更しておきます。

最後に変数「bool_carry」と「carry_object_name」を初期化しておきます。

これでオブジェクトを持ち運ぶ機能の作成は完了しました。後は実行して最初の動画のように上手く動くのか確認しましょう。動かし方はオブジェクトに合わせて左クリックを押して持ち上げ、下ろすときも左クリックで下ろせます。
今回はここまでです。少し長い説明になりましたが、最後までご覧いただきありがとうございました。よい開発ライフを!
Discussion