2012-05-27

Unityで音のフェードアウト

まあ、たまにはまともな記事も書きますよ。
今回は、Unityの話。たぶん、ブログではそんな扱ってなかったね-。

定期的に音が鳴っているオブジェクトを破棄する場合、audio.Stop()使えばまあ音は止まるんだが、
音がブツっとなるのがちょっと嫌。
で、まあ、音量をフェードアウトさせてから破棄してみようと思った。(volume=0.0fとするだけでも十分という気もしないでもない。)
Audioクラス自体にはフェード機能とかそんなのないので、試しにコルーチンを使ってみる。

 

   void OnHitItem()
    {
        Debug.Log("OnHitItem"); 
        valid = false;
        // Stopと使うと音がぶつ切りになる場合があるため、音量をフェードアウトさせて対応
        //audio.Stop();

        // 子においておいたパーティクルのエフェクトを開始
        ParticleSystem particleSystem = gameObject.GetComponentInChildren<particlesystem>();
        if (particleSystem) {
            particleSystem.Play();
            Debug.Log("Particle Start");
        }

        // フェードアウトスタート
        StartCoroutine("Fadeout", 1.0f);
        Debug.Log("OnHitItem End");
    }

    IEnumerator Fadeout( float duration )
    {
        float currentTime = 0.0f;
        float waitTime = 0.02f;
        float firstVol = audio.volume;
        while (duration > currentTime)
        {
            currentTime += Time.fixedDeltaTime;
            audio.volume = Mathf.Clamp01(firstVol * (duration - currentTime) / duration);
            Debug.Log("Step:" + audio.volume);
            yield return new WaitForSeconds(waitTime);
        }

        // エフェクトが完全に終了していたらオブジェクト破棄
        ParticleSystem particleSystem = gameObject.GetComponentInChildren<particlesystem>();
        while (particleSystem.isPlaying)
        {
            yield return new WaitForSeconds(waitTime);
        }
        Destroy( gameObject );
        Debug.Log("Destory");
    }

    // (以下略

まあ、こんな感じかなー。
アイテムに接触時に、外からOnHitItemが呼ばれることを想定してる。

呼ばれると同時に、接触したことを知らせるパーティクル表現を入れつつ、音をコルーチンでフェードアウトする。
さらに、一応パーティクルによるエフェクトが終了していることを確認してからDestory

ただし、コルーチン使う場合は、StartCoroutine直後の

 
        Debug.Log("OnHitItem End");

も即実行されてしまうので注意。つまり、

OnHitItem
Particle Start
Step: xx
OnHitItem End
Step: xx
Step: xx
...
Destory

こんな感じの実行順になる。はず。





追記:
こうしたほうが楽じゃね?こういうときに、Mathf.Lerpとか使うべきだよね。
 
        while (duration > currentTime)
        {
            //audio.volume = Mathf.Clamp01(firstVol * (duration - currentTime) / duration);
            audio.volume = Mathf.Lerp( firstVol, 0.0f, currentTime/duration );
            Debug.Log("Step:" + audio.volume);
            yield return new WaitForSeconds(waitTime);
            currentTime += waitTime;
        }

0 件のコメント: