こんばんは、睦月ハツカです。
今回はVRで音ゲーを作ってるところなので、それのノーツ系のオブジェクトの作り方のメモを自分の忘備録程度に書いていきます。
音ゲーと言えばノーツ(音符みたいなやつ)が降ってきたり流れてきて、それに合わせてタイミングよくボタンを押すゲームですね。
今回はVRで、ということで、周りに現れるノーツをタイミング良く叩くゲームにしたいと思っています。
そこで、タイミングよくたたくにしても叩けるオブジェクトがないので、今回はまず触れたら弾けるオブジェクトを作っていきます。
0.ざっくりした流れ
簡単に言ってこんな流れになります。
- Colliderコンポーネントが入ってるオブジェクトを用意する
- パーティクルシステムを作成
- スクリプトを書いて出現を制御
- プレファブにしてまとめる
1.Colliderコンポーネントが入ってるオブジェクトを用意する
Colliderコンポーネントが入ったGameObjectを用意します。
一番わかりやすいのはCreateボタンから作成できるSphereとかですね。
見た目は後からでも変えられるので今回はSphereで行きます。
2.パーティクルを作成
パーティクルシステムを追加
デフォルトだと間欠泉みたいに白いふわふわが吹き出しています。
これだとだらだら垂れ流している感じになってしまうので、パーティクルがはじけてからさっさと消えるようにします。
ParticleSystemの設定値
以下の変更をしていきます
・Duration=0.5 ・Looping=false
Emission
Burstのリスト(白い枠)の+マークをクリックしてデータを追加
Shape
Shape=Sphere
値を変えた後のパーティクルの動きがこちら。
Shapeをいろいろ変えてみるのも面白そうです。
その次にinspectorのparticleSystemコンポーネント
最後にこのパーティクルのGameObjectのTransformのPositionを0,0,0にしておいてください。
3.スクリプトを書いて出現を制御する
スクリプトを最初に作成したSphereにアタッチして、スクリプトを書いていきます。
public class NormalNotes : Notes { GameObject effectBuff; [SerializeField] GameObject goodEffect;//←これがパーティクルのオブジェクト TimeManager timeManager; void Start() { response = gameObject.GetComponent<AudioSource>(); } //触った時の処理 void OnCollisionEnter(Collision context) { effectBuff = null; response.Play(); if (this.timing == 0f) { effectBuff = Instantiate(goodEffect, new Vector3(0f, 0f, 0f), Quaternion.identity); effectBuff.transform.parent = this.transform; effectBuff.transform.position = this.transform.position; this.GetComponent().enabled = false; effectBuff.GetComponent().Play(); } if(this.transform.parent){ Destroy(this.transform.parent.gameObject,0.3f); Destroy(this.gameObject, 0.3f); }else{ Destroy(this.gameObject, 0.3f); } } }
雑に書いたスクリプトがコレ。
このコード全部コピペしても多分エラー吐くので考え方の参考のみで。
肝心なのはOnCollisionEnterメソッド。これでSphereに触った時にこの中の処理が走ります。
GameObjectインスタンスのeffectBuffを利用してパーティクルの出現箇所を制御します。
処理の簡単な流れ
ざっくりとした処理の内容は
effectBuffにパーティクルオブジェクトを複製
↓
複製したパーティクルオブジェクトの出現箇所を指定
今回はthis.transformなのでアタッチされているSphereの場所
↓
Sphereを透明化
↓
パーティクルを出現させる
↓
オブジェクトを削除
という流れ。
ちなみに上の例で、goodEffectは宣言時に[SerializeField]と前に記述されていますが、これはUnityのエディタ上にこの変数が表示・編集をすることが可能になるキーワードです。このオブジェクトがGetComponentメソッドを呼び出していない理由は、Unityエディタで設定することができるからです。
4.プレファブにしてまとめる・設定値を整理する
スクリプトを書いたらSphereオブジェクトとパーティクルオブジェクトをそれぞれプレファブにまとめてフォルダから使いまわしできるようにしましょう。
Sphereオブジェクトを選択してプロジェクトビューにドラッグ&ドロップします。
パーティクルオブジェクトにも同様の操作をします。
するとプロジェクトビュー内に二つのプレファブが生成されます。
いつまでもSphereという名前だと今後使う時に区別がつかないので名前を変えます。
Sphere→ExplodeObject
ParticleSystem→GoodEffect
ExploseObjectにアタッチされている先ほどのスクリプトをinspectorから設定します。
先ほど[SerializeField]を設定した変数がInspectorに表示されるようになってるのが分かると思います。
GoodEffectの場所に作成したプレファブのGoodEffectをドラッグ&ドロップします。
これで触れたら弾けるオブジェクトの出来上がりです。
※動画は音が鳴るので注意
ExploseObjectに何かがぶつかるとパーティクルを放出して消滅します。
その他補足とかメモ
パーティクルが表示されない???
処理の順番を前後させても一度の処理は同時におこなわれます。パーティクルの再生中にオブジェクトが消えてしまっている状態が考えられます。
パーティクルオブジェクトのPlay()とDestroy()はDestroy()が最後に処理されるコードですが、引数(()の中身)の2つ目に注目。
これは消えるまでの遅延時間を設定しています。この遅延時間を0にしてしまうと、パーティクルオブジェクトがせっかく生成、再生されても、それと同時に消滅させられてしまうので、再生処理をしても見ることができません。悲しい。
僕もよくUnityでソースコード書いてると処理されるタイミングがUpdateとかTimeで混乱しかけることがありましたという余談でした。
プレファブを分けるメリット
これは単純にスクリプトを書き換える手間なくパーティクルだけ置き換えることができるようにするためです。
プレファブを作成してモジュール化すると、ソースコードの修正をせずにパーティクルエフェクトだけを作り変えることができます。便利。RPGでキャラクターの武器だけを変更する時などの使い方に使えそうです。
今回は単純にメモ程度で。以上!