Синглтон Unity Audio Для Разных Сцен

#c# #unity3d #audio

Вопрос:

Итак, у меня есть базовый синглтон, который обрабатывает аудио в разных сценах.

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

Допустим, этот звуковой синглтон помещен в сцену 1, если я переключусь на сцену 2, он, кажется, работает. Единственная проблема в том, что если я начну со сцены 2, звук больше не будет работать. Я предполагаю, что это связано с тем, что синглтон создается только в сцене 1, поэтому в сцене 2 нет ссылки на синглтон. Я попытался сделать свой синглтон сборным, чтобы они были в каждой из моих сцен, что решает мою проблему отсутствия существующего синглтона в Scene2, но если я переключу сцены, он перестанет работать.

Есть ли способ, чтобы у меня был звуковой синглтон, который работает, даже если я не начинаю со сцены 1? Я думаю, что это не обязательно должен быть синглтон, но это то, что у меня есть до сих пор. Я новичок в unity, поэтому просматривал только базовые учебные пособия по Unity.

Редактировать: Причина, по которой я хочу начать со сцены 2, заключается в том, что я хочу протестировать определенные сцены.

Ответ №1:

Вы можете использовать мой шаблон Синглтона ниже. При объявлении вашего класса используйте « public class MyClass : Singletonlt;MyClassgt; «. Что вам нужно сделать, так это создать сцену, подобную начальной загрузке или запуску, и именно здесь вы размещаете свои одноэлементные игровые объекты. Они должны использовать какой — то стандартный одноэлементный код, очень похожий на то, что опубликовал Деруго, за исключением того, что я не стал бы создавать экземпляр компонента, если он не найден-вместо этого он должен показывать ошибку в журнале. Обычно синглеты моего менеджера имеют полезные свойства и массивы на них, которые задаются в инспекторе, поэтому простое создание такого компонента потеряло бы всю эту функциональность. Как только у вас будет сцена начальной загрузки или запуска, вы переместите ее в начало списка сцен загрузки в списке сцен сборки. У вас также должен быть другой одноэлементный игровой объект в сцене запуска, который затем загружает сцену 1 или сцену 2 или все, что вам нужно. Я создаю синглтон под названием GameManager, который имеет конечный автомат и определяет, какие сцены загружать, и знает, где мы находимся. Довольно часто он загружается в игровой сцене или нескольких сценах пользовательского интерфейса, и вы можете загружать их аддитивно. Таким образом, вы разбиваете свою игру и пользовательский интерфейс на несколько сцен для организации. Также важно для совместной работы при работе в команде иметь несколько сцен, так как они, как правило, не легко сливаются. Довольно часто людям нужна вступительная сцена, поэтому менеджер игр будет иметь разные состояния и перемещаться между ними, загружая разные сцены. Однако не вызывайте одноэлементный SceneManager, у Unity уже есть класс с таким именем.

 using UnityEngine;  public class Singletonlt;Tgt; : 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.GetComponentlt;Tgt;();  }   static bool doneOnce;   /// lt;summarygt;  /// Returns the instance of this singleton.  /// lt;/summarygt;  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 amp;amp; !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; }  

Ответ №2:

Вы, вероятно, могли бы использовать ленивый экземпляр, например,

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

так что теперь вы можете использовать, например

 CentralAudio.Instance.Source.PlayOneShot(someAudioClip);  

и в первый раз экземпляр будет создан по требованию.