【问题标题】:Unity Audio Singleton Across Scenes跨场景的 Unity Audio Singleton
【发布时间】:2021-11-26 10:05:15
【问题描述】:

所以我有一个基本的单例来处理跨场景的音频。

    private void Awake() {
        if (Instance == null) {
            Instance = this;
        } else {
            Destroy(gameObject);
            return;
        }

        DontDestroyOnLoad(gameObject);
    }

假设这个音频单例放置在 Scene1 中,如果我切换到 Scene2,它似乎可以工作。唯一的问题是,如果我从 Scene2 开始,音频将不再有效。我猜这是因为单例仅在 Scene1 中创建,因此在 Scene2 中没有单例引用。我已经尝试将我的单例制作成一个预制件,这样我就可以在我的每个场景中使用它们,这解决了我在 Scene2 中没有现有单例的问题,但是如果我切换场景,它就会停止工作。

有没有一种方法可以让我的音频单例在我不从 Scene1 开始时也能正常工作?我想它不一定是单例,但这就是我到目前为止所拥有的。我是 Unity 新手,所以我一直在查找基本的 Unity 教程。

编辑:我想从 Scene2 开始是因为我想测试特定的场景。

【问题讨论】:

    标签: c# unity3d audio


    【解决方案1】:

    您可能会使用惰性实例化,例如

    [RequireComponent(typeof(AudioSource))]
    public class CentralAudio : MonoBehaviour
    {
        [SerializeField] private AudioSource _source;
    
        public AudioSource Source => _source;
    
        private static CentralAudio _instance;
        
        public static CentralAudio Instance
        {
            get
            {
                // instance already exists -> return it right away
                if(_instance) return _instance;
    
                // look in the scene for one
                _instance = FindObjectOfType<CentralAudio>();
    
                // found one -> return it
                if(_instance) return _instance;
    
                // otherwise create a new one from scratch
                _instance = new GameObject(nameof(CentralAudio), typeof(AudioSource)).AddComponent<CentralAudio>();
            }
        }
        
        private void Awake()
        {
            // ensure singleton
            if(_instance && _instance != this)
            {
                Destroy(gameObject);
                return;
            }
    
            _instance = this;
    
            // lazy initialization of AudioSource component
            if(!_source) 
            {
                if(!TryGetComponent<AudioSource>(out _source))
                {
                    _source = gameObject.AddComponent<AudioSource>();
                }
            }
    
            DontDestroyOnLoad(gameObject);
        }
    }
    

    所以现在你可以使用例如

    CentralAudio.Instance.Source.PlayOneShot(someAudioClip);
    

    第一次实例将按需创建。

    【讨论】:

      【解决方案2】:

      您可以使用下面的我的单例模板。声明你的班级时使用“public class MyClass : Singleton&lt;MyClass&gt;”。你需要做的是有一个像 Bootstrap 或 Startup 这样的场景,这是你放置单例游戏对象的地方。他们应该使用一些与 derHugo 发布的非常相似的标准单例代码,但如果找不到,我不会实例化该组件 - 它应该在日志中显示错误。通常我的管理器单例具有在检查器中设置的有用属性和数组,因此仅创建这样的组件将失去所有功能。 拥有 Bootstrap 或 Startup 场景后,将其移动到构建场景列表中加载顺序的顶部。您应该在 Startup 场景中也有另一个单例游戏对象,然后加载 Scene1 或 Scene2 或您需要的任何内容。我制作了一个名为 GameManager 的单例,它有一个状态机并确定要加载哪些场景并知道我们在哪里。 很多时候它会在一个 GameUI 场景或多个 UI 场景中加载,您可以添加加载它们。这样,您就可以将游戏和 UI 分解为多个场景以进行组织。在团队中工作时具有多个场景对于协作也很重要,因为它们往往不容易合并。很多时候人们想要一个 Intro 场景,所以 GameManager 将有不同的状态并在它们之间移动以加载不同的场景。不过不要调用单例 SceneManager,Unity 已经有一个以这种方式命名的类。

      using UnityEngine;
      
      public class Singleton<T> : MonoBehaviour where T: MonoBehaviour
      {
          protected virtual void Awake()
          {
              if (instance != null)
              {
                  Debug.LogError($"Duplicate Singleton: {name} of type {typeof(T)}, destroying self");
                  GameObject.DestroyImmediate(gameObject);
              }
              else
                  instance = gameObject.GetComponent<T>();
          }
      
          static bool doneOnce;
      
          /// <summary>
          /// Returns the instance of this singleton.
          /// </summary>
          public static T Instance
          {
              [System.Diagnostics.DebuggerStepThrough]
              get
              {
                  if (instance == null)
                  {
                      instance = (T)GameObject.FindObjectOfType(typeof(T)); // not really any point to doing this (it will fail), Awake would have happened but it's possible your code got here before Awake
      
                      if (instance == null && !doneOnce)
                      {
                          doneOnce = true;
                          Debug.LogError($"!!! An instance of type {typeof(T)} is needed in the scene, but there is none !!!");
                      }
                  }
      
                  return instance;
              }
          }
      
          private static T instance;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-10-19
        • 2019-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多