3Dモデルを使用している場合の、被ダメージ時の点滅表現の実装方法。
Rendererの表示/非表示をn秒毎に切り替える事で再現した。
何回もブラッシュアップした記事。
以下、格ゲー風サンプル動画。
変更履歴
*微修正は除く。
21/03/03 コード修正
ミスもあり、酷いコードだったので、修正しました。
不確かな記事を載せて申し訳ないです。
以下変更点。
- 命名をFlashing→Flickerに変更(URLはそのまま)。
- OnCollisionEnterの位置がおかしかったのを修正。
- SetEnabledRenderersをforeach→forへ。
- enabledの反転処理を一行に。
21/08/03 記事、コード修正
- 無駄に迷わせるかも知れないので、記事の項目を統合。
- リセットを追加(キャラクターをオブジェクトプール化した場合のゲームオーバー時用)。
- 一部命名を変更。
「キャラクターの3DモデルのRenderer」が複数に分散されている場合
- コード内で細かい解説をしている。
- 実行例の雰囲気はコード内にコメントアウトして記述。
使い方
- StartやAwake等、初期化のタイミングで3DモデルのRendererを全て取得。
配列として保持しておく。 - ダメージを受けた時に、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」が一つの場合
- コード内で細かい解説をしている。
- 実行例の雰囲気はコード内にコメントアウトして記述。
使い方
- 3DモデルのRendererをインスペクターから紐付け or 初期化時にGetComponentChildrenで取得。
- ダメージを受けた時に、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();
}
}
*/