15.特殊な敵を実装する
前回の記事で書いたように、今回のゲームでは敵と武器とは対になります。
(断続的に登場するオーソドックスな敵)
これはすでに実装しているZonbunnyちゃんで良いでしょう。
(一斉に大量登場するが、HPが低い敵)
Zonbearちゃんのパラメータを調整すれば実現できそうです。
(盾orバリアを持っておりかつ、ダメージを食らわないでいると盾の耐久が回復する敵)
実装が必要ですね。今回はHellephantちゃんをこのシールド持ちにしましょう。
そうしてできた完成図がコチラ。
実装の段取りはこのようになります。
- Unity上でShieldとなるObjectを用意する
- Shieldに射撃RayがぶつかったらShieldのHPを減らす
- ShieldのHPがゼロになったらShieldを破壊する
- Shieldがダメージを受けずに一定時間経過したら、ShieldのHPを回復させる
- スナイパーライフルで射撃した時はShieldと本体の両方にダメージを与える
- Shieldにダメージが入った時、シールドの色を変えたり、大きさを小さくしたり、ヒットのエフェクトを表示する
Unity上でShieldとなるObjectを用意する
Hellephantの子Objectとして、3D Object -> cubeを作成し、ShpereColliderをアタッチします。シールドに衝突判定は設けないため、isTriggerにチェックを入れておきます。また、LayerをShootableにしておくことをお忘れなく。後の工程でこれに気づかず、2時間くらいハマりました。
Shieldの色を半透明にしたいため、専用のMaterialを用意します。Projectビューで右クリック -> Materialを作成し、Albedoから半透明の赤に調整し、ShieldObjectのMeshRendererにあるMaterialに設定します。
ShieldHealthManagerの実装
Shieldの管理を行うクラスとしてShieldHealthManagerを用意します。もちろんShieldObjectにアタッチ。
ついでに、ヒット時に大きさを変えたり、エフェクトを表示する処理も一緒に書いてしまいます。色を変える処理はUpdateメソッドもいじる必要があるので事項で説明します。
Shieldにダメージを与える & その際に大きさを変えたりエフェクトを表示する
まずは基本の部分として、TakeShieldDamage()メソッドを実装します。
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 |
public int shieldHealth = 30; int currentShieldHealth; MeshRenderer shieldMeshRend; Color defalutShieldMeshRendColor; float shieldFlashSpeed = 5f; bool damaged; ParticleSystem hitShieldParticles; private void Awake() { currentShieldHealth = shieldHealth; shieldMeshRend = GetComponent<MeshRenderer>(); //デフォのシールド色を保存しておく defalutShieldMeshRendColor = shieldMeshRend.material.color; //particle格納 hitShieldParticles = GameObject.Find("HitParticles").GetComponent<ParticleSystem>(); } public void TakeShieldDamage(int amount, Vector3 hitPoint) { damaged = true; if(currentShieldHealth > 0) { currentShieldHealth -= amount; //shieldを小さくする //TODO 変化率を数値じゃなくて計算にする transform.localScale *= 0.95f; //ぶつかった場所にエフェクトを表示する hitShieldParticles.transform.position = hitPoint; hitShieldParticles.Play(); } else { //shieldを消す Destroy(gameObject); } //攻撃後にシールドのHPが0を下回った時、シールドを消す if(currentShieldHealth <= 0) { Destroy(gameObject); } timer = 0; } |
EnemyHealthクラスのTakeDamage()メソッドをひな型に、変数の名前を書いたりShieldだけの処理を入れたりしてます。
次に、このメソッドの実行元として、PlayerShootingクラスのShoot()メソッドを修正します。
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 64 65 66 67 68 69 70 71 72 73 74 75 76 |
public void Shoot ( bool isPierce, bool isDiffuse, int numBullet, AudioClip fireClip, float range, int damagePerShot, int maxNbPower, int maxAmmo ) { (略) for (int i = 0; i < numRay; i++) { //SRの処理 if (isPierce) { RaycastHit[] hits = Physics.RaycastAll(shootRay[i]); foreach (var obj in hits) { //Rayがぶつかった対象は盾持ちか EnemyShield enemyShield = obj.collider.GetComponent<EnemyShield>(); //Rayがぶつかった対象にEnemyHealthコンポーネントがついているか(=エネミーだったら) EnemyHealth enemyHealth = obj.collider.GetComponent<EnemyHealth>(); //シールドがついてたら、シールドにダメージを与える if(enemyShield != null) { enemyShield.TakeShieldDamage(damagePerShot, obj.point); } //シールドがついてなくてエネミーだったらダメージ&ノックバック else if (enemyHealth != null) { (略) } } } else { //objectのLayerにshootableMask指定するの忘れがち if (Physics.Raycast(shootRay[i], out shootHit, range, shootableMask)) { //Rayがぶつかった対象は盾持ちか EnemyShield enemyShield = shootHit.collider.GetComponent<EnemyShield>(); //Rayがぶつかった対象にEnemyHealthコンポーネントがついているか(=エネミーだったら) EnemyHealth enemyHealth = shootHit.collider.GetComponent<EnemyHealth>(); //シールドがついてたらシールドのみにダメージをあたえる if(enemyShield != null) { enemyShield.TakeShieldDamage(damagePerShot, shootHit.point); } else if (enemyHealth != null) { (略) } (略) } else { (略) } } } (略) } |
EnemyHealthの判定を行う前にEnemyShieldの判定を差し込んでいます。
isTriggerにチェックを入れたColliderでもRayが衝突判定を返してくれるようにUnity側の設定を変更します。
Edit>ProjectSetting>PhysicsよりQuerriesHitTriggersにチェックを入れればOKです。
Shieldを回復させる & ヒット時にシールドの色を変える
一定時間Shieldへのダメージがなかったら、ShieldのHPを回復させます。これにより、スナイパーライフル以外の武器で倒すには集中砲火が必要となり、ほかの敵と合わせて出現した時のいやらしさが倍増します。
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 |
<br /> //シールドの回復量 public int numHealShield = 5; //シールド回復開始までの時間 float healIntervalTime = 5.0f; float timer; private void Update() { timer += Time.deltaTime; //TakeShieldDamageメソッド実行時にdamaged = true if (damaged) { //光らせる:shieldMaterialを一瞬透明にする shieldMeshRend.material.color = defalutShieldMeshRendColor + new Color(0, 0, 0, 1.0f); } else { //シールドの色をだんだん戻す shieldMeshRend.material.color = Color.Lerp(shieldMeshRend.material.color, defalutShieldMeshRendColor, shieldFlashSpeed * Time.deltaTime); } damaged = false; if(timer > healIntervalTime) { HealSheild(); } } void HealSheild() { if(currentShieldHealth >= shieldHealth) { return; } else { currentShieldHealth += numHealShield; //シールドの大きさを戻す //TODO 変化率を数値じゃなくて計算にする transform.localScale /= 0.95f; } } |
回復の処理は非常にシンプルですね。HPの値と一緒にShieldの大きさも戻してあげます。
シールドの大きさの変化率は数値を直で入れてしまってますが、本当はShieldのHPと、Colliderの大きさとの関係から計算式にすべきです。が、ややこしくなりそうなので今の段階では先送ってます。
また、ヒット時、Shieldの色にアルファ値を足してあげることで透明度を変更しています。
その直後からだんだんと色味を戻すため、Lerp関数を使っています。これはぜひ引き出しとして持っておきたい手法。
これにてShieldの実装は完了~~!!動かしてみて、攻撃を当てるたびに色が変わって小さくなること、HPがゼロになったら消滅すること、スナイパーライフルでは中身ごと攻撃できることを確認したらおしまいです。
次回はコチラ
Unity公式チュートリアルSurvival Shooter WITH PK Chapter.15「特殊な敵を実装する」
前回はコチラ
Unity公式チュートリアルSurvival Shooter WITH PK Chapter.14「武器変更を実装する」
「Unity公式チュートリアルSurvival Shooter WITH PK Chapter.15「特殊な敵を実装する」」への1件のフィードバック