UnityでFPSをつくる その9-3 [ 敵の攻撃 ]
Playerが敵の攻撃を受けた時のUIを、スクリプトで操作していきます。
「PlayerHP」と名付けたスクリプトを作成し、以下のコードを貼り付けてください。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerHP : MonoBehaviour
{
//HPゲージ
[SerializeField] int playerHP;
//被ダメージ量
[SerializeField] int receveDamageScore;
//被ダメージ演出用ボード
public Image damageBoard,deathStateBoard;
//HPゲージ用のUI複数をまとめたオブジェクト
public GameObject remainingHp;
//カメラの動きを制御する
Transform transformCamera;
//カメラを揺らす時間の長さ、大きさ
[SerializeField]float duration, magnitude;
//相対位置取得用
Vector3 pos;
// Start is called before the first frame update
void Start()
{
//被ダメージ演出用ボードを透明に初期化
damageBoard.color = Color.clear;
//カメラのTransformを取得
transformCamera = Camera.main.transform;
//Playerからの相対位置を取得
pos = transformCamera.localPosition;
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter(Collider other)
{
//弾にぶつかったら
if (other.tag == "EnemyBullet")
{
//プレイヤーのHPを減少させる
playerHP -= receveDamageScore;
//画面を点滅させるコルーチンの開始
StartCoroutine("damageFlashing");
//カメラを揺らすコルーチンの開始
StartCoroutine(shakeCamera(duration, magnitude));
//ダメージを受けたら対応するHPゲージを黒色にする
if (playerHP <= 4)
{
remainingHp.transform.Find("RemainingHp_5").gameObject.GetComponent<Image>().color = Color.black;
}
if (playerHP <= 3)
{
remainingHp.transform.Find("RemainingHp_4").gameObject.GetComponent<Image>().color = Color.black;
}
if (playerHP <= 2)
{
remainingHp.transform.Find("RemainingHp_3").gameObject.GetComponent<Image>().color = Color.black;
}
if (playerHP <= 1)
{
remainingHp.transform.Find("RemainingHp_2").gameObject.GetComponent<Image>().color = Color.black;
}
if (playerHP <= 0)
{
remainingHp.transform.Find("RemainingHp_1").gameObject.GetComponent<Image>().color = Color.black;
//スクリプトをOFFにする
GetComponent<PlayerMove>().enabled = false;
//その場で停止させる
GetComponent<Rigidbody>().velocity = Vector3.zero;
//死亡状態用に画面を赤くする
deathStateBoard.color = new Color(1f, 0f, 0f, 0.9f);
}
}
}
//画面を点滅
IEnumerator damageFlashing()
{
//被ダメージ演出用ボードを薄い赤色にする
damageBoard.color = new Color(1f, 0f, 0f, 0.7f);
//次の処理に移行するまでの待機時間
yield return new WaitForSeconds(0.15f);
//被ダメージ演出用ボードを透明にする
damageBoard.color = Color.clear;
}
//カメラを揺らす
IEnumerator shakeCamera(float duration, float magnitude)
{
//時間計測用
var elapsed = 0f;
//指定の時間を経過するまで
while (elapsed < duration)
{
//カメラのXY(縦横)位置を動かす
transformCamera.localPosition = new Vector3(pos.x + Random.Range(-1f, 1f) * magnitude, pos.y + Random.Range(-1f, 1f) * magnitude, pos.z);
//経過時間
elapsed += Time.deltaTime;
//次フレームで処理を再開。
yield return null;
}
//揺れる前の位置にカメラを戻す
transformCamera.localPosition = pos;
}
}
コードの内容を見ていきます。
4行目、照準実装時と同様に今回もUIを扱うので、名前空間「UnityEngine.UI」を宣言しています。

9,12行目では、初期状態のHPと、被弾した際にどの程度減少させるかを決める変数を宣言しています。
HPゲージの表示に合わせてHPは「5」、ダメ―ジは「1」ずつ負う設定にします。

15,18行目は、さきほど作成したUIを取得する為の変数を宣言しています。

21,24,27行目は、ダメージを負った際の、カメラを揺らす処理に使う変数を宣言しています。

33行目は、Imageオブジェクトの色を透明にし忘れた場合の保険として、初期化をしています。

36行目で、Transformの探索結果の参照を変数にキャッシュし、
39行目で、カメラを揺らした後に戻す基準となる相対位置を取得しています。

48~54行目で、弾がぶつかった際にタグで判別し、HPを1減らしています。


StartCoroutineで()内の名前が付いたコルーチンを開始します。
damageFlashingの定義は96~106行目に書いています。

戻り値の型をIEnumeratorとし、処理を中断するタイミングを yieldに続けて記述します。
この中断が加わることで、1フレーム内で処理を完了させていた今までの関数との違いが生まれます。

弾とぶつかった際にdamageBoardを薄い赤色にして、0.15秒経過後に初期状態と同じ透明に戻しています。
60行目は、カメラを揺らす処理にコルーチンを使っています。

定義は109~128行目です。

引数にfloat型変数を2つ持ち、その値を元にどのくらいの時間、どのくらいの大きさで揺らすのかを決めています。
今回は画面の点滅と時間を揃えて、0.15秒揺らすようにします。
時間の計測にはvarで型指定をした変数を使っています。
今まで変数を宣言する際の型指定は「int」「float」のように明示していましたが、varの場合は暗黙的な型指定となり、代入される値によって型が決まります。

while文は()内の条件式がtrueの間{}の処理を繰り返します。
これを使って経過時間の比較を行い、Random.Rangeにより-1から1の範囲で乱数を発生させて、magnitudeで指定した大きさを掛け合わせ、+-XY方向にカメラの位置を移動させることで揺れを実現しています。

経過時間はTime.deltaTime(直前のフレームからの経過時間)で取得するようにしているので、Update内で書く時同様、1フレームで1回取得するようにコルーチンを中断・再開させる必要があります。
その場合はyield return nullを使います。
while等の繰り返し処理の中にyield return nullを記述することにより、その行まできたら処理を中断して、次フレームから再開できます。
今回のようにwhile文{}内の最終行に書くことで、繰り返し処理が1フレームにつき1回実行されるようになりました。

カメラを揺らし終えた後、揺らす前の位置を記憶しておいた変数を代入し、Playerオブジェクトとの相対位置を元通りにしています。
63行目からは、残りHPに応じた処理を行っています。
被弾1~4発目までは対応HPゲージを黒にしています。


被弾5発目はHPゲージを黒にする処理に加え、プレイヤーの入力を受け付けなくする為に、スクリプトのOFF(trueでON)、移動停止、画面を赤くして死亡状態を演出しています。


最後に、このスクリプトをPlayerオブジェクトへアタッチし、各項目を以下のように設定します。

以上で[ 敵の攻撃 ]の説明を終わります、おつかれさまでした!