首页 > 解决方案 > 如何在加载时淡出和破坏音频

问题描述

我有一个基本脚本,允许音乐从场景 2 继续播放到场景 6,但我大部分时间都在尝试让它在音频开始淡出然后在场景 6 被破坏,然后加载到场景 7。

我在这里、google、youtube 甚至 Unity 论坛上进行了搜索,但没有任何效果,因为我在搜索中得到的只是如何让音乐继续播放

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

public class Music : MonoBehaviour
{
    // Start is called before the first frame update

    public GameObject theManager;
    public AudioSource music;
    public string loadLevel;
    public float fadeOutTime = 3f;
    bool fading;
    float fadePerSec;

    void Awake()
    {

        DontDestroyOnLoad(theManager);
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    void OnDestroy()
    {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }

    void Update()
    {
        if (fading)
        {
            music.volume = Mathf.MoveTowards(
            music.volume, 0, fadePerSec * Time.deltaTime);
        }
    }
    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        if ((scene.buildIndex != 2) && (scene.buildIndex != 3) && (scene.buildIndex != 4) && (scene.buildIndex != 5) && (scene.buildIndex != 6))
        {
            fading = true;
            fadePerSec = music.volume / fadeOutTime;
            Destroy(theManager, fadeOutTime);
        }

    }
}

这是我的项目的2个屏幕截图

项目布局

在此处输入图像描述

ScriptManager 的检查员

在此处输入图像描述

任何帮助表示赞赏并提前感谢

标签: c#visual-studiounity3daudio

解决方案


  1. 主要问题:附加此脚本的游戏对象被破坏

    当您切换场景时,附加了此脚本的ScriptManagerGameObject 将被销毁!因此可能根本就不会被调用。OnSceneLoaded

  2. 然后我不会使用该字段public GameObject theManager;......您已经拥有该字段public AudioSource music;,所以我宁愿music.gameObject在需要GameObject参考时使用。只是为了避免错误。

  3. 最后,我不会只为一次性事件使用不断Update检查bool标志的方法。我建议宁愿使用Coroutine

所以像

public class Music : MonoBehaviour
{
    public AudioSource music;
    public string loadLevel;
    public float fadeOutTime = 3f;

    private static Music _instance;

    void Awake()
    {
        DontDestroyOnLoad(music.gameObject);

        // If necessary use a singleton pattern to make sure this exists only once
        if(_instance)
        {
            Destroy(gameObject);
            return;
        }

        _instance = this;

        // Also don't destroy yourself!
        DontDestroyOnLoad(gameObject);

        // Just to be sure before adding a callback you should always remove it
        // This is valid even if it wasn't added yet
        // but it makes sure it is only added exactly once
        SceneManager.sceneLoaded -= OnSceneLoaded;
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    void OnDestroy()
    {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }

    private IEnumerator FadeOutAndDestroy()
    {
        var fadePerSec = music.volume / fadeOutTime;
        while(music.volume > 0)
        {
            music.volume = Mathf.MoveTowards(music.volume, 0, fadePerSec * Time.deltaTime);
            
            // yield says: Interupt the routine here, render this frame
            // and continue from here in the next frame
            // In other words: Coroutines are like small temporary Update methods
            yield return null;
        }

        // Now the volume is 0
        Destroy(music.gameObject);

        // and since no longer needed also destroy this object
        Destroy(gameObject);
    }

    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        if (scene.buildIndex != 7) return;
        
        StartCoroutine(FadeOutAndDestroy());
    }
}

推荐阅读