1. 我们知道,在Unity中,所有对象脚本都必须继承MonoBehavior脚本,才能使用Unity内置的脚本功能;
    2. 通常我们可以用静态类来取代单例模式,但是静态类方法的缺点是,它们必须继承最底层的类----Object。这意味着静态类不能继承MonoBehaviour,因此,我们不能使用它的任何一个Unity的功能,包括所有重要事件的回调函数,包括协程。并且,因为没有对象可供选择,我们失去了在运行时通过Inspector面版检查对象的数据的能力。这些都是我们可以通过单例模式使用的功能。
    3. 一个常见的解决办法是“单例作为组件”,让一个游戏对象包含自己。并提供静态方法以授予全局访问。需要注意,在这种情况下,我们必须用私有静态实例变量和一种全局访问的全局实例方法基本上实现典型的单例设计模式。
    4. 作为全局访问,我们对该组件在场景中只需要永远存在唯一一个组件单例实例:无则生成,多则销毁剩一个,切换场景不销毁唯一实例,仅此而已
      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; }
      }
      }
    5. 子类继承Unity单例组件类进行方法构造,就可以正常使用单例模式了:

      public class ResourcesManagerSingleton : SingletonComponent<ResourcesManagerSingleton>
      {
      public static ResourcesManagerSingleton Instance
      {
      get { return _Instance as ResourcesManagerSingleton; }
      set { _Instance = value; }
      }
      }
    6. 如果可能的话,我们不应该放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 组件式泛型单例模式的更多相关文章

  1. react-router 组件式配置与对象式配置小区别

    1. react-router 对象式配置 和 组件式配置    组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...

  2. Agile.Net 组件式开发平台 - 组件开发示例

    所谓组件式开发平台,它所有的功能模块都是以组件的形式扩展的,下面我来演示一个简单的组件开发例程. Agile.Net开发管理平台项目,已经托管在开源中国码云平台(http://git.oschina. ...

  3. Agile.Net 组件式开发平台 - 平台系统介绍

    平台介绍 Agile.Net 组件式开发平台是一款针对企业级产品的开发框架,平台架构基于SOA服务体系,多层组件式架构打造.平台提供企业应用开发所需的诸如ORM.IOC.WCF.EBS.SOA等分布式 ...

  4. 基于TypeScript的FineUIMvc组件式开发(开头篇)

    了解FineUIMvc的都知道,FineUIMvc中采用了大量的IFrame框架,对于IFrame的优缺点网上也有很多的讨论,这里我要说它的一个优点“有助于隔离代码逻辑”,这也是FineUIMvc官网 ...

  5. Unity3d&C#分布式游戏服务器ET框架介绍-组件式设计

    前几天写了<开源分享 Unity3d客户端与C#分布式服务端游戏框架>,受到很多人关注,QQ群几天就加了80多个人.开源这个框架的主要目的也是分享自己设计ET的一些想法,所以我准备写一系列 ...

  6. SuperMap iObject入门开发系列之一组件式GIS开发平台介绍

    本文是一位好友“炀炀”授权给我来发表的,介绍都是他的研究成果,在此,非常感谢.平台介绍:SuperMap iObjects Java/.NET 是面向GIS应用系统开发者的组件式GIS开发平台,具有强 ...

  7. 组件式开发(Vue)

    什么是组件式开发: 组件式开发就是将单个组件组合起来,形成一个大的组件进行页面的开发完成 什么是复合型组件: 复合型组件就是将相同的功能写成一个公用的组件(单元组件),供其他组件使用,就类似于后台开发 ...

  8. 组件式开发框架 craftyjs

    想要少写代码,请用组件式开发吧.传统的oop,一直做着重复的事性. 先理解下概念 Entity            实体        An entity is just an ID Compone ...

  9. PIE SDK组件式开发综合运用示例

    1. 功能概述 关于PIE SDK的功能开发,在我们的博客上已经分门别类的进行了展示,点击PIESat博客就可以访问,为了初学者入门,本章节将对从PIE SDK组件式二次开发如何搭建界面.如何综合开发 ...

随机推荐

  1. 不能安装这个“安装 OS X EI Capitan”应用程序副本不能验证” 的解决办法

    不能安装这个“安装 OS X EI Capitan”应用程序副本不能验证.它在下载过程中可能已遭破坏或篡改. 解决办法:修改系统时间. 1,查看你的dmg文件的创建日期 2,把你的系统日期修改到比这个 ...

  2. js函数在frame中的相互的调用

    框架编程概述一个HTML页面可以有一个或多个子框架,这些子框架以<iframe>来标记,用来显示一个独立的HTML页面.这里所讲的框架编程包括框架的自我控制以及框架之间的互相访问,例如从一 ...

  3. python-time、datetimme模块

    time模块 1.time.time():返回当前时间的时间戳. 打印时间戳: >>> import time >>> time.time() 1530329387 ...

  4. ASP.NET mvc 验证码 (转)

    ASP.net 验证码(C#) MVC http://blog.163.com/xu_shuhao/blog/static/5257748720101022697309/ 网站添加验证码,主要为防止机 ...

  5. Extjs 4.2 panel 添加 click 事件及右键菜单

    listeners: { render: function(c) { c.body.on('click', function() { //TODO 添加点击事件功能 }); c.body.on('co ...

  6. DataTables的相关问题集锦

    1.修改头部问题,列表加载完重新修改表头内容 使用回调函数: headerCallback: function( thead, data, start, end, display ) {        ...

  7. Openresty最佳案例 | 第6篇:OpenResty连接Mysql

    转载请标明出处: http://blog.csdn.net/forezp/article/details/78616698 本文出自方志朋的博客 centos 安装mysl Centos系统下安装my ...

  8. 魔板 Magic Squares(广搜,状态转化)

    题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜 ...

  9. 【CodeForces 660D】Number of Parallelograms(n个点所能组成的最多平行四边形数量)

    You are given n points on a plane. All the points are distinct and no three of them lie on the same ...

  10. 大学C++程序设计教程期末复习重点

    第一章 1.cin与count的应用<iostream> 例: cin>>a; cout<<"hello"<<endl; cout& ...