雪千渔Blog

  • 首页
  • 写写代码
    • dotNet
    • C++
    • Lua
    • Visual Basic
    • Java
    • Android
    • Web
  • DCC
    • Maya
    • Maya-Plug
    • AfterEffect
    • AfterEffect-Plug
    • PhotoShop-Plug
  • 游戏制作
    • Unity3D
    • UnrealEngine
    • 经验杂谈
    • 游戏设计
    • 自研引擎
    • 效果实现
  • 其他
    • 乱七八糟
    • 软件工具
    • 留言板
    • 自制素材
    • 关于我
雪千渔blog
唯有热爱,能抵漫长岁月
  1. 首页
  2. GameDev
  3. Unity3D
  4. 正文

MonoSingleton生命周期与移动构造

2022年3月23日 961点热度 0人点赞 0条评论

在Unity中使用单例时一般会选择使用跟随Unity生命周期的MonoBehaviour对象,一般情况下的MonoSingleton对象都是DontDestroyOnLoad处理不会销毁的对象。

切换场景时两个mono对象的生命周期。

https://www.imxqy.com/imagegx/unity/monosingleton_1.jpg

有一些时候为了在场景内更好的可视化调试和修改需要将MonoSingleton的对象放置于场景中而不是动态的添加,这样会出现一个问题,如果重新加载该场景或者其他存在此类型的场景时,将会造成两个MonoSingleton同时在场的情况,为了处理这种情况可以有两种方式:

  • 切换场景时保持旧实例,销毁新实例
  • 切换场景时将将旧实例数据移动到新实例后,销毁旧实例

https://www.imxqy.com/imagegx/unity/monosingleton_2.jpg

为了代码的复用性而实现的MonoSingleton,为了实现该功能不得不让派生类抛弃Awake函数来初始化。

这里使用OnMoveConstructor作为派生类初始化函数,Awake则负责MonoSingleton的初始化工作。

先尝试KeepInstance,如果存在存在旧实例说明当前对象是新实例,则销毁自己并结束函数;

如果没有允许保持旧实例或者没有旧实例,那就说明当前实例是需要初始化并留下来的,调用MoveInstance,将可能存在的旧实例传给新实例,派生类可以在OnMoveConstructor中对新实例进行初始化。

using System;
using UnityEngine;

public abstract class MonoSingleton<T>
    : MonoBehaviour where T : MonoSingleton<T>
{
    [SerializeField]
    private bool IsDontDestroyOnInit = true;
    [SerializeField]
    private bool IsKeepInstance = true;

    private static T mInstance = null;

    public static T Instance
    {
        get
        {
            if (mInstance == null)
            {
                //如果instance为空并且可以在场景里找到该类型,那么就设置为单例,否则新建对象
                mInstance = GameObject.FindObjectOfType(typeof(T)) as T;
                if (mInstance == null)
                {
                    GameObject go = new GameObject("__m_" + typeof(T).Name);
                    mInstance = go.AddComponent<T>();
                }
                if (mInstance.IsDontDestroyOnInit)
                {
                    if (object.ReferenceEquals(mInstance.transform.parent, null))
                    {
                        DontDestroyOnLoad(mInstance.gameObject);
                    }
                }
            }
            return mInstance;
        }
    }
    public static bool HasInstance
    {
        get => mInstance != null;
    }

    protected virtual void Awake()
    {
        //允许保持旧实例并且可以保持旧实例就直接返回
        if (IsKeepInstance && KeepInstance())
        {
            //keep
            return;
        }
        else
        {
            //这里有两种情况,无论是否存在旧实例,都会调用OnMoveConstructor虚函数
            //如存在旧实例则为移动,不存在旧实例(形参为null)则为新实例
            MoveInstance();
        }

        if (IsDontDestroyOnInit)
        {
            if (this.transform.parent == null)
            {
                DontDestroyOnLoad(gameObject);
            }
        }
    }

    protected virtual void OnMoveConstructor(T oldInstance)
    {

    }

    public static T GetInstance()
    {
        return Instance;
    }
    private void MoveInstance()
    {
        var old = mInstance;
        mInstance = this as T;
        OnMoveConstructor(old);
        if (old != null) //销毁旧实例
        {
            Destroy(old.gameObject);
        }
    }

    /// <summary>
    /// 保持实例,如果有新实例则会销毁,并返回true
    /// </summary>
    /// <returns></returns>
    private bool KeepInstance()
    {
        if (HasInstance)
        {
            Destroy(gameObject);
            return true;
        }
        return false;
    }

    protected virtual void OnDestroy()
    {
        if (HasInstance)
        {
            if (mInstance == this)
            {
                mInstance = null;
            }
        }
    }

}

 

 

 

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2022年4月10日

JomiXedYu

IndieGame Developer & Netease Games TechArt

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

JomiXedYu

IndieGame Developer & Netease Games TechArt

最新 热点 随机
最新 热点 随机
UE材质Custom节点与HLSL的HACK操作 UE5出现D3D12崩溃报错解决方案 游戏引擎脚本绑定的三种写法与利弊 一种解决不支持中文与空格文件名的编码 Vulkan坐标系通用方案以及反转viewport UE编辑器开发之蓝图篇
一种解决不支持中文与空格文件名的编码游戏引擎脚本绑定的三种写法与利弊UE5出现D3D12崩溃报错解决方案UE材质Custom节点与HLSL的HACK操作
游戏引擎脚本绑定的三种写法与利弊 .Net逆向 Steam平台Unity游戏破解 C++元编程之判断是否为共享指针模板 Lua面向对象 C++使用类模板中的类模板与类 HSV与RGB互转公式与Color封装
友情链接
  • DorinXL
  • 小博博客
  • 秋橘斋

COPYRIGHT © 2014-2023 雪千渔Blog. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

辽ICP备20006894号-1