#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);
и в первый раз экземпляр будет создан по требованию.