web-dev-qa-db-ja.com

Unityシングルトンマネージャークラス

Unityで、これらの値をプルするすべてのクラスに同じ定数値を吐く静的変数を持つグローバルクラスとしてどこからでもアクセスできるシングルトンゲームマネージャーを作成する良い方法は何ですか?そしてそれをUnityに実装する方法は何でしょうか?ゲームオブジェクトにアタッチする必要がありますか?視覚的にシーン内に存在せずに、フォルダ内に存在することはできますか?

33
DeviArt

いつものように:状況によって異なります。私は両方の種類のシングルトン、GameObjectに接続されたコンポーネント、およびMonoBehaviourから派生していないスタンドアロンクラスを使用しています。 IMO全体的な問題は、インスタンスがシーン、ゲームオブジェクトのライフサイクルにどのようにバインドされるかということです。また、他のMonoBehaviourオブジェクトを特に参照するコンポーネントを使用する方が簡単で安全であることを忘れないでください。

  1. 呼び出されたときに永続化レイヤーから設定をロードする必要がある構成クラスなど、いくつかの値を提供するだけでよいクラスがあります。これらのクラスは単純なシングルトンとして設計します。
  2. 一方、一部のオブジェクトは、シーンがいつ開始されるかを知る必要があります。つまり、Startが呼び出されるか、Updateまたは他のメソッドでアクションを実行する必要があります。次に、それらをコンポーネントとして実装し、新しいシーンのロード後も存続するゲームオブジェクトにアタッチします。

私は2つの部分を持つコンポーネントベースのシングルトン(タイプ2)を設計しました:GameObjectと呼ばれる永続的なMainはすべてのコンポーネントを保持し、MainComponentManagerと呼ばれるフラットシングルトン(タイプ1)を管理用にそれ。いくつかのデモコード:

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;
        }
    }
45
Kay

Unityに慣れていないエンジニアは、多くの場合、それに気付かない

eCSシステムに「シングルトン」を含めることはできません。

無意味です。

Unityにあるのは、XYZの位置にあるGameObjectsだけです。コンポーネントを取り付けることができます。

.... PhotoshopまたはMicrosoft Wordで「シングルトン」または「継承」を実現しようとするようなものです。

Photoshopファイル-XY位置のピクセル
テキストエディターファイル-X位置の文字
Unityファイル-XYZ位置のゲームオブジェクト

それは「ただそれだけ」です。

もちろん、とにかく、すべてのUnityプロジェクトにはプリロードシーンが必要です。

信じられないほど簡単なハウツー: https://stackoverflow.com/a/35891919/294884

それはとても簡単で、問題ではありません。

Unityに「組み込みのプリロードシーン」が含まれると(つまり、ワンクリックでシーンを作成できるようにするため)、これについては最終的に再び議論されることはありません。

(注A-Unityのコンポーネントのコンパイルに使用する一部の言語にはもちろんOOの概念があります。Unity自体はOOとはまったく関係がありません。)

(注B-Unityの初期の頃は、「オンザフライでゲームオブジェクトを作成し、それを一意に保ち、それにアタッチする」というコードを作成しようとする試みが見られます(奇妙なことは別として、FWIWだけでは理論的に一意性を保証することはできません(実際にはフレーム内でさえも不可能です)。繰り返しますが、それは些細な問題ではないため、完全にモットーではありません。 )

5
Fattie

シングルトンオブジェクトを簡単に作成できるシングルトンクラスを作成しました。これはMonoBehaviourスクリプトなので、コルーチンを使用できます。これは nity Wiki記事 に基づいており、後でプレハブから作成するオプションを追加します。

そのため、シングルトンコードを記述する必要はありません。 this Singleton.cs Base Class をダウンロードしてプロジェクトに追加し、それを拡張するシングルトンを作成します。

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/

1
Bivis

このクラスがグローバル変数へのアクセスのみを目的としている場合は、これにシングルトンパターンを実際に必要としたり、GameObjectを使用したりする必要はありません。

パブリック静的メンバーを持つクラスを作成するだけです。

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

他のソリューションは問題ありませんが、必要なのが変数へのグローバルアクセスだけである場合は、やりすぎです。

1
LITM

クラスごとに1つのシングルトンを作成する代わりに。シングルトンのジェネリッククラスを作成することをお勧めします。私はこの方法を使用して私の人生をとても簡単にしています。

詳細については こちら をご覧ください

または

UnityでUnity C#クラスを作成し、次のコードを使用します

/// <summary>
/// Inherit from this base class to create a singleton.
/// e.g. public class MyClassName : Singleton<MyClassName> {}
/// </summary>
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    // Check to see if we're about to be destroyed.
    private static bool m_ShuttingDown = false;
    private static object m_Lock = new object();
    private static T m_Instance;

    /// <summary>
    /// Access singleton instance through this propriety.
    /// </summary>
    public static T Instance
    {
        get
        {
            if (m_ShuttingDown)
            {
                Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
                    "' already destroyed. Returning null.");
                return null;
            }

            lock (m_Lock)
            {
                if (m_Instance == null)
                {
                    // Search for existing instance.
                    m_Instance = (T)FindObjectOfType(typeof(T));

                    // Create new instance if one doesn't already exist.
                    if (m_Instance == null)
                    {
                        // Need to create a new GameObject to attach the singleton to.
                        var singletonObject = new GameObject();
                        m_Instance = singletonObject.AddComponent<T>();
                        singletonObject.name = typeof(T).ToString() + " (Singleton)";

                        // Make instance persistent.
                        DontDestroyOnLoad(singletonObject);
                    }
                }

                return m_Instance;
         }
      }
  }

  private void OnApplicationQuit()
  {
     m_ShuttingDown = true;
  }

  private void OnDestroy()
  {
    m_ShuttingDown = true;
  }
}

0

これは私が作成したセットアップです。

最初にこのスクリプトを作成します。

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;       
}
0
rygo6

Unityチュートリアルから取った簡単なコードを次に示します。よりよく理解するために link を開いてください

using System.Collections.Generic;       //Allows us to use Lists. 

public class GameManager : MonoBehaviour
{

    public static GameManager instance = null;              //Static instance of GameManager which allows it to be accessed by any other script.
    private BoardManager boardScript;                       //Store a reference to our BoardManager which will set up the level.
    private int level = 3;                                  //Current level number, expressed in game as "Day 1".

    //Awake is always called before any Start functions
    void Awake()
    {
        //Check if instance already exists
        if (instance == null)

            //if not, set instance to this
            instance = this;

        //If instance already exists and it's not this:
        else if (instance != this)

            //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
            Destroy(gameObject);    

        //Sets this to not be destroyed when reloading scene
        DontDestroyOnLoad(gameObject);

        //Get a component reference to the attached BoardManager script
        boardScript = GetComponent<BoardManager>();

        //Call the InitGame function to initialize the first level 
        InitGame();
    }

    //Initializes the game for each level.
    void InitGame()
    {
        //Call the SetupScene function of the BoardManager script, pass it current level number.
        boardScript.SetupScene(level);

    }



    //Update is called every frame.
    void Update()
    {

    }
0
Hassaan sohail