在Unity中,有什么方法可以创建一个单独的游戏管理器,可以作为全局类在任何地方访问,静态变量会将相同的常量值吐出到每个提取这些值的类中?在Unity中实现它的方法是什么?我必须将它附加到GameObject吗?可以只是在文件夹中,而不是在视觉上在场景中吗?
答案 0 :(得分:44)
总是如此:它取决于。我使用两种类型的单例,附加到GameObject
的组件和不是MonoBehaviour
派生的独立类。 IMO的整体问题是如何将实例绑定到场景,游戏对象的生命周期......并且不要忘记有时候让组件特别引用其他MonoBehaviour
对象更方便更安全。
Start
或必须在Update
或其他方法中执行操作。然后我将它们作为组件实现,并将它们附加到游戏对象中,该游戏对象可以在加载新场景后继续存在。我设计了基于组件的单例(类型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;
}
}
答案 1 :(得分:4)
刚接触Unity的工程师通常不会注意到
没有意义。
Unity中的所有内容都是GameObjects,位于XYZ位置。他们可以附加组件。
这就像试图拥有一个单身&#34;或者&#34;继承&#34;在.... Photoshop或Microsoft Word。
Photoshop 文件 - XY位置的像素
文本编辑器文件 - X位置的字母
Unity 文件 - 位于XYZ位置的GameObjects
就是那么简单&#34;。
难以置信的简单方法:https://stackoverflow.com/a/35891919/294884
这很简单,这不是问题。
一旦Unity包含一个&#34;内置的预加载场景&#34; (即,为了节省你一次点击创建一个),这将永远不会再讨论。
(注意A - 用于编译Unity的组件的一些语言当然具有OO概念; Unity本身根本没有与OO的连接。)
(注意B - 在团结的早期,你会看到尝试制作代码&#34;动态创建游戏对象 - 并保持其独特性 - 并将其自身附加到其中#&# 34; 。除了奇怪之外,只是FWIW理论上它不可能确保唯一性(实际上甚至不在一个框架内)。再一次,它完全没有实际意义,因为它是#sa;简单的非问题,在Unity中,一般行为只是进入预加载场景。)
答案 2 :(得分:1)
如果这个类只是用于访问全局变量,那么你真的不需要单例模式,或者使用GameObject。
只需创建一个包含公共静态成员的类。
public class Globals
{
public static int mStatic1 = 0;
public static float mStatic2 = 0.0f;
// ....etc
}
其他解决方案很好,但如果您只需要对变量进行全局访问,那就太过分了。
答案 3 :(得分:1)
我编写了一个单例类,可以轻松创建单例对象。它是MonoBehaviour脚本,因此您可以使用Coroutines。它基于这个Unity Wiki article,我将添加选项,以便稍后从Prefab创建它。
所以你不需要编写Singleton代码。只需下载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类是一个单例,你可以通过Instance调用它:
MySingleton.Instance.globalVar = "A";
Debug.Log ("globalVar: " + MySingleton.Instance.globalVar);
以下是完整的教程:http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/
答案 4 :(得分: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;
}
答案 5 :(得分:0)
不是为每个类创建一个单例。我建议您为单例创建一个通用类。我习惯遵循这种方法,这使我的生活非常轻松。
有关更多详细信息,请访问here
或
统一创建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;
}
}
答案 6 :(得分:0)
这是来自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()
{
}
答案 7 :(得分:0)
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
public static T instance { get; private set; }
protected virtual void Awake() {
if (instance == null)
{
instance = (T)this;
DontDestroyOnLoad(gameObject);
OnInit();
}
else if (instance != this)
{
Destroy(gameObject);
}
}
protected virtual void OnInit()
{
}
}
游戏管理:
class GameManager : Singleton<GameManager> {
}
答案 8 :(得分:-1)
一种方法是制作一个场景,只是为了初始化你的游戏管理器:
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;