Uniy 组件式泛型单例模式
- 我们知道,在Unity中,所有对象脚本都必须继承MonoBehavior脚本,才能使用Unity内置的脚本功能;
- 通常我们可以用静态类来取代单例模式,但是静态类方法的缺点是,它们必须继承最底层的类----Object。这意味着静态类不能继承MonoBehaviour,因此,我们不能使用它的任何一个Unity的功能,包括所有重要事件的回调函数,包括协程。并且,因为没有对象可供选择,我们失去了在运行时通过Inspector面版检查对象的数据的能力。这些都是我们可以通过单例模式使用的功能。
- 一个常见的解决办法是“单例作为组件”,让一个游戏对象包含自己。并提供静态方法以授予全局访问。需要注意,在这种情况下,我们必须用私有静态实例变量和一种全局访问的全局实例方法基本上实现典型的单例设计模式。
- 作为全局访问,我们对该组件在场景中只需要永远存在唯一一个组件单例实例:无则生成,多则销毁剩一个,切换场景不销毁唯一实例,仅此而已
using UnityEngine; public class SingletonComponent<T> : MonoBehaviour where T : SingletonComponent<T>
{
private static SingletonComponent<T> _instance; public static SingletonComponent<T> _Instance
{
get
{
if (_instance != null)
{
T[] compoments = GameObject.FindObjectsOfType(typeof (T)) as T[]; if (compoments != null && compoments.Length == )
{
return compoments[];
}
else
{
for (int c = ; c < compoments.Length -; ++c)
{
DestroyImmediate(compoments[c].gameObject);
}
return compoments[compoments.Length -];
}
} GameObject go = new GameObject(typeof(T).Name,typeof(T));
_instance = go.GetComponent<T>();
DontDestroyOnLoad(_instance.gameObject);
return _instance;
}
set { _instance = value as T; }
}
} - 子类继承Unity单例组件类进行方法构造,就可以正常使用单例模式了:
public class ResourcesManagerSingleton : SingletonComponent<ResourcesManagerSingleton>
{
public static ResourcesManagerSingleton Instance
{
get { return _Instance as ResourcesManagerSingleton; }
set { _Instance = value; }
}
} - 如果可能的话,我们不应该放SingletonAsComponent 的派生类到我们的场景面版。这是因为 DontDestroyOnLoad()方法从来没被调用过。这将使单例组件对象在下一个场景加载的时候不存在了。
因此,如果任何对象尝试在OnDestroy()中做任何与单例相关的事,那它就会调用单例属性。如果单例在这一刻已经被摧毁,该对象的销毁过程就会在应用程序关闭期间创建一个新的单例。这可能会损坏我们的场景文件,因为我们的单例组件被遗留在了场景之后。如果这样,Unity就会报出一个错误:

为什么某些对象会在销毁阶段调用单例模式是因为单例经常使用观察者模式。这种设计模式允许其他对象注册/注销他们特定的任务,类似于Unity如何锁住回调,但是用了一个不太自动化的方式。我们将在即将到来的部分中看到一个全局信息系统的例子。对象将在系统构建的时候注册,而在关闭的时候取消注册,要做到这一点的最方便的地方是它的ondestroy()方法内。因此,这样的对象可能会遇到上述问题,也就是单例模式在应用程序关闭期间出现问题的地方。
为了解决这个问题,我们需要做出三点改变。首先,我们需要添加一个附加标志给单例组件,用来跟踪它的活动状态,并在适当的时候禁用它。这包括了单例自己的毁灭,以及应用程序关闭(OnApplicationQuit()是另一个Unity在这段时间有用的回调):
private bool _alive = true;
void OnDestroy() { _alive = false; }
void OnApplicationQuit() { _alive = false; }
Secondly, we should implement a way for external objects to verify the Singleton’s current
state:
然后,我们应该实现一种外部对象来验证单例的当前状态:
public static bool IsAlive {
get {
if (__Instance == null)
return false;
return __Instance._alive;
}
}
最后,任何试图在自己OnDestroy()方法里调用单例的,必须先使用IsAlive属性来验证状态。举个例子:
public class SomeComponent : MonoBehaviour {
void OnDestroy() {
if (MySingletonComponent.IsAlive) {
MySingletonComponent.Instance.SomeMethod();
}
}
}
这将确保没有人试图在销毁过程中访问实例。如果我们不遵守这个规则,我们就会因为返回到编辑模式下,由于单例还存在于场景中而运行报错。
比较讽刺的是单例组件的出现后,在我们访问单例的实例之前,我们用Find()方法来确定单例组件是否在场景中存在。
幸运的是,这将只发生在单例组件的第一次被访问时。但是单例的初始化不一定发生在场景的初始化的时候,因此可能在这个对象被实例化和调用Find()方法时给我们游戏的过程中造成一个很不好的表现。解决办法是一个最高的类通过简单的调用每一个实例在场景的初始化时确定单例的初始化。
这种方法的缺点是,如果我们之后决定存在多个管理类,我们希望把它的行为分离出来更为模块化,就会有很多的代码需要改变。
还有进一步的选择,我们可以探索,如利用Unity的内置的脚本代码和检查界面之间的接口。
Uniy 组件式泛型单例模式的更多相关文章
- react-router 组件式配置与对象式配置小区别
1. react-router 对象式配置 和 组件式配置 组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...
- Agile.Net 组件式开发平台 - 组件开发示例
所谓组件式开发平台,它所有的功能模块都是以组件的形式扩展的,下面我来演示一个简单的组件开发例程. Agile.Net开发管理平台项目,已经托管在开源中国码云平台(http://git.oschina. ...
- Agile.Net 组件式开发平台 - 平台系统介绍
平台介绍 Agile.Net 组件式开发平台是一款针对企业级产品的开发框架,平台架构基于SOA服务体系,多层组件式架构打造.平台提供企业应用开发所需的诸如ORM.IOC.WCF.EBS.SOA等分布式 ...
- 基于TypeScript的FineUIMvc组件式开发(开头篇)
了解FineUIMvc的都知道,FineUIMvc中采用了大量的IFrame框架,对于IFrame的优缺点网上也有很多的讨论,这里我要说它的一个优点“有助于隔离代码逻辑”,这也是FineUIMvc官网 ...
- Unity3d&C#分布式游戏服务器ET框架介绍-组件式设计
前几天写了<开源分享 Unity3d客户端与C#分布式服务端游戏框架>,受到很多人关注,QQ群几天就加了80多个人.开源这个框架的主要目的也是分享自己设计ET的一些想法,所以我准备写一系列 ...
- SuperMap iObject入门开发系列之一组件式GIS开发平台介绍
本文是一位好友“炀炀”授权给我来发表的,介绍都是他的研究成果,在此,非常感谢.平台介绍:SuperMap iObjects Java/.NET 是面向GIS应用系统开发者的组件式GIS开发平台,具有强 ...
- 组件式开发(Vue)
什么是组件式开发: 组件式开发就是将单个组件组合起来,形成一个大的组件进行页面的开发完成 什么是复合型组件: 复合型组件就是将相同的功能写成一个公用的组件(单元组件),供其他组件使用,就类似于后台开发 ...
- 组件式开发框架 craftyjs
想要少写代码,请用组件式开发吧.传统的oop,一直做着重复的事性. 先理解下概念 Entity 实体 An entity is just an ID Compone ...
- PIE SDK组件式开发综合运用示例
1. 功能概述 关于PIE SDK的功能开发,在我们的博客上已经分门别类的进行了展示,点击PIESat博客就可以访问,为了初学者入门,本章节将对从PIE SDK组件式二次开发如何搭建界面.如何综合开发 ...
随机推荐
- 学大伟业 Day 6 培训总结
今天接着昨天的继续讲数据结构 今天先是 分块 在统计问题中,尤其是序列问题,经常涉及到区间的操作,比如修改一段区间的元素,询问某个区间的元素的信息. 如果每次都对一整个区间的每一个元素进行操作的话,那 ...
- Android学习笔记_12_网络通信之从web获取资源数据到Android
从web获取图片信息,并显示到android的imageView控件. 一.添加网络访问权限. <uses-permission android:name="android.permi ...
- UML 类关系图(泛化,实现,依赖,关联(聚合,组合))
UML的构造快包含3种: (1) 事物(4种):结构事物,行为事物,分组事物,注释事物 (2) 关系(4种):泛化关系,实现关系,依赖关系,关联关系 (3) 图(10种):用例图,类图,对象图,包图 ...
- 课时60.CSS的固定格式(掌握)
CSS就是用来设置样式的,美化界面的 如何验证? 打开一个京东首页 删除掉css样式 发现页面变得非常难看 由此我们验证了一个说法,css就是用来美化界面的 1.格式: <style type= ...
- Java基础——数组复习
数组是一个变量,存储相同数据类型的一组数据 声明一个变量就是在内存空间划出一块合适的空间 声明一个数组就是在内存空间划出一串连续的空间 数组长度固定不变,避免数组越界 数组是静态分配内存空间的,所 ...
- Kong Api 初体验
请查看原文: https://www.fangzhipeng.com/nginx/kong/2016/07/11/kong-api-gateway/ Kong是一个可扩展的开源API层(也称为API网 ...
- Oracle客户端与Toad、plsql developer安装
(一)oracle client与oracle instant client比较 当我们要使用Toad.plsql developer等工具连接数据库时,首先需要在自己的电脑上安装oracle cli ...
- Python常用模块之os和sys
1.OS常用方法 os.access(path, mode) # 检验权限模式 os.getcwd() #获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirn ...
- foreach, for in, for of 之间的异同
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数. 注意: forEach() 对于空数组是不会执行回调函数的. 示例代码: var arr = [4, 9, 16, 25]; ...
- http状态码(status_codes)
首先:1XX 接受的请求正在处理,2XX请求正常处理完毕,3XX需要进行附加操作以完成请求(重定向?),4XX服务器无法处理请求(也就是客户端请求错误),5XX服务器处理请求出错. 当然不仅仅是一张图 ...