unity3D技术之使用单例模式SingletonWord下载.docx
- 文档编号:22036546
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:9
- 大小:18.53KB
unity3D技术之使用单例模式SingletonWord下载.docx
《unity3D技术之使用单例模式SingletonWord下载.docx》由会员分享,可在线阅读,更多相关《unity3D技术之使用单例模式SingletonWord下载.docx(9页珍藏版)》请在冰豆网上搜索。
{
privatestaticGameObjectm_Container=null;
privatestaticstringm_Name=“Singleton”;
privatestaticDictionary<
string,object>
m_SingletonMap=newDictionary<
();
privatestaticboolm_IsDestroying=false;
publicstaticboolIsDestroying
{
get{returnm_IsDestroying;
}
publicstaticboolIsCreatedInstance(stringName)
if(m_Container==null)
returnfalse;
}
if(m_SingletonMap!
=null&
&
m_SingletonMap.ContainsKey(Name))
returntrue;
returnfalse;
publicstaticobjectgetInstance(stringName)
if(m_Container==null)
Debug.Log(“CreateSingleton.”);
m_Container=newGameObject();
m_Container.name=m_Name;
m_Container.AddComponent(typeof(Singleton));
if(!
m_SingletonMap.ContainsKey(Name))
if(System.Type.GetType(Name)!
=null)
m_SingletonMap.Add(Name,m_Container.AddComponent(System.Type.GetType(Name)));
else
Debug.LogWarning(“SingletonTypeERROR!
(”+Name+“)”);
returnm_SingletonMap[Name];
}
publicvoidRemoveInstance(stringName)
if(m_Container!
=null&
m_SingletonMap.ContainsKey(Name))
UnityEngine.Object.Destroy((UnityEngine.Object)(m_SingletonMap[Name]));
m_SingletonMap.Remove(Name);
Debug.LogWarning(“SingletonREMOVE!
voidAwake()
Debug.Log(“AwakeSingleton.”);
DontDestroyOnLoad(gameObject);
voidStart()
Debug.Log(“StartSingleton.”);
voidUpdate()
voidOnApplicationQuit()
Debug.Log(“DestroySingleton”);
if(m_Container!
GameObject.Destroy(m_Container);
m_Container=null;
m_IsDestroying=true;
代码大部分都比较容易看懂,下面介绍几点注意的地方:
当我们在其他代码里需要访问某个单例时,只需调用getInstance函数即可,参数是需要访问的脚本的名字。
我们来看一下这个函数。
它首先判断所有单例所在的容器m_Container是否为空(实际上就是场景中是否存在一个Gameobject,上面捆绑了一个Singleton脚本),如果为空,它将自动创建一个对象,然后以“Singleton”命名,再捆绑Singleton脚本。
m_SingletonMap是负责维护所有单例的映射。
当第一次访问某个单例时,它会自动向m_Container上添加一个该单例类型的Component,并保存在单例映射中,再返回这个单例。
因此,我们可以看出,单例的创建完全都是自动的,你完全不需要考虑在哪里、在什么时候捆绑脚本,这是多么令人高兴得事情!
在Awake函数中,有一句代码DontDestroyOnLoad(gameObject);
,这是非常重要的,这句话意味着,当我们的场景发生变化时,单例模式将不受任何影响。
除此之外,我们还要注意到,这句话也必须放到Awake函数,而不能放到Start函数中,这是由两个函数的执行顺序决定的,如果反过来,便可能会造成访问单例不成功,下面的例子里会更详细的介绍;
在OnApplicationQuit函数中,我们将销毁单例模式。
最后一点很重要:
一定不要在OnDestroy函数中直接访问单例模式!
这样很有可能会造成单例无法销毁。
这是因为,当程序退出准备销毁单例模式时,我们在其他脚本的OnDestroy函数中再次请求访问它,这样将重新构造一个新的单例而不会被销毁(因为之前已经销毁过一次了)。
如果一定要访问的话,一定要先调用IsCreatedInstance,判断该单例是否存在。
--来自狗刨学习网
例子
下面,我们通过一个小例子来演示单例模式的使用。
首先,我们需要创建如上的Singleton脚本。
然后,再创建一个新的脚本SingletonSample.cs用于测试,其内容如下:
usingUnityEngine;
publicclassSingletonSample:
//Usethisforinitialization
voidStart(){
TestSingleton();
//Updateiscalledonceperframe
voidUpdate()
privatevoidTestSingleton()
LitJsonSamplelitjson=Singleton.getInstance(“LitJsonSample”)asLitJsonSample;
litjson.DisplayFamilyList();
//
voidOnDestroy(){
LitJsonSamplelitjson=Singleton.getInstance(“LitJsonSample”)asLitJsonSample;
litjson.DisplayFamilyList();
//
注意,为了方便,我使用了上一篇博文里使用的Litjson的代码,并做了少许修改。
下面是修改后的LitJsonSample.cs:
usingUnityEditor;
usingLitJson;
publicclassFamilyInfo{
publicstringname;
publicintage;
publicstringtellphone;
publicstringaddress;
publicclassFamilyList{
publicList<
FamilyInfo>
family_list;
publicclassLitJsonSample:
MonoBehaviour{
publicFamilyListm_FamilyList=null;
//Usethisforinitialization
voidAwake(){
ReloadFamilyData();
privatevoidReloadFamilyData()
//AssetDatabase.ImportAsset(“Localize/family.txt”);
UnityEngine.TextAssets=Resources.Load(“Localize/family”)asTextAsset;
stringtmp=s.text;
m_FamilyList=JsonMapper.ToObject<
FamilyList>
(tmp);
if(JsonMapper.HasInterpretError())
Debug.LogWarning(JsonMapper.GetInterpretError());
publicvoidDisplayFamilyList()
if(m_FamilyList==null)return;
foreach(FamilyInfoinfoinm_FamilyList.family_list)
Debug.Log(“Name:
”+info.name+”
Age:
”+info.age+”
Tel:
”+info.tellphone+”
Addr:
”+info.address);
voidUpdate(){
然后,将SingletonSample.cs添加到场景中的一个对象上。
我偷懒就直接添加到了摄像机上。
注意,其他两个代码不要添加到任何对象上。
运行结果如图:
2.png(47.47KB,下载次数:
0)
下载附件
保存到相册
5
天前上传
为了证明之前所说的不要在OnDestroy函数里访问单例模式,我们把SingletonSample.cs脚本里注释掉得OnDestroy函数解开注释,然后再次运行。
结果如下:
1.png(95.15KB,下载次数:
我们注意到,除了Log页面里出现了错误信息外,右侧的场景面板里也多了一个Singleton对象(这是我已经停止运行了)。
从Log信息里,我们可以发现,在第一次销毁掉单例模式后,单例模式又再次被创建,但却没有被销毁,由此便残留在了面板里。
正确的做法是,在OnDestroy函数里加一层安全性判断,如下:
voidOnDestroy(){
if(Singleton.IsCreatedInstance(“LitJsonSample”))
这样,就可以得到正确结果了。
结束语
最后,还有几句话要啰嗦一下,虽然和单例模式的关系不大,嘿嘿。
我们需要注意一下Start函数和Awake函数的执行顺序。
在这个例子里,我在LitJsonSample.cs的Awake函数里调用了ReloadFamilyData来初始化数据,细心的童鞋可以发现,在上一篇博文里,初始化数据是在Start函数里完成的。
之所以要把它挪到Awake函数里,是为了在我们访问单例时,可以保证数据一定已经被初始化了,因此把初始化函数放到Awake函数里,访问单例的代码放在Start函数里。
同样的原因,在Singleton.cs的脚本里DontDestroyOnLoad(gameObject);
需要放在Awake函数,而不是Start函数里。
关于Awake函数和Start函数的执行顺序,可以详见脚本说明。
简单来说,Awake函数在这个脚本在场景中加载时就会调用,至于所有脚本的Awake函数的调用顺序是未知的。
然后,在所有的Awake函数调用完毕后,才开始调用Start函数。
需要注意的是,Start函数也不是一定立即执行的,它是在该脚本第一次调用Update函数之前调用的,也就是说,如果这个脚本一开始的状态是disable的,那么直到它变成enable状态,在Update函数第一次执行前,才会执行Start函数。
两个函数的执行顺序是时间有时正是某些Bug的产生原因!
而且这些Bug往往很难发现。
哈,我这次实习的面试时,面试的姐姐就问过我这个问题,希望大家也可以搞清楚,如果我这里有说的不对的,请指正。
好啦,这次就到这里,谢谢阅读!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- unity3D 技术 使用 模式 Singleton