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