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组件式二次开发如何搭建界面.如何综合开发 ...
随机推荐
- js中json对象取键和值
1.json中输出各个键值: var ohp = {"星期一":18,"星期二":16,"星期三":19,"星期四":1 ...
- canvas基本图形
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- servlet三种方式实现servlet接口
简单介绍 Servlet接口实现类 1.Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet.HttpServlet. 2.HttpServlet指能够处理HTTP请 ...
- 【luoguP1238】【NOIP2014】生活大爆炸版剪刀石头布
生活大爆炸版剪刀石头布 ——[传送门] 这道题可以原原本本地说得上是一道水题了,通过判断两人的出拳不同给分然后统计输出.就是对于游戏得分 ...
- javascript之Window 对象
一.说明:他是JS中最大的对象,它描述的是一个浏览器窗口,一般要引用他的属性和方法时,不需要用“Window.XXX”这种形式,而是直接使用“XXX”.一个框架页面也是一个窗口. 二.Window窗口 ...
- U盘安装centOS和下载地址
使用到的材料: 1.centos-6.2 i386 minimal 下载地址:http://mirrors.163.com/centos/6.2/isos/i386/CentOS-6.2-i386-m ...
- Question 20171117 Java中的编码问题?
撰文缘由 前几天做一个邮件发送功能,一些常用信息配置在properties文件中,通过prop.getProperty(key)来获取配置的信息,结果配置文件中是用中文写的,邮件发送成功后,邮箱中的激 ...
- Showing All Messages : error: open /Users/apple/Library/Developer/Xcode/DerivedData/xxx-dkhmpttmnuppvbcxijlcxacfpzcl/Build/Products/Debug-iphoneos/xxx.app/EaseUIResource.bundle/arrow@2x.png: N
2报错 Showing All Messages : error: open /Users/apple/Library/Developer/Xcode/DerivedData/xxx-dkhmpttm ...
- <逆向学习第二天>如何手动脱UPX、Aspack壳
UPS.AsPack压缩壳介绍: UPX .AsPack是一款先进的可执行程序文件压缩器.压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间.网络上传下载的时间和其它分布以及存储费用. ...
- 【赛时总结】NOIP2018-三校联考1024
◇NOIP三校联考-1024◇ 发现以前的博客写得似乎都很水……基本上都没什么阅读量QwQ 决定改过自新╰( ̄ω ̄o) 就从这篇博客开始吧~ 现场考得无地自容,看到题解才发现一些东西……(我第三题还没 ...