介绍
对常用的模块进行封装,实现部分通用基础框架。文章来源地址https://www.toymoban.com/news/detail-516311.html
单例基类
饿汉式单例基类
public class SingletonBase<T> where T : new()
{
private static T _instance;
public static T Instance
{
get {
if (_instance == null) {
_instance = new T();
}
return _instance;
}
}
}
饿汉式Mono单例基类
public class SingletonMonoBase<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance => _instance;
// 子类继承并重写Awake,调用父级Awake,即可赋值Instance
protected virtual void Awake() {
_instance = this as T;
}
}
全局公共Mono
mono模块
public class MonoModule : MonoBehaviour
{
public event UnityAction MonoEvent;
// Start is called before the first frame update
void Start() {
GameObject.DontDestroyOnLoad(this);
}
// Update is called once per frame
void Update() {
MonoEvent?.Invoke();
}
public void AddEvent(UnityAction func) {
MonoEvent += func;
}
public void RemoveEvent(UnityAction func) {
MonoEvent -= func;
}
private void OnApplicationQuit() {
// 退出时释放并销毁,以免MissingReferenceException
MonoMgr.Instance.DestroyRef();
DestroyImmediate(this.gameObject);
}
}
mono管理器
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
public class MonoMgr : SingletonBase<MonoMgr>
{
private MonoModule _monoModule;
public MonoMgr() {
// 只在MonoModule不存在时创建新的MonoModule对象
_monoModule = Object.FindObjectOfType<MonoModule>();
if (_monoModule == null)
{
GameObject gameObject = new GameObject("MonoModule");
_monoModule = gameObject.AddComponent<MonoModule>();
Debug.Log("不存在");
}
else
{
Debug.Log("存在");
}
}
public void AddEvent(UnityAction func) {
_monoModule.AddEvent(func);
}
public void RemoveEvent(UnityAction func) {
_monoModule.RemoveEvent(func);
}
public Coroutine StartCoroutine(IEnumerator enumerator) {
return _monoModule.StartCoroutine(enumerator);
}
public void StopCoroutine(IEnumerator enumerator) {
_monoModule.StopCoroutine(enumerator);
}
public void StopCoroutine(Coroutine coroutine) {
_monoModule.StopCoroutine(coroutine);
}
public void StopAllCoroutine() {
_monoModule.StopAllCoroutines();
}
public void DestroyRef() {
MonoMgr.Instance = null;
_monoModule = null;
}
}
通用简易有限状态机FSM
状态机
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum StateEnum
{
Idle,
Walk,
Jump,
JumpDown,
JumpAtk,
Dash,
Atk,
Skill,
EnemyIdle,
EnemyWalk,
EnemyDetectedPlayer,
EnemyChargePlayer,
EnemyEvadePlayer,
EnemyHit,
EnemyAtk,
EnemyDead,
MageTeleport
}
[System.Serializable]
public class FsmSystem
{
/// <summary>
/// 下次状态ID
/// </summary>
public StateEnum NextStateID { get; private set; }
/// <summary>
/// 当前状态ID
/// </summary>
public StateEnum CurrentStateID { get; private set; }
/// <summary>
/// 当前状态
/// </summary>
public IState CurrentState { get; private set; }
public Dictionary<StateEnum, IState> statesDict = new();
/// <summary>
/// 添加状态
/// </summary>
/// <param name="stateId"></param>
/// <param name="state"></param>
public void AddState(StateEnum stateId, IState state) {
if (!statesDict.TryAdd(stateId, state)) // 键若存在,则覆盖
{
statesDict[stateId] = state;
}
}
/// <summary>
/// 切换状态
/// </summary>
/// <param name="stateID">状态ID,即枚举中的状态类型</param>
public void SwitchState(StateEnum stateID) {
NextStateID = stateID;
if (CurrentState != null)
{
CurrentState.OnExit();
}
CurrentStateID = stateID;
CurrentState = statesDict[stateID];
CurrentState.OnEnter();
}
public void OnUpdate() {
CurrentState.OnUpdate();
}
public void OnPhysicsUpdate() {
CurrentState.OnPhysicsUpdate();
}
}
状态接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IState
{
void OnEnter();
void OnUpdate();
void OnPhysicsUpdate();
void OnExit();
}
对象池
对象池
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BufferPool
{
/// <summary>
/// 缓存池中的对象的父物体,防止物体过多显示在Hierarchy中而杂乱
/// </summary>
private GameObject _poolParentObj;
/// <summary>
/// 对象list
/// </summary>
private readonly List<GameObject> _gameObjList;
private readonly GameObject _gameObject;
private readonly bool _isCreateParent;
private readonly Transform _targetParentObj;
/// <summary>
/// 初始化缓存池,并且指定缓存池的目标父物体
/// </summary>
/// <param name="gameObj">需要放入缓存池的对象</param>
/// <param name="targetParentObj">指定缓存池对象的父物体</param>
/// <param name="isCreateParent">是否创建缓存池中对象的父物体</param>
public BufferPool(GameObject gameObj, Transform targetParentObj = null, bool isCreateParent = true) {
this._gameObject = gameObj;
this._gameObjList = new List<GameObject>();
this._isCreateParent = isCreateParent;
this._targetParentObj = targetParentObj;
if (isCreateParent)
{
// 创建缓存池中对象的父物体
this._poolParentObj = new GameObject(gameObj.name);
//_poolParentObj.transform.SetPositionAndRotation(Vector3.zero, Quaternion.Euler(Vector3.zero));
}
if (targetParentObj != null && isCreateParent)
// 将缓存池整体的父物体设为指定物体
_poolParentObj.transform.parent = targetParentObj;
}
/// <summary>
/// 将对象放回缓存池
/// </summary>
/// <param name="currentGameObj">目标缓存池对象</param>
public void PutToPool(GameObject currentGameObj) {
_gameObjList.Add(currentGameObj);
currentGameObj.SetActive(false);
//currentGameObj.transform.SetParent(null);
}
/// <summary>
/// 从缓存池获取对象
/// </summary>
/// <returns>缓存对象</returns>
public GameObject GetToPool(bool isActiveObj) {
GameObject gameObj = null;
// 当前对象list是否有对象,有则取并从list移除,无则创建
if (_gameObjList.Count > 0)
{
gameObj = _gameObjList[0];
_gameObjList.RemoveAt(0);
}
else
{
gameObj = GameObject.Instantiate<GameObject>(this._gameObject);
}
// 是否获取时激活
if (isActiveObj)
gameObj.SetActive(true);
// 是否创建缓存池中对象的父物体
if (this._isCreateParent)
gameObj.transform.SetParent(this._poolParentObj.transform);
else
gameObj.transform.SetParent(this._targetParentObj);
return gameObj;
}
}
对象池管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BufferPoolMgr : SingletonBase<BufferPoolMgr>
{
/// <summary>
/// key: 缓存池的对象名
/// value: 对应的缓存池对象
/// 存储多个缓存池
/// </summary>
private readonly Dictionary<string, BufferPool> _poolDic = new Dictionary<string, BufferPool>();
/// <summary>
/// 初始化单个对象池并放入字典,让管理器来管理
/// </summary>
/// <param name="poolName">缓存池对象名</param>
/// <param name="gameObject">缓存池对象</param>
/// <param name="targetParentObj">缓存池对象在Hierarchy的父节点</param>
public void Init(string poolName, GameObject gameObject, Transform targetParentObj = null, bool isCreateParent = true) {
// if (!_poolDic.ContainsKey(poolName)) { // 判断是否存在
_poolDic[poolName] = new BufferPool(gameObject, targetParentObj, isCreateParent);
// }
}
/// <summary>
/// 从指定的缓存池中获取对象
/// </summary>
/// <param name="poolName">缓存池的名称</param>
/// <param name="isActiveObj">是否激活对象,是-在获取时同时激活对象,否则交给外部激活</param>
/// <returns>缓存池对象</returns>
public GameObject GetToPools(string poolName,bool isActiveObj = true) {
GameObject gameObj = null;
gameObj = _poolDic[poolName].GetToPool(isActiveObj); // 直接获取对象,缓存池类中会有空判断
return gameObj;
}
/// <summary>
/// 将对象放入指定对象池
/// </summary>
/// <param name="poolName">指定缓存池</param>
/// <param name="gameObject">使用完的缓存池对象</param>
public void PutToPools(string poolName, GameObject gameObject) {
if (_poolDic.ContainsKey(poolName)) { // 判断这个缓存池是否存在,不存在则Init创建
_poolDic[poolName].PutToPool(gameObject);
//Debug.Log($"key:{poolName}存在,放入池中");
}
else {
this.Init(poolName, gameObject);
}
}
/// <summary>
/// 清除缓存池
/// </summary>
public void ClearPool() {
this._poolDic.Clear();
}
}
UI管理器
UI基类
using System.Collections.Generic;
using TMPro;
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// UI Panel基类
/// 提供了快速查找和获取UI组件的功能,方便面板的显示和隐藏。
/// </summary>
public class UIPanelBase : MonoBehaviour
{
/// <summary>
/// 找到自身的所有的子控件
/// 定义了一个Dictionary类型的变量,根据控件名称存储对应的控件组件,
/// 其中控件组件以List类型存储,是为了允许同一个控件名对应多个控件组件,比如同一个面板有多个按钮。
/// </summary>
private Dictionary<string, List<UIBehaviour>> _controlDict = new Dictionary<string, List<UIBehaviour>>();
protected virtual void Awake() {
// 获取所有子控件
FindControlsInChildren<Text>();
FindControlsInChildren<Image>();
FindControlsInChildren<RawImage>();
FindControlsInChildren<Button>();
FindControlsInChildren<Slider>();
FindControlsInChildren<Toggle>();
FindControlsInChildren<ScrollRect>();
FindControlsInChildren<TextMeshProUGUI>();
FindControlsInChildren<TMP_Dropdown>();
FindControlsInChildren<TMP_InputField>();
}
/// <summary>
/// 在子对象中查找指定类型的控件,并将它们添加到控件字典中
/// 该方法通过泛型参数T来查找指定类型的控件,并将它们添加到控件字典中。
/// 在查找控件时使用了GetComponentsInChildren方法,它会在所有子对象中查找指定类型的控件。
/// 如果控件名称在控件字典中已存在,则将该控件添加到对应的控件列表中,否则创建一个新的控件列表,并将该控件添加到列表中。
/// </summary>
/// <typeparam name="T">控件类型</typeparam>
private void FindControlsInChildren<T>() where T : UIBehaviour
{
T[] controls = GetComponentsInChildren<T>(true);
foreach (T control in controls)
{
string controlName = control.gameObject.name;
//在字典_controlDict中尝试通过控件名称(controlName)获取对应的列表(value),
//如果存在该名称的列表,则将该控件(control)添加到该列表中
if (_controlDict.TryGetValue(controlName, out var value))
{
value.Add(control);
}
else
{
_controlDict.Add(controlName, new List<UIBehaviour>() { control });
}
//如果是按钮控件
if(control is Button)
{
(control as Button).onClick.AddListener(()=>
{
OnClick(controlName);
});
}
//如果是单选框或者多选框
else if(control is Toggle)
{
(control as Toggle).onValueChanged.AddListener((value) =>
{
OnValueChanged(controlName, value);
});
}
}
}
/// <summary>
/// 获取指定名称的控件
/// 该方法用于根据控件名称和控件类型获取对应的控件对象。
/// 首先判断控件字典中是否包含指定的控件名称,如果包含则遍历该名称对应的控件列表,
/// 找到第一个类型符合的控件对象,然后返回该对象。如果找不到符合要求的控件,则返回null。
/// </summary>
/// <typeparam name="T">控件类型</typeparam>
/// <param name="controlName">控件名称</param>
/// <returns>指定名称的控件,如果不存在则返回null</returns>
public T GetControl<T>(string controlName) where T : UIBehaviour
{
if (_controlDict.ContainsKey(controlName))
{
List<UIBehaviour> controls = _controlDict[controlName];
foreach (UIBehaviour control in controls)
{
if (control is T t)
{
return t;
}
}
}
return null;
}
protected virtual void OnClick(string btnName)
{
}
protected virtual void OnValueChanged(string toggleName, bool value)
{
}
/// <summary>
/// 显示自己
/// </summary>
public virtual void Show()
{
gameObject.SetActive(true);
}
/// <summary>
/// 隐藏自己
/// </summary>
public virtual void Hide()
{
gameObject.SetActive(false);
}
}
UI管理器
using System.Collections.Generic;
using System.Resources;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// UI层级枚举
/// </summary>
public enum UILayer_Enum
{
Bottom, // 底层
Middle, // 中间层
Top, // 顶层
System // 系统层
}
/// <summary>
/// UI管理器
/// </summary>
public class UIManager : SingletonBase<UIManager>
{
/// <summary>
/// 存储所有已经创建的UI面板的字典
/// </summary>
public Dictionary<string, UIPanelBase> panelDict = new Dictionary<string, UIPanelBase>();
// UI层级的父级Transform
/// <summary>
/// 底层父物体
/// </summary>
private Transform _bottomLayer;
/// <summary>
/// 中层父物体
/// </summary>
private Transform _middleLayer;
/// <summary>
/// 顶层父物体
/// </summary>
private Transform _topLayer;
/// <summary>
/// 系统层父物体
/// </summary>
private Transform _systemLayer;
/// <summary>
/// 记录UI的Canvas父对象,方便外部使用
/// </summary>
public RectTransform canvas;
public UIManager() {
// 创建Canvas,场景切换时不销毁
GameObject canvasObj = Resources.Load<GameObject>("UI/Canvas");
canvas = canvasObj.transform as RectTransform;
GameObject.DontDestroyOnLoad(canvasObj);
//找到各层级
_bottomLayer = canvas.Find("Bottom");
_middleLayer = canvas.Find("Middle");
_topLayer = canvas.Find("Top");
_systemLayer = canvas.Find("System");
//创建EventSystem,场景切换时不销毁
GameObject eventSystem = Resources.Load<GameObject>("UI/EventSystem");
GameObject.DontDestroyOnLoad(eventSystem);
}
/// <summary>
/// 根据层级枚举获取对应层级的父物体
/// </summary>
/// <param name="layerEnum">层级</param>
/// <returns>对应层级的父物体</returns>
public Transform GetLayerFather(UILayer_Enum layerEnum) {
switch (layerEnum)
{
case UILayer_Enum.Bottom:
return _bottomLayer;
case UILayer_Enum.Middle:
return _middleLayer;
case UILayer_Enum.Top:
return _topLayer;
case UILayer_Enum.System:
return _systemLayer;
}
return null;
}
/// <summary>
/// 显示/创建UI面板
/// 传入面板名“panelName ',UI层级“layer`和一个可选的回调函数`callBack"。
/// 如果已经加载过该面板,则直接显示面板;否则,异步加载面板预设体并显示。
/// </summary>
/// <typeparam name="T">面板脚本类型</typeparam>
/// <param name="panelName">面板名称</param>
/// <param name="layerEnum">显示在哪一层级</param>
/// <param name="callBack">面板预制体创建成功后的回调</param>
public void ShowPanel<T>(string panelName, UILayer_Enum layerEnum = UILayer_Enum.Middle, UnityAction<T> callBack = null) where T : UIPanelBase
{
// 如果已经存在该面板,则直接显示
if (panelDict.ContainsKey(panelName))
{
// 处理面板创建完成后的回调逻辑
panelDict[panelName].Show();
callBack?.Invoke(panelDict[panelName] as T);
return;
}
//异步加载面板预制体
GameObject obj = Resources.Load<GameObject>("UI/" + panelName);
// 在回调中设置新加载的面板
// 设置父对象及其相对位置和大小
Transform parent = GetLayerFather(layerEnum);
obj.transform.SetParent(parent);
obj.transform.localPosition = Vector3.zero;
obj.transform.localScale = Vector3.one;
(obj.transform as RectTransform).offsetMax = Vector2.zero;
(obj.transform as RectTransform).offsetMin = Vector2.zero;
// 得到预制体上的UIPanelBase脚本
T panel = obj.GetComponent<T>();
// 执行面板创建完成后的回调
callBack?.Invoke(panel);
// 显示面板
panel.Show();
// 存入面板字典
panelDict.Add(panelName, panel);
}
/// <summary>
/// 隐藏面板,根据传入的isDestroy判断是否销毁面板
/// </summary>
/// <param name="panelName">要隐藏的面板的名称</param>
/// <param name="isDestroy">是否销毁面板</param>
public void HidePanel(string panelName,bool isDestroy = true) {
// 检查面板是否存在
if (panelDict.ContainsKey(panelName))
{
// 调用面板的 HideMe() 方法进行隐藏
panelDict[panelName].Hide();
// 是否销毁面板
if (isDestroy)
{
GameObject.Destroy(panelDict[panelName].gameObject);
// 从字典中移除该面板
panelDict.Remove(panelName);
}
}
}
/// <summary>
/// 获取已显示的面板
/// </summary>
/// <typeparam name="T">面板脚本类型,必须是 UIPanelBase 的子类</typeparam>
/// <param name="name">要获取的面板的名称</param>
/// <returns>面板脚本,返回指定类型的 UIPanelBase 对象</returns>
public T GetPanel<T>(string name) where T : UIPanelBase {
// 检查面板是否存在
if (panelDict.ContainsKey(name))
// 如果面板存在,将其转换为 T 类型并返回
return panelDict[name] as T;
// 如果面板不存在,返回 null
return null;
}
}
AB包管理器
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
public class AssetBundleManager : SingletonMonoBase<AssetBundleManager>
{
/// <summary>
/// 存储所有加载过的资源包
/// </summary>
private Dictionary<string, AssetBundle> assetBundleDict = new Dictionary<string, AssetBundle>();
/// <summary>
/// 主资源包,只加载一次
/// </summary>
private AssetBundle _mainAssetBundle;
/// <summary>
/// 依赖配置文件
/// </summary>
private AssetBundleManifest _manifest;
/// <summary>
/// 资源包存放路径
/// </summary>
private string AssetBundlePath => Application.streamingAssetsPath + "/";
/// <summary>
/// 主资源包名称,根据平台不同而不同
/// </summary>
private string MainAssetBundleName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "PC";
#endif
}
}
#region 同步加载资源
/// <summary>
/// 同步加载资源,三种方法重载
/// </summary>
/// <param name="assetBundleName">资源包名称</param>
/// <param name="resourceName">资源名称</param>
public Object LoadResource(string assetBundleName, string resourceName) {
LoadAssetBundle(assetBundleName);
Object obj = assetBundleDict[assetBundleName].LoadAsset(resourceName);
if (obj is GameObject)
return Object.Instantiate(obj);
else
return obj;
}
public Object LoadResource(string assetBundleName, string resourceName, Type type) {
LoadAssetBundle(assetBundleName);
Object obj = assetBundleDict[assetBundleName].LoadAsset(resourceName, type);
if (obj is GameObject)
return Object.Instantiate(obj);
else
return obj;
}
public T LoadResource<T>(string assetBundleName, string resourceName) where T : Object {
LoadAssetBundle(assetBundleName);
T t = assetBundleDict[assetBundleName].LoadAsset<T>(resourceName);
if (t is GameObject)
return Object.Instantiate(t);
else
return t;
}
#endregion
#region 异步加载资源
/// <summary>
/// 异步加载资源,三种方法重载
/// 这个函数用于异步加载资源,参数包括资源包名称、资源名称和回调函数。
/// 它使用了协程并调用了另一个函数ReallyLoadResourceAsync来实现异步加载。
/// 该函数使用StartCoroutine方法来开启一个协程,并传入了参数assetBundleName,resourceName和callback。
/// </summary>
/// <param name="assetBundleName">资源包名称</param>
/// <param name="resourceName">资源名称</param>
/// <param name="callback">回调函数</param>
/// <returns></returns>
public void LoadResourceAsync(string assetBundleName, string resourceName, Action<Object> callback) {
// 调用私有方法 ReallyLoadResourceAsync 来完成异步加载资源的操作
StartCoroutine(ReallyLoadResourceAsync(assetBundleName, resourceName, callback));
}
/// <summary>
/// 用于实际的异步加载资源操作。它使用yield return StartCoroutine方法来等待资源包加载完成。
/// 然后,它使用LoadAssetAsync方法异步加载资源,并等待请求完成。
/// 最后,如果资源是GameObject,将其实例化并传递给回调函数,否则直接传递资源。
/// </summary>
/// <param name="assetBundleName">资源包名称</param>
/// <param name="resourceName">资源名称</param>
/// <param name="callback">回调函数</param>
/// <returns></returns>
private IEnumerator ReallyLoadResourceAsync(string assetBundleName, string resourceName, Action<Object> callback) {
// 调用 LoadAssetBundleAsync 异步加载 AssetBundle
yield return StartCoroutine(LoadAssetBundleAsync(assetBundleName));
// 加载 AssetBundle 中的资源
AssetBundleRequest request = assetBundleDict[assetBundleName].LoadAssetAsync(resourceName);
// 等待资源加载完成
yield return request;
// 如果加载的资源是 GameObject,则实例化一个新的 GameObject,并传给回调函数
// 否则直接将加载的资源传给回调函数
if (request.asset is GameObject)
callback(Object.Instantiate(request.asset));
else
callback(request.asset);
}
/// <summary>
/// LoadResourceAsync的重载,接受一个类型参数
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="resourceName"></param>
/// <param name="type"></param>
/// <param name="callback"></param>
public void LoadResourceAsync(string assetBundleName, string resourceName, System.Type type,
Action<Object> callback) {
// 调用私有方法 ReallyLoadResourceAsync 来完成异步加载资源的操作
StartCoroutine(ReallyLoadResourceAsync(assetBundleName, resourceName, type, callback));
}
/// <summary>
/// ReallyLoadResourceAsync重载
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="resourceName"></param>
/// <param name="type"></param>
/// <param name="callback"></param>
/// <returns></returns>
private IEnumerator ReallyLoadResourceAsync(string assetBundleName, string resourceName, System.Type type,
Action<Object> callback) {
// 调用 LoadAssetBundleAsync 异步加载 AssetBundle
yield return StartCoroutine(LoadAssetBundleAsync(assetBundleName));
// 加载 AssetBundle 中指定类型的资源
AssetBundleRequest request = assetBundleDict[assetBundleName].LoadAssetAsync(resourceName, type);
// 等待资源加载完成
yield return request;
// 如果加载的资源是 GameObject,则实例化一个新的 GameObject,并传给回调函数
// 否则直接将加载的资源传给回调函数
if (request.asset is GameObject)
callback(Object.Instantiate(request.asset));
else
callback(request.asset);
}
/// <summary>
/// LoadResourceAsync 重载
/// 这个函数使用了泛型来加载资源,它还接受了类型参数。它也使用了协程,并调用了另一个函数ReallyLoadResourceAsync T。
/// 该函数使用了StartCoroutine方法来开启一个协程,并传入了参数assetBundleName,resourceName和callback。
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="resourceName"></param>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
public void LoadResourceAsync<T>(string assetBundleName, string resourceName, Action<T> callback) where T : Object {
// 调用私有方法 ReallyLoadResourceAsync 来完成异步加载资源的操作
StartCoroutine(ReallyLoadResourceAsync<T>(assetBundleName, resourceName, callback));
}
/// <summary>
/// ReallyLoadResourceAsync 泛型重载
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="resourceName"></param>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private IEnumerator ReallyLoadResourceAsync<T>(string assetBundleName, string resourceName, Action<T> callback)
where T : Object {
// 调用 LoadAssetBundleAsync 异步加载 AssetBundle
yield return StartCoroutine(LoadAssetBundleAsync(assetBundleName));
// 加载 AssetBundle 中指定类型的资源
AssetBundleRequest request = assetBundleDict[assetBundleName].LoadAssetAsync<T>(resourceName);
// 等待资源加载完成
yield return request;
// 如果加载的资源是 GameObject,则实例化一个新的 GameObject,并传给回调函数
// 否则直接将加载的资源传给回调函数
if (request.asset is GameObject)
callback(GameObject.Instantiate(request.asset) as T);
else
callback(request.asset as T);
}
#endregion
/// <summary>
/// 同步加载资源包
/// </summary>
/// <param name="assetBundleName">资源包名称</param>
private void LoadAssetBundle(string assetBundleName) {
if (_mainAssetBundle == null)
{
_mainAssetBundle = AssetBundle.LoadFromFile(AssetBundlePath + MainAssetBundleName);
_manifest = _mainAssetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
string[] dependencies = _manifest.GetAllDependencies(assetBundleName);
for (int i = 0; i < dependencies.Length; i++)
{
if (!assetBundleDict.ContainsKey(dependencies[i]))
{
assetBundleDict.Add(dependencies[i], AssetBundle.LoadFromFile(AssetBundlePath + dependencies[i]));
}
}
if (!assetBundleDict.ContainsKey(assetBundleName))
{
assetBundleDict.Add(assetBundleName, AssetBundle.LoadFromFile(AssetBundlePath + assetBundleName));
}
}
/// <summary>
/// 异步加载资源包
/// </summary>
/// <param name="assetBundleName">资源包名称</param>
/// <returns></returns>
private IEnumerator LoadAssetBundleAsync(string assetBundleName) {
if (_mainAssetBundle == null)
{
AssetBundleCreateRequest abCreateRequest =
AssetBundle.LoadFromFileAsync(AssetBundlePath + MainAssetBundleName);
yield return abCreateRequest;
_mainAssetBundle = abCreateRequest.assetBundle;
AssetBundleRequest abRequest = _mainAssetBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
yield return abRequest;
_manifest = abRequest.asset as AssetBundleManifest;
}
string[] dependencies = _manifest.GetAllDependencies(assetBundleName);
for (int i = 0; i < dependencies.Length; i++)
{
if (!assetBundleDict.ContainsKey(dependencies[i]))
{
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(AssetBundlePath + dependencies[i]);
yield return request;
assetBundleDict.Add(dependencies[i], request.assetBundle);
}
}
if (!assetBundleDict.ContainsKey(assetBundleName))
{
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(AssetBundlePath + assetBundleName);
yield return request;
assetBundleDict.Add(assetBundleName, request.assetBundle);
}
}
/// <summary>
/// 卸载单个资源包
/// </summary>
/// <param name="assetBundleName">资源包名称</param>
public void UnloadAssetBundle(string assetBundleName) {
if (assetBundleDict.ContainsKey(assetBundleName))
{
assetBundleDict[assetBundleName].Unload(false);
assetBundleDict.Remove(assetBundleName);
}
}
/// <summary>
/// 卸载所有资源包
/// </summary>
public void Clear() {
AssetBundle.UnloadAllAssetBundles(false);
assetBundleDict.Clear();
_mainAssetBundle = null;
_manifest = null;
}
}
特效管理器
/// <summary>
/// 特效管理器,配合缓存池,将特效生成到目标位置,特效播放结束后收回到缓存池中
/// </summary>
public class EffectMgr1: MonoBehaviour
{
/// <summary>
/// 偏移位置,挂载到特效上设置即可
/// </summary>
public Vector2 offsetPos;
private Animator _animator;
private string _poolName = null;
/// <summary>
/// updateEvent
/// </summary>
public UnityAction updateHandler;
protected virtual void Awake() {
_animator = this.GetComponent<Animator>();
}
protected virtual void Update() {
updateHandler?.Invoke();
if (this._poolName is not null)
{
if (_animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1)
{
BufferPoolMgr.Instance.PutToPools(this._poolName, this.gameObject);
}
}
}
public virtual void Init(Vector2 targetPos) {
this.transform.position = targetPos + offsetPos;
this.gameObject.SetActive(true);
}
/// <summary>
/// 指定特效生成的位置,并激活
/// </summary>
/// <param name="targetPos">目标位置</param>
/// <param name="poolName">缓存池名称</param>
public virtual void Init(Vector2 targetPos, string poolName) {
this._poolName = poolName;
this.transform.position = targetPos + offsetPos;
this.gameObject.SetActive(true);
}
}
音效管理器
public class AudioManager : SingletonMonoBase<AudioManager>
{
// 音效依附对象
private GameObject _audioSourceObj = null;
// 音效字典
private Dictionary<string, AudioSource> _audioDict = new();
private void Start() {
_audioSourceObj = this.gameObject;
}
/// <summary>
/// 播放音效
/// </summary>
public void PlayAudio(string audioClipPath, string audioName, bool isLoop = false, float volume = 1, UnityAction<AudioSource> callBack = null)
{
if(_audioSourceObj == null)
{
_audioSourceObj = new GameObject();
_audioSourceObj.name = "Sound";
}
if (_audioDict.TryGetValue(audioName, out var value))
{
value.Play();
return;
}
// 资源加载并初始化
var audioClip = AssetDatabase.LoadAssetAtPath<AudioClip>($"Assets/Arts/AudioClip/{audioClipPath}/{audioName}.wav");
AudioSource audioSource = _audioSourceObj.AddComponent<AudioSource>();
audioSource.clip = audioClip;
audioSource.loop = isLoop;
audioSource.volume = volume;
audioSource.Play();
_audioDict.Add(audioName, audioSource);
}
/// <summary>
/// 改变音效声音大小
/// </summary>
/// <param name="audioName"></param>
/// <param name="volume"></param>
public void ChangeSoundValue(string audioName, float volume)
{
_audioDict[audioName].volume = volume;
}
/// <summary>
/// 停止音效
/// </summary>
public void PauseAudio(string audioName)
{
if( _audioDict.TryGetValue(audioName, out var value) )
{
value.Stop();
}
}
}
洗牌工具类
public class ShuffleQueue<T>
{
//存储元素
private Queue<T> _sequence;
// 存储上次打乱顺序的元素
private List<T> _lastShuffled;
private Random _random;
// 构造函数,接受一个 IEnumerable<T> 类型的参数来初始化队列
public ShuffleQueue(IEnumerable<T> data) {
_sequence = new Queue<T>(data);
_lastShuffled = new List<T>();
_random = new Random();
}
// 定义一个 GetNext 方法用于取出并删除队首元素
public T GetNext() {
// 如果队列为空,则调用 Shuffle 方法来打乱顺序并重新填充队列
if (_sequence.Count == 0)
Shuffle();
// 取出并删除队首元素
T next = _sequence.Dequeue();
// 将取出的元素添加到上次打乱顺序的元素列表中
_lastShuffled.Add(next);
return next;
}
// 定义一个 Shuffle 方法用于打乱顺序并重新填充队列
private void Shuffle() {
// 获取上次打乱顺序的元素列表的元素个数
int count = _lastShuffled.Count;
// 获取上次打乱顺序的末尾元素
T lastElement = _lastShuffled[count - 1];
// 使用 Knuth-Durstenfeld Shuffle算法来随机打乱临时列表中的元素顺序
do
{
for (int i = count - 1; i > 0; i--)
{
int randomIndex = _random.Next(0, count);
// 使用元组进行析构交换元素
(_lastShuffled[randomIndex], _lastShuffled[i]) = (_lastShuffled[i], _lastShuffled[randomIndex]);
}
// 检查随机打乱后的首位元素是否与上次打乱顺序的末尾元素相同,如果相同,则重新打乱顺序
} while (_lastShuffled[0].Equals(lastElement));
// 将临时列表中的元素依次添加到队列中
foreach (T item in _lastShuffled)
{
_sequence.Enqueue(item);
}
// 清空上次打乱顺序的元素列表
_lastShuffled.Clear();
}
}
文章来源:https://www.toymoban.com/news/detail-516311.html
到了这里,关于Unity常用基础框架的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!