Unityで3Dモデルの色を点滅させる

Unity

3Dモデルの色を点滅するスクリプトです。

実際に使うファイルは下の方にあります。

ダメージを食らったときとかの演出に使ってます。

Start()の中で、Renderer系のコンポーネント(SpriteRendererとかMeshRendererとか)を持つオブジェクトをGetcomponentsInChildren()で取得して、さらにRendererコンポーネントの持っているmaterialをすべて取得。

materialをKeyにして、該当materialの初期カラーをDictionaryに入れてます。

注意点として、materialがカラーのプロパティを持っていないと使えません。持っていないときはマテリアルを新しく作り、カラーのプロパティを持ったシェーダを設定する必要があります。

 
    //一度にすると時間かかりそうなのでコルーチンを使う
    //カラーの初期値も必要なのでDictionary型を使う
    //自分以下のオブジェクトから、カラー付きマテリアルをカラーと一緒にDictionaryにいれる
    //
    Dictionary _materialAndInitialColors;
    protected virtual IEnumerator/*スタート時に全て取得するならここはvoidでも良い*/ DetectAllRenderer(GameObject target)
    {
        _materialAndInitialColors = new Dictionary();
        Renderer[] renderers = target.GetComponentsInChildren();
        foreach (Renderer render in renderers)//レンダラーすべてを調べる
        {

            foreach (Material material in render.materials)//マテリアルすべてを調査
            {
                if (material.HasProperty("_Color"))
                {
                    _materialAndInitialColors.Add(material, material.color);
                    break;
                }
            }
            yield return new WaitForEndOfFrame();/*IEnumeratorをvoidにしたらこの行は不要*/
        }
    }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//色を点滅
//カラーを持っているマテリアルと初期値のカラーを辞書型で渡す
//初期値のカラーをマテリアルごとに設定しておかないといけないので辞書型を使った
public class ImageFlicker
{
    
    public static IEnumerator Flicker(Dictionary matAndInitialColors,
        Color flickerColor, float flickerSpeed, float flickerDuration)
    {
       
        if(matAndInitialColors.Count == 0)
        {
#if UNITY_EDITOR
            Debug.Log("マテリアルがセットできていない:コルーチンを使っているが数フレームで取得できるはず");
#endif
            yield break;
        }
        float flickerStop = Time.time + flickerDuration;
        while(Time.time < flickerStop)
        {
            
            foreach(Material mat in matAndInitialColors.Keys)
            {
                mat.color = flickerColor;
            }
            yield return new WaitForSeconds(flickerSpeed);
            foreach(KeyValuePair kvp in matAndInitialColors)
            {
                kvp.Key.color = kvp.Value;
            }
            yield return new WaitForSeconds(flickerSpeed);
        }
    }   
//オブジェクトをプールする場合,ゲームオブジェクトが破壊されたときに呼び出したほうが良いかも
public static void ColorInitialize(Dictionary matAndInitialColors)
    {
        if (matAndInitialColors == null || matAndInitialColors.Count == 0)
        {
#if UNITY_EDITOR
            Debug.Log("マテリアルがセットできていない:コルーチンを使っているが数フレームで取得できるはず");
#endif
            return;
        }
        foreach (KeyValuePair kvp in matAndInitialColors)
        {
            kvp.Key.color = kvp.Value;
        }
    } 
}

一つにまとめたスクリプトが↓です。

このcsファイルを使えばそのままコンポーネントとして使えるはずです。試してませんが。

スプライトにも多分使える? 試してませんが。

FlickerModel.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class FlickerModel : MonoBehaviour
{
    [SerializeField,Header("ダメージを受けたときの点滅色")]
    protected Color flickerColor = Color.red;
    [SerializeField]
    protected float flickerDuration = 0.5f, flickerSpeed = 0.1f;
    protected Dictionary _materialAndInitialColors;
    protected virtual void Start()
    {
	StartCoroutine(DetectAllRenderer(gameObject);
    }
    //使うときはこれを呼び出します
    public void FlickerModel(){
	StartCoroutine( ImageFlicker.Flicker(_materialAndInitialColors, flickerColor, flickerSpeed, flickerDuration));
    }
   
    //一度にすると時間かかりそうなのでコルーチンを使う
    //カラーの初期値も必要なのでDictionary型を使う
    //オブジェクトの持つカラー付きマテリアルをカラーと一緒にいれる
    protected virtual IEnumerator DetectAllRenderer(GameObject target)
    {
        _materialAndInitialColors = new Dictionary();
        Renderer[] renderers = target.GetComponentsInChildren();
        foreach (Renderer render in renderers)//レンダラーすべてを調べる
        {

            foreach (Material material in render.materials)//マテリアルすべてを調査
            {
                if (material.HasProperty("_Color"))
                {
                    _materialAndInitialColors.Add(material, material.color);
                    break;
                }
            }
            yield return new WaitForEndOfFrame();
        }
    }
}
//色を点滅
//初期値のカラーをマテリアルごとに設定しておかないといけないので辞書型を使った
public class ImageFlicker
{
    
    public static IEnumerator Flicker(Dictionary matAndInitialColors/*マテリアルと初期設定してあるカラー*/,
        Color flickerColor/*点滅する色*/, float flickerSpeed/*点滅の速さ*/, float flickerDuration/*点滅する時間,秒*/)
    {
       
        if(matAndInitialColors.Count == 0)
        {
#if UNITY_EDITOR
            Debug.Log("マテリアルがセットできていない:コルーチンを使っているが数フレームで取得できるはず");
#endif
            yield break;
        }
        float flickerStop = Time.time + flickerDuration;
        while(Time.time < flickerStop)
        {
            
            foreach(Material mat in matAndInitialColors.Keys)
            {
                mat.color = flickerColor;
            }
            yield return new WaitForSeconds(flickerSpeed);
            foreach(KeyValuePair kvp in matAndInitialColors)
            {
                kvp.Key.color = kvp.Value;
            }
            yield return new WaitForSeconds(flickerSpeed);
        }
    }
//追記
//オブジェクトをプールする場合、OnDisableとかで呼び出さないと赤色のまま出現することがあります
   public static void ColorInitialize(Dictionary matAndInitialColors)
    {
        if (matAndInitialColors == null || matAndInitialColors.Count == 0)
        {
#if UNITY_EDITOR
            Debug.Log("マテリアルがセットできていない:コルーチンを使っているが数フレームで取得できるはず");
#endif
            return;
        }
        foreach (KeyValuePair kvp in matAndInitialColors)
        {
            kvp.Key.color = kvp.Value;
        }
    }
    
}

ImageFlickerは別ファイルにしても大丈夫です。

色んなやり方があると思います。

コメント

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