[Unity][ParticleSystem]3D座標を起点にuGUI上にパーティクルを発生・収束させる
サンプル動画
移動や連発にも対応してようやく納得いくものが出来た
色々妥協してる部分もあるけど個人的には満足 pic.twitter.com/hWVOqxVhAw
— madoramu (@madoramu_f) 2019年3月8日
移動や連発にも対応してようやく納得いくものが出来た
色々妥協してる部分もあるけど個人的には満足 pic.twitter.com/hWVOqxVhAw
3Dアクションゲームなどで良くある、
「敵を攻撃したらパーティクルが発生して、UI上のゲージに向かって飛んでゲージが溜まる。」
というものを実装してみました。
(割と需要あると思っているのですが、どこにもサンプルが無かったので自作することに)
サンプルプロジェクト
以下のGithubに上げてあります
https://github.com/madoramu/ParticleHorming
※サンプル動画は別プロジェクトの物なので、上記URLのプロジェクトは少し内容が異なります。
環境
Unity2018.3
WindowsとAndroidで動作確認済み
重要:ScreenSpaceCamera設定のCanvasのみ対応しています
実装方法
サンプルプロジェクトの中身を抜粋して説明していきます。
細かい部分などはプロジェクトを閲覧してください。
メインカメラとUIカメラの用意・設定
メインカメラ
こちらはキャラクターの追尾、およびUI以外の描画を担当。
- CullingMaskで「UI」を除外する。
- Depthを「0」にする。
- UIカメラより低ければおk
UIカメラ
UIの描画のみ担当。
- メインカメラには絶対映らない場所に移動させる
- AudioListenerは外しておく
- ClearFlagsを「Depth Only」にする。
- CullingMaskで「UI」だけにする。
- Depthを「10」にする。
- メインカメラより高ければおk
上記二つのカメラ設定により、メインカメラの描画の後にUIレイヤーの情報が上に描画されます。
キャンバスの用意と設定(重要)
UI表示用・座標変換用で2つのScreenSpaceCamera設定Canvasを用意します。
- UI表示用にはUIカメラ、座標変換用にはメインカメラをそれぞれ設定する
- RectTransform以外のパラメーターは全て同じにする事
- 一応念のため
※何故設定カメラ以外同じパラメーターのCanvasを二つ使用したのかは感想に記載しています。
ParticleSystemの設定
ここは好みに合わせて弄って問題ありませんが、以下の2点は必須です。
- ParticleSystemオブジェクトのLayerは「必ず「UI」に設定する事」
- UI表示用のCanvas直下に配置する事
「何故World設定か?」
- 後述のパーティクル発生処理で解説しますが、ParticleSystemそのものを移動させるので、Localだとその移動にパーティクルも追従してしまうため。
「Rederer→Order in Layerについて」
- 上記画像には映っていませんが、今回はUIより前面に出したかったため値を増やしました。ここはお好みでおk。
パーティクル発生処理
ParticleSystem.Emitを使用して、意図的にパーティクルを発生させることが出来ます。
https://docs.unity3d.com/ja/current/ScriptReference/ParticleSystem.Emit.html
処理の流れ
- 3D座標からScreenSpaceCanvas上の2D座標に変換
- ゲームだと主に敵に攻撃が当たった時の、敵座標位置が3D座標になります。
- テラシュールブログを参考(というかほぼ丸パクリ)にして作成しました。
- 下記ページの「World Space を Screen Space Cameraへ」です。
- http://tsubakit1.hateblo.jp/entry/2016/03/01/020510
- 変換した2D座標にParticleSystemを移動
- Emitでパーティクル生成。
以下コード抜粋
public void CreateParticle()
{
// 3D空間座標からカメラスクリーン上の座標に変換する
Vector3 basePos = m_Emit3DTransformList.GetRandom().position; // GetRandom()についてはListExtensionsを参照
Vector2 screenPos = m_Camera.WorldToScreenPoint(basePos);
// カメラスクリーン座標をキャンバス上のローカル座標に変換する
Vector2 cameraCanvasPos = Vector2.zero;
RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RaycasterCameraCanvasRectTransform, screenPos, m_Camera, out cameraCanvasPos);
// 座標確認
Debug.LogFormat("rectPos{0}", cameraCanvasPos);
// ParticleSystemを放出位置に移動させてEmit
m_ParticleSystem.transform.localPosition = cameraCanvasPos;
m_ParticleSystem.Emit(m_EmitParticleCount);
}
パーティクル更新(収束)処理
普段パーティクルをスクリプト側で操作することは余り無いですが、今回は特定位置に収束させたかったのでググった結果、公式サイトで以下のページが出てきました。
https://docs.unity3d.com/ja/current/ScriptReference/ParticleSystem.GetParticles.html
このページを参考に以下の様な処理で更新させることにしました。
// 更新
for(int i = 0; i < m_ActiveParticleCount; ++i)
{
float rate = (1.0f - m_ParticleList[i].remainingLifetime / m_ParticleList[i].startLifetime);
rate = Mathf.Pow(rate, m_ReactionDistance); // 指数関数を加えることにより、収束する勢いを変更できるようにしてる
m_ParticleList[i].position = Vector3.Lerp(m_ParticleList[i].position, m_TargetTransform.position, rate);
}
m_ParticleSystem.SetParticles(m_ParticleList, m_ActiveParticleCount);
今回は指数関数を使って、等速直線移動ではなく少しアレンジをしています。
ここに関しては書き方によって幾通りも表現が出来ると思います。
感想
当初はScreenSpaceCameraのCanvas一つで解決できないか試行錯誤していましたが、キャラを追尾する = Canvasが移動する関係上、パーティクルが毎フレームぶれたり座標がおかしなことになったりした結果、今の形に落ち着きました。
冒頭でも言った通りScreenSpaceOverlay設定のCanvasには対応できないので、結構使いどころは限定的かも。
ですが、ParticleSystem上でパーティクルをいつも通り設定できるメリットは大きいので、個人的には満足度高めです。
Author And Source
この問題について([Unity][ParticleSystem]3D座標を起点にuGUI上にパーティクルを発生・収束させる), 我々は、より多くの情報をここで見つけました https://qiita.com/madoramu_f/items/f0d1a49a909ad1a8e9c5著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .