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组件式二次开发如何搭建界面.如何综合开发 ...
随机推荐
- Android学习笔记_62_手机安全卫士知识点归纳(2)ListView重要属性 PopupWindow应用
1.缓存颜色: 为什么ListView在拖动的时间是黑色,而静止时间是自己的颜色是因为 ListView的缓存.只需一个配置即可.在这个ListView里面加上它即可. android:cacheCo ...
- HDU 1222 Wolf and Rabbit(数学,找规律)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...
- SqlSugar之SqlQueryDynamic返回值处理
现在有个需求,有一张表每个月表名都会变的,但结构是一样的,我们不能再用类映射来完成的,我不能每个月都去手动添加,我们只能使用sql语句来完成这个需求.为了方便我这边选择的是SqlQueryDynami ...
- Restframework框架总结及restful规范
1. django rest framework框架的作用? 帮助开发者可以快速开发出遵循restful规范的API 2. django rest framework框架都有哪些组件(10)? -版本 ...
- group by 注意的细节 ,
1. GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前. HAVING语句必须在ORDER BY子句之后.(where先执行,再groupby分组:groupby先分组,ha ...
- oracle远程导出/导入
创建db_link,远程导出/导入.expdp/impdp Oracle数据库本地磁盘空间有限,或应用系统的需要,会通过远程的方式导出数据库.在oracle当中,exp远程导库的速度太慢,而expdp ...
- c#一种存储结构解决动态平衡问题
不说其他了,最近为了实现这么一个场景了而提取的一种结构.我们把一种数据缓存,比如开辟的存储Buffer,或者连接池.放置在一个结构中.很多时候这有一个共同的特点,我们的业务在一段时间会急剧增长,我们开 ...
- 【PHP】Laravel将HTML实体转换回普通字符
问题 最近一个laravel模板的项目需要用到summernote富文本编辑器,内容保存到数据库里是原始的html代码.再读取出来时使用htmlspecialchars_decode()对内容进行转换 ...
- ECSHOP和SHOPEX快递单号查询申通插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- PHP 十问
1.为了保证精度,Mysql中存钱数的字段用什么类型?PHP怎么处理浮点数精度 decimal数据类型来存储钱: 浮点数的精度有限.尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由 ...