Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 脚本的执行顺序-唤醒和合一_C#_Unity3d - Fatal编程技术网

C# 脚本的执行顺序-唤醒和合一

C# 脚本的执行顺序-唤醒和合一,c#,unity3d,C#,Unity3d,我面临着与脚本执行顺序相关的问题,尽管我是一名经验丰富的Unity开发人员,但这一点我已经记不住了。所以我想要一个关于这个的解释 这是我的menucontoler脚本代码: public class MainMenuController : MonoBehaviour { [SerializeField] Text bestScoreText; [SerializeField] Toggle soundToggle; private void OnEnable() { In

我面临着与脚本执行顺序相关的问题,尽管我是一名经验丰富的Unity开发人员,但这一点我已经记不住了。所以我想要一个关于这个的解释

这是我的menucontoler脚本代码:

public class MainMenuController : MonoBehaviour
{  
 [SerializeField] Text bestScoreText;
 [SerializeField] Toggle soundToggle;
 private void OnEnable()
 {
     Init();
 }
 private void Init()
 {
     if (GameManager.Instance == null)
         Debug.Log("null game manager");
     GameManager.Instance.PlayerLives = 0;
     bestScoreText.text = DataStorage.RetrieveBestScore().ToString("D5");
     SoundManager.Instance.IsSoundEnabled = DataStorage.RetrieveSoundStatus() == GameConstants.STAT_ON ? true : false;
     soundToggle.isOn = !SoundManager.Instance.IsSoundEnabled;
 }
}
public class GameManager : MonoBehaviour
{
   private static GameManager instance;
   //
   private int levelIndex;
   private int gameScore;   
   private int playerLives;

   void Awake()
   {
      instance = this;
   }

   public static GameManager Instance
   {
      get
      {
          return instance;
      }
   }
}
这是我的GameManager脚本代码:

public class MainMenuController : MonoBehaviour
{  
 [SerializeField] Text bestScoreText;
 [SerializeField] Toggle soundToggle;
 private void OnEnable()
 {
     Init();
 }
 private void Init()
 {
     if (GameManager.Instance == null)
         Debug.Log("null game manager");
     GameManager.Instance.PlayerLives = 0;
     bestScoreText.text = DataStorage.RetrieveBestScore().ToString("D5");
     SoundManager.Instance.IsSoundEnabled = DataStorage.RetrieveSoundStatus() == GameConstants.STAT_ON ? true : false;
     soundToggle.isOn = !SoundManager.Instance.IsSoundEnabled;
 }
}
public class GameManager : MonoBehaviour
{
   private static GameManager instance;
   //
   private int levelIndex;
   private int gameScore;   
   private int playerLives;

   void Awake()
   {
      instance = this;
   }

   public static GameManager Instance
   {
      get
      {
          return instance;
      }
   }
}
我在执行期间收到NullReferenceException:

现在我无法理解-如何在其他脚本的唤醒方法之前执行OnEnable方法

由于这个原因,我得到一个空引用异常。据我所知,所有脚本唤醒方法首先执行,然后在对项目的所有脚本进行一次布尔调用之后执行


请给我解释一下这一点,这样我这边的困惑就可以解决了。

你没有正确地实现单例模式,你应该考虑比赛条件,特别是当涉及unity的事件函数时。 正确的单例行为,如果实例不存在,则创建实例,还允许您使用预定义字段生成预定义的单例,也更容易实现其他单例而无需重复代码(样板):

使用UnityEngine;
公共类单态模式:单态行为,ISingleton其中T:单态行为
{
#区域静态场
私有静态T实例=null;
#端区
#区域字段
[序列化字段]
受保护的bool destroyOnLoad=真;
私有转换m_Transform=null;
私有游戏对象m_GameObject=null;
private bool m_isInitialized=假;
#端区
#区域静态特性
公共静态bool实例
{
获取{返回实例!=null;}
}
/// 
///获取将持续到应用程序退出的单例实例。
/// 
///实例。
公共静态T实例
{
得到
{
if(实例==null)
{
instance=FindObjectOfType();
//我们需要创建新的实例
if(实例==null)
{
var _singletonType=typeof(T);
//如果该类存在预置,则首先在资源中搜索
字符串_singletoname=_singletonType.Name;
GameObject _singletonPrefab=Resources.Load(“Singleton/”+_singletonName,typeof(GameObject))作为GameObject;
如果(_singletonprefact!=null)
{
Log(string.Format(“[SingletonPattern]使用预置创建Singleton{0}”,_singletonName));
instance=(实例化(_singletonPrefab)为GameObject).GetComponent();
}
其他的
{
实例=新游戏对象().AddComponent();
}
//更新名称
instance.name=_singletoname;
}
}
返回实例;
}
专用设备
{
实例=值;
}
}
#端区
#区域属性
公共转换缓存转换
{
得到
{
if(m_transform==null)
{
m_变换=变换;
}
返回m_变换;
}
}
公共游戏对象CachedGameObject
{
得到
{
如果(m_gameObject==null)
{
m_gameObject=游戏对象;
}
返回m_游戏对象;
}
}
#端区
#区域单环回
受保护的虚拟void Awake()
{
if(instance!=null&&instance!=this)
{
摧毁(游戏对象);
}
如果(!m_已初始化)
{
Init();
}
}
受保护的虚拟void Start()
{ }
受保护的虚拟无效重置()
{
//重置属性
m_gameObject=null;
m_变换=null;
m_初始=错误;
}
受保护的虚拟void OnEnable()
{ }
受保护的虚拟无效OnDisable()
{ }
受保护的虚拟空OnDestroy()
{
}
Application Quit()上受保护的虚拟void
{
if(实例==此)
{
实例=null;
}
}
#端区
#区域方法
受保护的虚拟void Init()
{
//设置为已初始化
m_i初始=真;
//以防万一,进行处理以使只有一个实例处于活动状态
if(实例==null)
{
实例=此为T;
}
//正在销毁此类类型的冗余副本
else if(实例!=此)
{
销毁(CachedGameObject);
返回;
}
//将其设置为持久对象
如果(!destroyOnLoad)
{
DontDestroyOnLoad(CachedGameObject);
}
}
公开作废
{
//破坏
销毁(CachedGameObject);
}
#端区
}
创建GameManager单例现在很容易:

public class GameManager : SingletonPattern<GameManager>
{

}
公共类游戏管理器:单音模式
{
}
现在,如果您随时访问
GameManager.Instance
,它将创建尚未创建的实例,从而避免了在unity的事件函数中维护竞争条件的麻烦


如果您有一个
GameManager
或任何要在编辑器中预设属性的单例,而在游戏模式下创建的实例将不具有这些属性,则创建一个实例预置,并将其放置在名为singleton的文件夹下名为Resources的文件夹中,因为系统首先检查是否存在单例的预定义预置并生成它,然后返回到创建新的游戏对象并将脚本附加到它。

在您显示的代码中,您尝试获取名为
GameManager
的某个实例,但后来下面的脚本被命名为
SoundManager
soundManagerObj.GetComponent<SoundManager>().IsSoundEnabled();
public class GameManager : MonoBehaviour
{
   public static GameManager instance = null;

   // Change this to public to access from the other script
   public int levelIndex;
   public int gameScore;   
   public int playerLives;

   void Awake()
   {
        if(instance == null)
            instance = this;
        else if (instance != this)
            Destroy(gameObject);

        // To keep this objectr from one scene to the next one      
        DontDestryOnLoad(gameObject)
   }
}
public class MainMenuController : MonoBehaviour
{  
 [SerializeField] Text bestScoreText;
 [SerializeField] Toggle soundToggle;
 public GameObject gameManager;

 private void OnEnable()
 {
     Init();
 }
 private void Init()
 {
    if (GameManager.instance == null){
        Debug.Log("null game manager");
        Instantiate(gameManager);
    } 
    gameManager.playerLives = 0;
    //...
 }
}