Unity的程序基础框架,视频地址:https://www.bilibili.com/video/BV1C441117wU
一、建立目录
在Assets下建立标准目录,如下图:
二、功能模块
三、脚本
3.1、单例模式基类
知识点:单例模式是设计模式中很常用的一种模式,它的目的是让一个类在程序运行期间有且只有一个实例。因为只有一个实例,减少了内存消耗和系统性能开销。单例模式有三个特点:
(1)单例类只能有一个实例。
(2)单例类必须自己创建自己的唯一实例。
(3)单例类必须给所有其他对象提供这一实例。
脚本:BaseManager.cs
//定义单例模式基类,采用泛型构造,使用无参构造函数约束泛型T的类型。
public class BaseManager<T> where T:new()
{
//定义单例模式基类实例变量
private static T instance;
//定义单例模式基类中实例化方法
public static T GetInstance()
{
//如果实例为空,则实例化对象
if (instance == null)
instance = new T();
return instance;
}
}
//------------------------------------------------------------------------------------
//单例模式基类的使用,新的单例模式类直接继承基类
public class GameManager : BaseManager<GameManager>
{
}
public class ItemManager : BaseManager<ItemManager>
{
}
//其他单例模式类的使用
public class test
{
void main()
{
GameManager.GetInstance();
ItemManager.GetInstance();
}
}
3.2、缓存池模块
在GameObject大量生成->销毁的情况下(如子弹射击),销毁的物体只是删除对内存空间的引用,但并未释放实例化物体占用的内存空间。当内存空间占满后进行GC(Garbage Collection),将造成游戏运行卡顿。为了避免这种情况,通过缓存池对销毁物体的内存空间进行暂存,当需要创建新物体时直接从缓存池取出,新物体不再占用新的内存空间(除非缓存池中存放的物体数量不够),从而减少内存的消耗。
知识点:命名空间System.Collections.Generic中有两个非常重要,而且常用的泛型集合类,它们分别是Dictionary<TKey,TValue>字典和List列表。Dictionary字典通常用于保存键/值对的数据,而List列表通中用于保存可通过索引访问的对象的强类型列表。
脚本:PoolMgr.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class PoolMgr : BaseManager<PoolMgr>
{
//定义构造类,每类放入缓存池的物体应当有一个标识其类别的父对象,及存储物体的容器
public class PoolData
{
public GameObject PoolFather;
public List<GameObject> PoolList;
//FObj物体用于在缓存池内表明物体具体类别,PoolObj物体用于代表缓存池,多个FObj的父对象都设置为PoolObj以体现层级关系
public PoolData(GameObject Obj,GameObject PoolObj)
{
PoolFather = new GameObject(Obj.name);
PoolFather.transform.parent = PoolObj.transform;
PoolList = new List<GameObject>() {
};
PutObj(Obj);
}
public void PutObj(GameObject Obj)
{
Obj.SetActive(false);
PoolList.Add(Obj);
Obj.transform.parent = PoolFather.transform;
}
public GameObject GetObj()
{
GameObject Obj = null;
Obj = PoolList[0];
PoolList.RemoveAt(0);
//取出物体时使其激活
Obj.SetActive(true);
//取出缓存池的物体断开和缓存池物体的父子联系
Obj.transform.parent = null;
return Obj;
}
}
//创建缓存池,定义字典参数PoolDict实现多个对象的存储,其中第一个string参数说明缓存物体的类别,用自定义的PoolData类型作为第二个参数存储对象类别(PoolFather)和对象List列表(PoolList)。
public Dictionary<string, PoolData> PoolDict = new Dictionary<string, PoolData>();
//定义一个物体,放入缓存池中的物体挂接到该物体下面,实现界面的简介易懂
private GameObject PoolObj;
//把物体放入缓存池,第一个参数存储物体名字,第二个参数存储物体实例
public void PutObj(string name,GameObject Obj)
{
//如果缓存池物体为空,则创建一个
if (PoolObj == null)
PoolObj = new GameObject("Pool");
//如果缓存池中有此类物体的List,则添加进该类物体的List中;如缓存池中无此类物体,则新建一个此类物体的List,并将该物体存入新建的List。
if (PoolDict.ContainsKey(name))
{
//在对应name类的List中存入物体
PoolDict[name].PutObj(Obj);
}else
{
//新建一个name类的PoolData,并把Obj物体添加进PoolData的List里
PoolDict.Add(name, new PoolData(Obj,PoolObj));
}
}
//采用异步加载方式从缓存池中取出指定物体,通过物体名字进行索引
public void GetObj(string name,UnityAction<GameObject> CallBack)
{
//如果缓存池中存在指定的物体名,且该类物体数量大于0则取出,否则重新实例化一个物体
if (PoolDict.ContainsKey(name) && PoolDict[name].PoolList.Count > 0)
{
CallBack(PoolDict[name].GetObj());
//调用PoolData中的GetObj()方法,从缓存池中取出物体
//Obj = PoolDict[name].GetObj();
}
else
{
ResourcesMgr.GetInstance().LoadAsync<GameObject>(name,(PObj)=>
{
PObj.name = name;
CallBack(PObj);
});
//重新实例化要取出的物体,从Resources目录中调用预制体
//Obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
//把实例化的物体名字改为传入的调用名字,否则物体实例化后会在名字后面加上(clone),不利于后续处理
//Obj.name = name;
}
}
//切场景的时候应当清除缓存池并把缓存池物体置空,否则调用会报错
public void PoolClear()
{
PoolDict.Clear();
PoolObj = null;
}
}
// PoolGetTest .cs----------------------------------------------------------------------
//从缓存池中取出物体脚本。当按下鼠标左键时,从缓存池取出指定名称为"Test/ Monster "的物体,当缓//存池中没有物体时,将从取出Resources/Test/目录下的Cube预制体进行实例化。按下鼠标右键时,则对"Test/ Player "物体进行相同操作。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolGetTest : MonoBehaviour
{
void Update()
{
if(Input.GetMouseButtonDown(0))
{
PoolMgr.GetInstance().GetObj("Test/Monster",(Obj)=> {
});
}
if (Input.GetMouseButtonDown(1))
{
PoolMgr.GetInstance().GetObj("Test/Player", (Obj) => {
});
}
}
}
// PoolPutTest .cs----------------------------------------------------------------------
//将物体放入缓存池脚本。将此脚本挂在Resources/Test/目录下的预制体上,当该物体被实例化调用后,延迟1秒后放入缓存池。
public class PoolPutTest : MonoBehaviour
{
//当对象激活时,会进入的生命周期函数
private void OnEnable()
{
Invoke("Put",1);
}
void Put()
{
PoolMgr.GetInstance().PutObj(this.gameObject.name,this.gameObject);
}
}
3.3、事件中心模块
通过Dictionary<string,UnityAction>存储事件及对应的处理方法,string存储事件名,UnityAction使用委托来存储多个事件处理方法。
脚本:EventMgr.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class EventMgr : BaseManager<EventMgr>
{
//Dictionary的Key对应字符串类型的事件名(如怪物死亡,玩家死亡等),Value对应的是监听这个事件的委托函数们,此处使用UnityEngine.Events命名空间下自带的事件标识UnityAction。
private Dictionary<string, UnityAction<object>> EventDict = new Dictionary<string, UnityAction<object>>();
//添加事件监听,添加指定事件名字的监听器,并说明准备处理该事件的方法
public void AddEventListener(string name,UnityAction<object> action)
{
//如果事件管理模块中有name名字的事件,则在该事件中加入一个传入的处理方法
if(EventDict.ContainsKey(name))
{
EventDict[name] += action;
}
//如果事件管理模块中没有name名字的事件,则添加这个事件以及对应的处理方法
else
{
EventDict.Add(name, action);
}
}
//移除事件监听,当物体销毁时应当在事件管理器中移除该物体监听事件执行的方法
public void RemoveEventListener(string name,UnityAction<