UE4でレーザービームを実装する
アイアンマンとか見ててレーザーを打ちたくなったので。障害物による中断と打ち終わった後に急に消えないようにする対応で少し複雑になってしまった。ブログは後でパーティクル作成と発射処理を分けて書くつもり。 #UE4Study pic.twitter.com/C3l6jCKjg5
— ほげたつ (@HogeTatu) 2015, 7月 27
これの実装手順です。
パーティクル作成と発射処理を分けて書こうと思っていた時期もありましたが、パーティクル編がほぼチュートリアルと同じなので割愛することにしました。
パーティクル作成まで
パーティクル用のマテリアルをBeamMaterial、パーティクルをBeamParticleという名前で作成します。
この辺りは上記チュートリアル動画の6:14くらいまでとほぼ同様なので、そちらを見ながら作成して下さい。
チュートリアル動画から、ParticleEmitterに以下の変更を加えています。
- Lifetimeを0.1に変更
- InitialColorを(20, 5, 0)に変更
- SourceのSourceMethodをUserSetに変更
- TargetのTargetMethodをUserSetに変更
LifetimeやSourceMethod、TargetMethodはBP側からパーティクルの位置や消失を制御するための変更です。
銃のモデルをShooterGameデモから持ってくる
[UE4] 他プロジェクトからアセットを移動させる方法 | historia Inc - 株式会社ヒストリア
この辺りを参考にWeapons/Rifleをコピーしてきます。
ライフルでビーム?とか細かいことは無しで…
腕のメッシュに銃アタッチ用のソケットを追加
hand_rにRightHandという名前でソケットを追加します。
プレビューで見ながら、LocationとRotationをいい感じにします。
銃のBPを作成する
FirstPersonGunという名前でBPを作成し、
- DefaultSceneRoot
- SkeletalMesh(SkeletalMesh)
- BeamParticle(ParticleSystem)
- BeamHitParticle(ParticleSystem)
- BeamParticle(ParticleSystem)
- SkeletalMesh(SkeletalMesh)
という階層でコンポーネントを追加します。
SkeletalMesh
- スケルタルメッシュにRifleを設定
BeamParticle
レーザービーム本体のパーティクルです。
- ParticlesのTemplateにBeamParticleを設定
- AutoActivateのチェックを外す
BeamHitParticle
レーザービームが障害物に当たった時の火花パーティクルです。
- ParticlesのTemplateにP_Sparksを設定
- AutoActivateのチェックを外す
※P_Sparksは元が青っぽいパーティクルだったので、色をオレンジっぽく変えてあります。
実行時にプレイヤーが銃を持つように設定する
FirstPersonCharacterのBPを開き、イベントグラフに以下の処理を追加します。
BeginPlay時に、FirstPersonGunをスポーンし、後から使うためにGunという変数にリファレンスを保持しています。
その後、AttachToを使ってRightHandのソケットに対してアタッチしています。
ここで試しに実行してみて、正常に銃がアタッチされていることを確認します。
レーザービーム発射処理の流れ
- ビームは照射直後、時間経過により長さが伸びていく
- ビームの長さには制限がある
- ビーム停止後はビーム開始点から時間経過により長さが短くなっていく
- ビームの長さがほぼ0になったら非アクティブ化する
必要な変数宣言
FirstPersonGunに必要な変数を宣言します。
- EmitTimer(float)
ビーム照射時間
- EmitStopTime(float)
ビーム照射停止時間
- BeamLenMax(float)
ビームの長さの最大値
動画では5000
- BeamSpeed(float)
ビームの速さ
動画では10000
- EmitStartDistance(float)
発射口からのビームパーティクル開始位置
- EmitEndDistance(float)
発射口からのビームパーティクル終了位置
- EmitStop(bool)
ビーム照射停止フラグ
照射開始する関数定義
Emit
照射後のビーム更新処理全体図
ここが一番複雑ですが、ひとまず全体の流れです。
細かく分割しながら見ていきます。
ビーム有効判定と照射時間更新
Emit関数内でBeamParticleをActive化しているので、それを見て更新処理を実行しています。
更新処理の頭では照射開始からの継続時間(照射時間)を更新しています。
ビーム長の更新処理と非アクティブ化判定
ビーム照射中は照射停止判定とビームパーティクル終了位置の更新を行います。
ビーム照射停止後はビームパーティクル開始/終了位置どちらも更新が必要です。
また、前述している通り、ビームの長さがほぼ0になる(開始位置が終了位置に追いつく)と非アクティブ化して終了を待ちます。
※パーティクルを非有効化したら放出は止まりますが、すぐには完全に非アクティブになりません。
放出中のものが消えるまで、IsActiveの判定はtrueのままになるので注意が必要です。
ビームパーティクル位置の計算と障害物当たり判定
変数上ではビームパーティクルの位置を長さで持っていますが、ここで実際にどの位置なのかの計算を行います。
GetWorldRotationからGetForwardVectorすることでパーティクルの向きが単位ベクトルとして取得できるので、それに長さを掛けたものにGetWorldLocationで取得したパーティクルの原点(発射口)を足してあげることで位置が計算できます。
障害物の当たり判定にはLineTraceByChannelを使用しています。
これはStartとEndの間を直線で辿った時に、ヒットしたものを取得できるものです。
今回の当たり判定では目で見えるものに当たり判定を行いたかったので、TraceChannelはVisibilityで設定してあります。
当たり判定後の処理
SetBeamSourcePoint/SetBeamTargetPointはビームパーティクルの開始/終了位置を設定できるものです。
つまりLineTraceした時に、当たり判定開始地点はビームパーティクルの開始地点、実際に当たった地点がビームパーティクルの終了地点という事になります。
当たりが発生した場合、終了位置の更新の他、ビームヒット用パーティクルの有効化、終了位置用の変数を当たった地点に合わせて更新するといった処理を行っています。
当たりが発生しなかった場合は終了位置を当たり判定終了地点に設定するのみです。
Emit関数を呼ぶ
最後にFirstPersonCharacterを開き、照射開始のイベントを追加します。
イベントグラフの中に既にSpawn projectileという処理があり、ここの内容を今回作成したものに置き換えるだけです。
これで実装完了です