kizumi_header_banner_img

Hello! Beautiful Kizumi!

加载中

文章导读

Unity程序基础框架


avatar
Yuyas 2025年12月19日 5

**不继承MonoBehavior的单例模式基类**…

**继承MonoBehavior的单例模式基类**

自动挂载版:

“`c#
public class SingletonMonoAuto : MonoBehaviour where T : SingletonMonoAuto
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
GameObject obj = new GameObject();
obj.name = typeof(T).ToString();
instance = obj.AddComponent();
}
return instance;
}
}
}
“`

**[安全问题] 单例模式唯一性 – 构造函数**

针对非Mono

因为继承MonoBehaviour的类本身就不能被new,所以这里主要说不继承的单例基类

1.将基类设置成抽象类,则基类不能被new

2.将子类设置一个private构造器

3.基类用反射来获取构造器创建实例,因为步骤2不再能使用new

“`c#
public class Singleton where T : class
{
private static T instance;
public static T Instance
{
get
{
if(instance == null)
{
ConstructorInfo info = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,
null,
Type.EmptyTypes,
null);
if (info != null)
instance = info.Invoke(null) as T;
else
Debug.LogError(“不存在private私有构造器”);
}
return instance;
}
}
}
“`

**[安全问题] 单例模式唯一性 – 重复挂载**

针对挂载Mono

[DisallowMultipleComponent]

同一物体上不能挂载多个组件,不能根治(不常用)

在awake获取instance前判空即可

“`c#
if(instance != null)
{
Destory(this); // 销毁多余组件
return;
}
“`

**[安全问题] 单例模式线程安全 – 是否加锁**

针对非Mono

继承Mono的类不允许使用多线程

**公共Mono模块**

作用:

1.通过事件或委托,让不继承MonoBehaviour的脚本也能进行相关生命周期函数更新

2.为不继承MonoBehaviour的脚本提供协同程序开启或关闭的方法

3.统一管理帧更新等相关逻辑,提高性能

**缓存池(对象池)模块**

分为柜子(Dictionary),抽屉(List,Stack,Queue等)容器

方法:

public GameObject GetObj(string name)

public void PushObj(GameObject obj)

public void ClearPoor()

– 窗口布局优化

使用静态变量 public static bool isOpenLayout = true;

若为true,在每个对象首次初始化创建其根对象

在子对象失活时移入根对象,在子对象激活时移除根对象

– 对象上限优化

在GetObj方法中加入可选参数MaxUsedObject设置最大激活物体上限

协同开发时为统一上限,可以为每个Perfab单独挂载一个脚本用于设置最大上限,在PoolMgr中获取并在没有挂载时LogError

“`c#
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class PoolData
{
public Stack stk = new Stack();
public List usedList = new List();

private GameObject dataRoot;
public int Count => stk.Count;
public int UsedCount => usedList.Count;

public void SetDataRootParent(GameObject obj)
{
if (dataRoot == null) dataRoot = new GameObject();
dataRoot.transform.SetParent(obj.transform);
}

public void SetDataRootName(string name)
{
if (dataRoot == null) dataRoot = new GameObject();
dataRoot.name = name;
}

public GameObject Pop()
{
GameObject obj;

if (Count > 0)
{
obj = stk.Pop();
}
else
{
obj = usedList[0];
usedList.RemoveAt(0);
}

usedList.Add(obj);

if(PoolMgr.isOpenLayout)
obj.transform.SetParent(null);

return obj;
}

public void Push(GameObject obj)
{
if (PoolMgr.isOpenLayout)
obj.transform.SetParent(dataRoot.transform);

stk.Push(obj);
usedList.Remove(obj);
}
}

public class PoolMgr : Singleton
{
public static bool isOpenLayout = true;

private PoolMgr()
{
if(PoolMgr.isOpenLayout)
{
poolRoot = new GameObject();
poolRoot.name = “Pool”;
}
}

public Dictionary dic = new Dictionary();

private GameObject poolRoot;

public GameObject GetObj(string name, int maxUsedObject = 50)
{
GameObject obj;

if(dic.ContainsKey(name) && (dic[name].UsedCount > maxUsedObject || dic[name].Count > 0))
{
obj = dic[name].Pop();
obj.name = name;
obj.SetActive(true);
}
else
{
if (!dic.ContainsKey(name))
{
// 如果没有抽屉,创建抽屉
PoolData data = new PoolData();
if (PoolMgr.isOpenLayout)
{
data.SetDataRootParent(poolRoot);
data.SetDataRootName(name);
}
dic.Add(name, data);
}
// 实例化新对象
Debug.Log(dic[name].UsedCount);
obj = GameObject.Instantiate(Resources.Load(name));
obj.name = name;
dic[name].usedList.Add(obj);
}

return obj;
}

public void PushObj(GameObject obj)
{
if (PoolMgr.isOpenLayout)
if (poolRoot == null)
{
poolRoot = new GameObject();
poolRoot.name = “Pool”;
}

obj.SetActive(false);

dic[obj.name].Push(obj);
}

public void ClearPoor()
{
dic.Clear();

if (PoolMgr.isOpenLayout)
poolRoot = null;
}
}
“`

**事件中心模块**

通过一个中心化机制,使多个系统,模块,对象之间进行==松耦合通信==,再结合观察者设计模式构成了事件中心模块

使用private Dictionary dic;

方法:

AddEventListener(string eventName, UnityAction func)

RemoveEventListener(string eventName, UnityAction func)

Clear()

Clear(string eventName)

传参优化:

– 使用UnityAction替代无参UnityAction作为字典的值,在使用时转化为所需要的参数即可;

– 缺点:在值和引用类型转化的过程中存在==装箱拆箱,浪费性能==,因此不推荐使用
– 自定义一个抽象EventInfoBase类作为父类(目的是可以创建多个自定义个参数的EventInfo封装UnityAction来使用),取代字典中的UnityAction(在创建字典时==确定了委托参数类型,避免了装箱拆箱==)

– public class EventInfo : EventInfoBase 作无参数UnityAction的封装
– public class EventInfo : EventInfoBase 作一参数UnityAction的封装

事件名优化:

– 使用枚举类型来代替字符串传入参数名和字典查询事件

“`c#
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public abstract class EventInfoBase { };

public class EventInfo : EventInfoBase
{
public UnityAction actions;

public EventInfo() { }

public EventInfo(UnityAction func)
{
actions += func;
}
}

public class EventInfo : EventInfoBase
{
public UnityAction actions;

public EventInfo() { }

public EventInfo(UnityAction func)
{
actions += func;
}
}

public class EventCenter : Singleton
{
private EventCenter() { }

private Dictionary dic = new Dictionary();

#region 一参数委托
public void EventTrigger(string eventName, T info)
{
if (dic.ContainsKey(eventName))
{
(dic[eventName] as EventInfo).actions?.Invoke(info);
}
}

public void AddEventListener(string eventName, UnityAction func)
{
if (!dic.ContainsKey(eventName))
dic.Add(eventName, new EventInfo());
(dic[eventName] as EventInfo).actions += func;
}

public void RemoveEventListener(string eventName, UnityAction func)
{
if (dic.ContainsKey(eventName))
{
(dic[eventName] as EventInfo).actions -= func;
}
}
#endregion

#region 无参数委托
public void EventTrigger(string eventName)
{
if(dic.ContainsKey(eventName))
{
(dic[eventName] as EventInfo).actions?.Invoke();
}
}

public void AddEventListener(string eventName, UnityAction func)
{
if (!dic.ContainsKey(eventName))
dic.Add(eventName, new EventInfo());
(dic[eventName] as EventInfo).actions += func;
}

public void RemoveEventListener(string eventName, UnityAction func)
{
if (dic.ContainsKey(eventName))
{
(dic[eventName] as EventInfo).actions -= func;
}
}
#endregion

public void Clear()
{
dic.Clear();
}

public void Clear(string eventName)
{
if(dic.ContainsKey(eventName))
{
dic.Remove(eventName);
}
}
}

“`

**资源加载模块**



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码

个人信息

avatar

24
文章
1
评论
1
用户

近期文章