アクションゲームで剣を振った時や魔法を使った時等にパーティクルを飛ばして敵に当たった時にダメージを与えたい事があります。
そこで今回はUnityのパーティクルにコライダを設定し主人公が剣を振った時に衝撃波を前に飛ばし敵との当たり判定が出来るようにしていきます。
パーティクル粒子の1つ1つの衝突を検知したい場合は
↑の記事を参照してください。
ファンタジーの世界ならば魔法を唱えた後に炎や氷、風のパーティクルを飛ばして敵に攻撃をする時にも同じように使えます。
魔法によって前方に飛ばすだけでなく前後左右に同じパーティクルを飛ばすといった事も可能になります。
パーティクルの設定
まずは剣を振った時に飛ばす衝撃波のパーティクルを用意しましょう。
UnityのParticleSystemを使って自前のパーティクルを作成してもいいのですが、難しいのと時間がかかるので、
AssetStoreでダウンロードしたものを使用します。
わたくしはFX EXplosion Packをインポートさせて頂きました。
パーティクルをインポートしたらヒエラルキー上にドラッグ&ドロップしてください。
今回使用するパーティクルは↑のような階層になっています。
Exposion-[Explosion10]がParticleSystemになっているのでここのLoopingにチェックを入れSceneタブでパーティクルを連続して再生させ確認します。
今回使用する衝撃波のパーティクルは↑のような感じです。
衝撃波なのに爆発パーティクルを使用してますが・・・・まぁ気にしないでください。(^_^;)
パーティクルにコライダを設定する
大元のExplosion10のインスペクタからAdd Component→Physics→Box Colliderを取りつけます。
コライダのサイズをSceneタブのパーティクルのサイズを見ながら調整します。
このコライダは単純な当たり判定部分なのでパーティクルと完全に一致せず当たり判定として使いたいサイズに調整します。
調整が終わったらさきほどチェックしたParticleSystemのLoopingのチェックを外します。
ここまでで当たり判定を付けたパーティクルが作成出来ました。
まだパーティクルを飛ばすスクリプトの作成はしてませんが、その前に主人公キャラの作成をしていきましょう。
その後にパーティクルにスクリプトを設定していきます。
主人公キャラの設定
主人公キャラクターにはStandardAssetsに入っているEthanを使います。
キャラクターの移動、アニメーション、装備した剣を振る機能を取りつけてください。
キャラクターの移動に関しては
アニメーションに関しては
攻撃機能やアニメーションイベントについては
を参照して機能を取りつけてみてください。
アニメーションイベントでAttackStart、AttackEndというイベントを発生させる必要があります。
衝撃波を飛ばす確認だけして面倒な設定はしたくないという方は主人公に
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using UnityEngine; using System.Collections; public class ShockwaveTest : MonoBehaviour { [SerializeField] private GameObject shockwavePrefab; void Update () { if(Input.GetButtonDown("Fire1")) { // 衝撃波プレハブをインスタンス化 var shockwaveInstance = Instantiate<GameObject>(shockwavePrefab, transform.position + transform.forward, Quaternion.identity); // 衝撃波の飛んでいく方向を指定 shockwaveInstance.GetComponent<ShockwaveMove>().SetDirection(transform.forward); } } } |
というスクリプトを取りつけマウスの左ボタンを押した時に衝撃波を発生させるようにします。
さきほどの記事で主人公の動きやアニメーション、アニメーションイベントを作成した方はEthanにはProcessAttackShockwaveという新しいスクリプトを取りつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using UnityEngine; using System.Collections; public class ProcessAttackShockwave : MonoBehaviour { // 衝撃波のプレハブ [SerializeField] private GameObject shockwavePrefab; void AttackStart() { // 衝撃波プレハブをインスタンス化 var shockwaveInstance = Instantiate<GameObject>(shockwavePrefab, transform.position + transform.forward, Quaternion.identity); // 衝撃波の飛んでいく方向を指定 shockwaveInstance.GetComponent<ShockwaveMove>().SetDirection(transform.forward); } } |
アニメーションイベントでAttackStartが呼び出されたら衝撃波のプレハブをインスタンス化します。
衝撃波のプレハブはさきほど作ったExplosion10を設定します。
登場させる位置はProcessAttackが取り付けてあるEthanの位置(transform.position)+Ethanの1m前方(transform.forward)で、角度はEthanと同じにします。
衝撃波の発生位置をEthanの位置ではなく剣を振った時の位置や角度にすると発生場所や向きが変わってアニメーションによって変化を加える事が出来ます。
インスタンス化したパーティクルにはShockwaveMoveという移動させるスクリプトを取りつける予定でその中にあるSetDirectionメソッドを呼び出してパーティクルの飛ばす方向を設定しています。
これで剣を振った時にパーティクルを主人公の前方に飛ばす事が出来るようになります。
パーティクルにスクリプトを取りつける
パーティクルを移動させたり、当たり判定をするスクリプトを作成し取りつけましょう。
パーティクルを移動させるShockwaveMoveスクリプトの作成
主人公側でパーティクルを出現させる事が出来たのでパーティクルにShockwaveMoveという新しいスクリプトを取りつけ、
自身で勝手に動くようにしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | using UnityEngine; using System.Collections; public class ShockwaveMove : MonoBehaviour { // 飛んでいく方向 private Vector3 direction; // 飛ばす力 [SerializeField] private float power; // Rigidbody private Rigidbody rigid; // パーティクルシステム private ParticleSystem particle; void Start () { rigid = GetComponent<Rigidbody>(); // 自身の子要素からParticleSystemを取得 particle = GetComponentInChildren<ParticleSystem>(); } void Update () { // パーティクルの再生が終わったら衝撃波ゲームオブジェクトを消す if(!particle.isPlaying) { Destroy(this.gameObject); } } // 衝撃波の飛んでいく方向を設定 public void SetDirection(Vector3 direction) { this.direction = direction; } // 衝撃波に力を加えて飛ばす void FixedUpdate() { rigid.AddForce(direction * power); } // 衝突しない判定 void OnTriggerEnter(Collider col) { // 壁か敵に当たった場合 if(col.tag == "Block" || col.tag == "Enemy") { // 敵に当たった場合はダメージを与える if(col.tag == "Enemy") { Destroy(col.gameObject); } // 衝撃波を消す Destroy(this.gameObject); } } // 衝突する判定 void OnCollisionEnter(Collision col) { if(col.gameObject.tag == "Block" || col.gameObject.tag == "Enemy") { if(col.gameObject.tag == "Enemy") { Destroy (col.gameObject); } Destroy(this.gameObject); } } } |
パーティクルはRigidbodyに力を加えて動かします。
Updateメソッドではパーティクルの再生が終わったらパーティクルゲームオブジェクト自体を削除してしまいます。
今回の場合はパーティクルの再生終了と共にゲームオブジェクトを削除してますが、Startメソッドで
1 2 3 | Destory(obj, 5); |
としてインスタンス化されたパーティクルが登場した5秒後にゲームオブジェクトを削除するようにしてもいいと思います。
SetDirectionメソッドはProcessAttackShockwaveスクリプトから呼び出され、パーティクルの進む方向を設定しています。
Rigidbodyに力を加えてパーティクルを移動させるので、FixedUpdateメソッド内で進む方向に力を加えています。
コライダのIs Triggerのチェックのオンオフによってやり方がかわるのでOnTriggerEnterとOnCollisionEnterの両方を記載しました。
を使います。
Is Triggerにチェックが入っていないとパーティクルをインスタンス化した時に主人公自身と衝突判定がされるので、そこら辺の対処も必要になります。
UnityのEditメニュー→Project Settings→PhysicsでPhysicsManagerでレイヤーのマトリックスを表示させ、主人公、剣、パーティクルにそれぞれのレイヤーを設定し、
お互いの接触をしないようにしておくといいかもしれません。
主人公にHuman、剣にSword、パーティクルにShockwaveという名前のレイヤーを設定していたら、
↑のようにShockwaveとHuman、Swordの当たり判定が行われないようにしておきます。
パーティクルゲームオブジェクトの設定
パーティクルの当たり判定、動きのスクリプトが完成したのでパーティクルゲームオブジェクトにスクリプトを取りつけ設定をしましょう。
今回の衝撃波の当たり判定は衝突ではなく空間の接触で判定するよう設定しますので、コライダのIs Triggerにチェックを入れます。
またRigidbodyを使ってパーティクルを移動させるのでAdd Component→Physics→Rigidbodyを取りつけます。
↑のように設定しました。
RigidobodyのUse Gravityにチェックを入れればパーティクルゲームオブジェクトに重力を働かせる事も出来ますが、飛ばした衝撃波に重力が働くとおかしくなるので
今回はチェックを入れません。
物理的なものを投げる場合は重力を働かせるほうがリアルな感じになりますね。
設定が終わったらパーティクルゲームオブジェクトであるExplosion10をAssetsフォルダにドラッグ&ドロップしプレハブ化します。
プレハブ化したらEthanに取り付けたProcessAttackShockwaveのshockwaveにこのExplosion10プレハブを設定しておきます。
これで衝撃波を飛ばす機能が完成しました。
サンプル用に壁と敵の設定をする
衝撃波を飛ばす事が出来るようになりましたので、ぶつける対象である壁と敵とを設置してみます。
壁は3D ObjectのCubeを使って作成し、TagにBlockを設定します。
敵はモデルを配置しCharacterControllerを取りつけコライダのサイズを調整し、TagにEnemyを設定します。
さきほど作成したShockwaveCheckスクリプトの処理から考えると壁にぶつかった時はパーティクルが消滅し、
敵に当たった時はパーティクルを消して敵のゲームオブジェクトを消しています。
衝撃波の機能を確認する
それでは全ての機能が出来たので主人公に剣を振らせ衝撃波を飛ばして確認してみましょう。
衝撃波が壁に当たると消え、敵に当たったら敵が消えていますね。
四方に衝撃波を飛ばしてみる
最後に衝撃波を前方だけでなく四方に飛ばせるようにしてみましょう。
ProcessAttackShockwaveの衝撃波プレハブをインスタンス化している部分を改造します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 武器のコライダを有効にする void AttackStart() { var shockwaveInstance1 = Instantiate<GameObject>(shockwavePrefab, transform.position + transform.forward, Quaternion.identity); var shockwaveInstance2 = Instantiate<GameObject>(shockwavePrefab, transform.position + transform.right, Quaternion.identity); var shockwaveInstance3 = Instantiate<GameObject>(shockwavePrefab, transform.position - transform.right, Quaternion.identity); var shockwaveInstance4 = Instantiate<GameObject>(shockwavePrefab, transform.position - transform.forward, Quaternion.identity); shockwaveInstance1.GetComponent<ShockwaveMove>().SetDirection(transform.forward); shockwaveInstance2.GetComponent<ShockwaveMove>().SetDirection(transform.right); shockwaveInstance3.GetComponent<ShockwaveMove>().SetDirection(-transform.right); shockwaveInstance4.GetComponent<ShockwaveMove>().SetDirection(-transform.forward); } |
4方向分の衝撃波を作成し発生する位置をキャラクターの中心から計算します。
飛ばす方向も前後左右に設定するだけです。
それでは確認してみましょう。
ちゃんと四方に衝撃波が飛んでいますね!
もう少し改造すれば斜め前や後ろにも飛ばす事が出来るので試してみてください。