Unity基础程序框架设计【学习笔记】【边学习边更新】

一、几种常见的单例模式基类及要点

(1)常规单例

1. 常规单例基类写法一

using UnityEngine;

public class NormalSingleton<T> where T : class,new()
{
    private static T _single;
    public static T Single
    {
        get
        {
            if (_single == null)
            {
                T t = new T();
                if (t is MonoBehaviour)
                {
                    Debug.LogError("请使用Mono单例基类");
                    return null;
                }
                _single = t;
            }
            return _single;
        }
    }
}

2. 常规单例基类写法二

using UnityEngine;

public class NormalSingleton1<T> where T : class,new()
{
    private static T _instance;
    public static T GetInstance()
    {
        if(_instance==null)
        {
            _instance = new T();
        }
        return _instance;
    }
}

3. 总结

两种方式其实差不多,不过是用属性和方法的区别,个人偏向于写法一感觉属性更优雅些。

(2)Mono类单例

1. Mono类单例基类写法一

public class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T GetInstance()
    {
        return instance;
    }

    private void Awake()
    {
        instance = this as T;
    }
}

2. Mono类单例基类写法二

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MonoSingleton2<T> : MonoBehaviour where T:MonoBehaviour
{
    private static T _single;

    public static T Single
    {
        get
        {
            if(_single==null)
            {
                _single = FindObjectOfType<T>();
                {
                    if(_single==null)
                    {
                        Debug.Log("场景中未找到类的对象,类名为:" + typeof(T).Name);
                    }
                }
            }
            return _single;
        }
    }

    private void Awake()
    {
        if(_single==null)
        {
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

3. Mono类单例基类写法三

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MonoSingleton3<T> : MonoBehaviour where T :MonoBehaviour,new()
{
    private static T _single;

    public static T GetSingle()
    {
        if(_single == null)
        {
            GameObject obj = new GameObject();
            obj.name = typeof(T).Name;
            DontDestroyOnLoad(obj);
            _single = obj.AddComponent<T>();
        }
        return _single;
    }
}

4. 总结

前两者均需要将脚本挂在物体上,写法三可以实现自动生成同名称的空物体,写法二和三均用到了反射的知识点,写法三逻辑清晰巧妙,
通过判断单例对象是否为空来决定是否启动不销毁函数逻辑,保证所有场景中仅有一个实例,而写法二是采用销毁的方式不够优雅,建议使用写法三。

(3)使用方式和好处

使用方式:让需要实现单例的类继承相应的单例模式基类。
好处:    通过继承的方式,省去对所需类实现单例的时间。

二、缓存池模块

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 池子类 
/// </summary>
public class PoolData
{
    public GameObject fatherObj;
    public List<GameObject> poolList;

    public static Transform gunPoint = GameObject.Find("gunPoint").transform;

    public PoolData(GameObject obj,GameObject poolObj)
    {
        fatherObj = new GameObject(obj.name);
        fatherObj.transform.parent = poolObj.transform;
        poolList = new List<GameObject>() {  };
        PushObj(obj);
    }
    
    public void PushObj(GameObject obj)
    {
        //存起来
        poolList.Add(obj);
        //设置父对象
        obj.transform.parent = fatherObj.transform;
        //失活 隐藏物体
        obj.SetActive(false);
    }

    public GameObject GetObj()
    {
        GameObject obj = null;
        //取出第一个
        obj = poolList[0];
        poolList.RemoveAt(0);
        obj.transform.parent = gunPoint;
        obj.SetActive(true);
        obj.transform.parent = null;

        return obj;
    }
}

/// <summary>
/// 缓存池模块
/// </summary>
public class PoolMgrPro : NormalSingleton<PoolMgrPro>
{
    public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();

    public GameObject poolObj = null;

    //取出池子
    public GameObject GetObj(string name)
    {
        GameObject obj = null;

        if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
        {
            obj = poolDic[name].GetObj();
        }
        else
        {
            obj = GameObject.Instantiate(Resources.Load<GameObject>(name),PoolData.gunPoint);
            obj.name = name;
        }

        return obj;
    }

    //存入池子
    public void PushObj(string name, GameObject obj)
    {
        if (poolObj == null)
        {
            poolObj = new GameObject("Pool");
        }
        //有对应池子
        if (poolDic.ContainsKey(name))
        {
            poolDic[name].PushObj(obj);
        }
        //无对应池子
        else
        {
            poolDic.Add(name, new PoolData(obj, poolObj));
        }
    }

    //清空缓存池
    public void Clear()
    {
        poolDic.Clear();
        poolObj = null;
    }
}

使用方式

特殊情境:针对子弹火花弹痕效果设计的缓存池,在对应预制体身上挂载延迟函数,在角色开火函数中调用取出对象池,
在预制体身上延迟调用存入对象池,也就是存回对应的List中,可以有效提高性能效率。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值