Подтвердить что ты не робот

Классы менеджеров Unity singleton

В Unity, что является хорошим способом создания однопользовательского игрового менеджера, к которому можно получить доступ во всем мире как к глобальному классу со статическими переменными, которые будут выплевывать одни и те же константные значения для каждого класса, который извлекает эти значения? И каков был бы способ реализации в Unity? Нужно ли прикреплять его к GameObject? Может ли он быть в папке без визуального отображения?

4b9b3361

Ответ 1

Как всегда: это зависит. Я использую одноэлементы обоих видов, компоненты, прикрепленные к GameObject, и автономные классы, не полученные из MonoBehaviour. IMO - общий вопрос: каким образом экземпляры привязаны к жизненному циклу сцен, игровых объектов... И не забывайте, что иногда удобнее иметь компонент, особенно ссылающийся на другие объекты MonoBehaviour, проще и безопаснее.

  • Существуют классы, которые просто должны предоставлять некоторые значения, например, например, класс конфигурации, который должен загружать настройки из уровня персистентности при вызове. Я разрабатываю эти классы как простые синглтоны.
  • С другой стороны, некоторые объекты должны знать, когда сцена запущена, т.е. Start вызывается или должен выполнять действия в Update или других методах. Затем я реализую их как компонент и присоединяю их к игровому объекту, который выживает при загрузке новых сцен.

Я разработал компонентные синглтоны (тип 2) с двумя частями: постоянный GameObject, называемый Main, который содержит все компоненты и плоский синглтон (тип 1), называемый MainComponentManager для управления им. Некоторые демо-коды:

public class MainComponentManger {
    private static MainComponentManger instance;
    public static void CreateInstance () {
        if (instance == null) {
            instance = new MainComponentManger ();
            GameObject go = GameObject.Find ("Main");
            if (go == null) {
                go = new GameObject ("Main");
                instance.main = go;
                // important: make game object persistent:
                Object.DontDestroyOnLoad (go);
            }
            // trigger instantiation of other singletons
            Component c = MenuManager.SharedInstance;
            // ...
        }
    }

    GameObject main;

    public static MainComponentManger SharedInstance {
        get {
            if (instance == null) {
                CreateInstance ();
            }
            return instance;
        }
    }

    public static T AddMainComponent <T> () where T : UnityEngine.Component {
        T t = SharedInstance.main.GetComponent<T> ();
        if (t != null) {
            return t;
        }
        return SharedInstance.main.AddComponent <T> ();
    }

Теперь другие синглтоны, которые хотят зарегистрироваться как компонент Main, выглядят следующим образом:

public class AudioManager : MonoBehaviour {
    private static AudioManager instance = null;
    public static AudioManager SharedInstance {
        get {
            if (instance == null) {
                instance = MainComponentManger.AddMainComponent<AudioManager> ();
            }
            return instance;
        }
    }

Ответ 2

Инженеры, которые новичок в Unity, часто не замечают, что

у вас не может быть "singleton" в системе ECS.

Это бессмысленно.

Все, что у вас есть в Unity, - это GameObjects, at, XYZ. Они могут иметь компоненты.

Это будет похоже на попытку "одиночного" или "наследования" в... Photoshop или Microsoft Word.

Photoshop - пиксели в положениях XY
Текстовый редактор - буквы в положениях X

Unity - GameObjects на позициях XYZ

Это просто так просто.

Конечно, в любом проекте Unity вам обязательно нужно иметь предварительную сцену.

Невероятно простой способ: fooobar.com/questions/182020/...

Это так просто, это не проблема.

Когда Unity включает в себя "встроенную сцену предварительной загрузки" (то есть, чтобы сохранить один щелчок при создании одного), это, наконец, никогда не будет обсуждаться снова.

(Примечание. A - некоторые языки, которые вы используете для компиляции компонентов для Unity, конечно, имеют концепции OO; сам Unity не имеет никакого отношения к OO вообще.)

(Примечание B - в первые дни Unity вы увидите попытки создать код, который "создает игровой объект" на лету ", и сохраняет его уникальным - и присоединяется к нему". Помимо причудливого, просто FWIW теоретически не представляется возможным обеспечить уникальность (на самом деле даже не в пределах кадра). Опять же, это просто совершенно спорно потому что это тривиальное не проблема, в единстве общего поведения просто пойти на преднагрузки сцене.)

Ответ 3

Если этот класс предназначен только для доступа к глобальным переменным, вам не нужен шаблон singleton для этого или использовать GameObject.

Просто создайте класс с общедоступными статическими членами.

public class Globals
{
    public static int mStatic1 = 0;
    public static float mStatic2 = 0.0f;
    // ....etc
}

Другие решения прекрасны, но излишнее, если вам нужен глобальный доступ к переменным.

Ответ 4

Я написал одноэлементный класс, который упрощает создание одноэлементных объектов. Это MonoBehaviour script, поэтому вы можете использовать Coroutines. Он основан на этой статье Wiki Unity, и я добавлю вариант для ее создания из Prefab позже.

Поэтому вам не нужно писать коды Singleton. Просто скачайте этот базовый класс Singleton.cs, добавьте его в свой проект и создайте свой синглтон, расширяющий его:

public class MySingleton : Singleton<MySingleton> {
  protected MySingleton () {} // Protect the constructor!

  public string globalVar;

  void Awake () {
      Debug.Log("Awoke Singleton Instance: " + gameObject.GetInstanceID());
  }
}

Теперь ваш класс MySingleton является синглом, и вы можете вызвать его по экземпляру:

MySingleton.Instance.globalVar = "A";
Debug.Log ("globalVar: " + MySingleton.Instance.globalVar);

Вот полный учебник: http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/

Ответ 5

Это настройка, которую я создал.

Сначала создайте этот script:

MonoBehaviourUtility.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;

static public class MonoBehaviourUtility 
{

    static public T GetManager<T>( ref T manager ) where T : MonoBehaviour
    {
        if (manager == null)
        {
            manager = (T)GameObject.FindObjectOfType( typeof( T ) );
            if (manager == null)
            {
                GameObject gameObject = new GameObject( typeof( T ).ToString() );
                manager = (T)gameObject.AddComponent( typeof( T ) );
            }
        }
        return manager;
    }

}

Затем в любом классе вы хотите быть одиночным:

public class ExampleManager : MonoBehaviour 
{   
    static public ExampleManager sharedManager 
    {
        get 
        {
            return MonoBehaviourUtility.GetManager<ExampleManager>( ref _sharedManager );
        }
    }   
    static private ExampleManager _sharedManager;       
}

Ответ 6

Один из способов сделать это - создать сцену просто для инициализации игрового менеджера, например так:

public class GameManager : MonoBehaviour {
    static GameManager instance;

    //other codes

    void Awake() {
        DontDestroyOnLoad(transform.gameObject);
        instance = this;
    }

    //other codes
}

Вот и все, что вам нужно сделать. А затем сразу же после инициализации игрового менеджера загрузите следующую сцену и больше никогда не возвращайтесь на эту сцену.

Посмотрите этот учебник: https://youtu.be/64uOVmQ5R1k?list=WL

Изменить: Изменен GameManager static instance; в static GameManager instance;