【Unity/3D】被ダメージ時の点滅表現

【Unity】被ダメージ点滅表現の前のズームキック

3Dモデルを使用している場合の、被ダメージ時の点滅表現の実装方法。
Rendererの表示/非表示をn秒毎に切り替える事で再現した。

何回もブラッシュアップした記事。

以下、格ゲー風サンプル動画。

変更履歴

*微修正は除く。

21/03/03 コード修正

ミスもあり、酷いコードだったので、修正しました。
不確かな記事を載せて申し訳ないです。

以下変更点。

  • 命名をFlashing→Flickerに変更(URLはそのまま)。
  • OnCollisionEnterの位置がおかしかったのを修正。
  • SetEnabledRenderersをforeach→forへ。
  • enabledの反転処理を一行に。

21/08/03 記事、コード修正

  • 無駄に迷わせるかも知れないので、記事の項目を統合。
  • リセットを追加(キャラクターをオブジェクトプール化した場合のゲームオーバー時用)。
  • 一部命名を変更。

「キャラクターの3DモデルのRenderer」が複数に分散されている場合

  • コード内で細かい解説をしている。
  • 実行例の雰囲気はコード内にコメントアウトして記述。

使い方

  1. StartやAwake等、初期化のタイミングで3DモデルのRendererを全て取得。
    配列として保持しておく。
  2. ダメージを受けた時に、Damagedを呼ぶ。

コード


//子のRendererの配列。
	Renderer[] childrenRenderer;

//今childrenRendererが有効か無効かのフラグ。
	bool isEnabledRenderers;

//ダメージを受けているかのフラグ。
	bool isDamaged;

//リセットする時の為にコルーチンを保持しておく。
	Coroutine flicker;


//ダメージ点滅の長さ。無敵時間と共通。

//任意の値。
	float flickerDuration = 1.5f;

//ダメージ点滅の合計経過時間。    
	float flickerTotalElapsedTime;
//ダメージ点滅のRendererの有効・無効切り替え用の経過時間。
	float flickerElapsedTime;

//ダメージ点滅のRendererの有効・無効切り替え用のインターバル。
//任意の値。
	float flickerInterval = 0.075f;



//初期化時に子のRendererを全て取得しておく。Startか、Awakeに追記すれば良い。
//Renderer系全てに対応。
	void Awake()
	{
		childrenRenderer = GetComponentsInChildren<Renderer>(); 
	}


	void Damaged()
	{
//ダメージ点滅中は二重に実行しない。
		if (isDamaged)
			return;

/*
//ここでHPを減らしたりとかする。
		hp -= damage;
		if (hp < 0)
			hp = 0;
*/

/*
//そのダメージによって死んだ場合は、ダメージ点滅させない。
		if (hp <= 0) {
			Died();
			return;
		}
*/

		StartFlicker();
	}



	void SetEnabledRenderers(bool b)
	{
//多分forの方が軽いと思ったからこう書いた。foreachでも良いです。
		for (int i = 0; i < childrenRenderer.Length; i++)
		{
			childrenRenderer[i].enabled = b;
		}
	}


	void StartFlicker()
	{
//isDamagedで多重実行を防いでいるので、ここで多重実行を弾かなくてもOK。        
		flicker = StartCoroutine(Flicker());                 
	}


	IEnumerator Flicker()
	{

		isDamaged = true;

		flickerTotalElapsedTime = 0;
		flickerElapsedTime = 0;

		while (true) {

			flickerTotalElapsedTime += Time.deltaTime;
			flickerElapsedTime += Time.deltaTime;



			if (flickerInterval <= flickerElapsedTime) {
//ここが被ダメージ点滅の処理。


				flickerElapsedTime = 0;
//Rendererの有効、無効の反転。
				isEnabledRenderers = !isEnabledRenderers;
				SetEnabledRenderers(isEnabledRenderers);

			}


			if (flickerDuration <= flickerTotalElapsedTime) {
//ここが被ダメージ点滅の終了時の処理。

				isDamaged = false;

//最後には必ずRendererを有効にする(消えっぱなしになるのを防ぐ)。
				isEnabledRenderers = true;
				SetEnabledRenderers(true);

				flicker = null;
				yield break;
			}

			yield return null;
		}

	}

//コルーチンのリセット用。
	void ResetFlicker()
	{
		if (flicker != null) {
			StopCoroutine(flicker);
			flicker = null;
		}
	}


/*
//リセットの雰囲気。ゲームオーバー時等に実行。
	void Reset()
	{
		ResetFlicker();

		isDamaged = false;
		isEnabledRenderers = true;
		SetEnabledRenderers(true);


		
	}
*/

/*
//呼ぶ方の一例。
	void OnCollisionEnter(Collision col)
	{
//敵の攻撃に触れたらDamagedを呼ぶ。
		if (col.gameObject.CompareTag("EnemyAttack")) {
			Damaged();
		}
	}
*/

「キャラクターの3DモデルのRenderer」が一つの場合

  • コード内で細かい解説をしている。
  • 実行例の雰囲気はコード内にコメントアウトして記述。

使い方

  1. 3DモデルのRendererをインスペクターから紐付け or 初期化時にGetComponentChildrenで取得。
  2. ダメージを受けた時に、Damagedを呼ぶ。

コード


//3DモデルのRendererをインスペクターから紐付け or 初期化時に取得。
	[SerializeField]
	Renderer renderer;

//ダメージを受けているかのフラグ。
	bool isDamaged;

//リセットする時の為にコルーチンを保持しておく。
	Coroutine flicker;


//ダメージ点滅の長さ。無敵時間と共通。
//任意の値。
	float flickerDuration = 1.5f;

//ダメージ点滅の合計経過時間。
	float flickerTotalElapsedTime;
//ダメージ点滅のRendererの有効・無効切り替え用の経過時間。
	float flickerElapsedTime;

//ダメージ点滅のRendererの有効・無効切り替え用のインターバル。
//任意の値。
	float flickerInterval = 0.075f;




//初期化時に子のRendererを取得しておく。Startか、Awakeに追記すれば良い。
//Renderer系全てに対応。
	void Awake()
	{
//インスペクターから紐付けしていれば必要なし。
//      renderer = GetComponentInChildren<Renderer>();
	}


	void Damaged()
	{
//ダメージ点滅中は二重に実行しない。
		if (isDamaged)
			return;

/*
//ここでHPを減らしたりとかする。
		hp -= damage;
		if (hp < 0)
			hp = 0;
*/

/*
//そのダメージによって死んだ場合は、ダメージ点滅させない。
		if (hp <= 0) {
			Died();
			return;
		}
*/

		StartFlicker();
	}



	void StartFlicker()
	{
//isDamagedで多重実行を防いでいるので、ここで多重実行を弾かなくてもOK。
		flicker = StartCoroutine(Flicker());
	}


	IEnumerator Flicker()
	{

		isDamaged = true;

		flickerTotalElapsedTime = 0;
		flickerElapsedTime = 0;

		while (true) {

			flickerTotalElapsedTime += Time.deltaTime;
			flickerElapsedTime += Time.deltaTime;



			if (flickerInterval <= flickerElapsedTime) {
//ここが被ダメージ点滅の処理。


				flickerElapsedTime = 0;
//Rendererの有効、無効の反転。
				renderer.enabled = !renderer.enabled;

			}


			if (flickerDuration <= flickerTotalElapsedTime) {
//ここが被ダメージ点滅の終了時の処理。

				isDamaged = false;

//最後には必ずRendererを有効にする(消えっぱなしになるのを防ぐ)。
				renderer.enabled = true;

				flicker = null;
				yield break;
			}

			yield return null;
		}

	}

//コルーチンの強制停止用。
	void ResetFlicker()
	{
		if (flicker != null) {
			StopCoroutine(flicker);
			flicker = null;
		}
	}


/*
//リセットの雰囲気。ゲームオーバー時等に実行。
	void Reset()
	{
		ResetFlicker();

		isDamaged = false;
		renderer.enabled = true;


		
	}
*/

/*
//呼ぶ方の一例。
	void OnCollisionEnter(Collision col)
	{
//敵の攻撃に触れたらDamagedを呼ぶ。
		if (col.gameObject.CompareTag("EnemyAttack")) {
			Damaged();
		}
	}
*/

タイトルとURLをコピーしました