Unity知识点概要
1.脚本完整声明周期Awake OnEnable Start Update FixedUpdate LateUpdate OnGUI OnDisable OnDestroy2.更新函数Update逻辑帧执行次数取决于运行电脑的帧率。FixedUpdate渲染帧每0.02s执行一次一般进行物理模拟计算跟随每帧渲染可以调整执行的时间间隔。注例如在联机游戏中我们希望不同的玩家无论使用什么样的电脑所产生的物理效果是一致的比如《人类一败涂地》等游戏。LateUpdate在所有Update执行完成后调用一般处理摄像头移动等依赖其他对象逻辑。3.初始化函数Awake在脚本整个生命周期active true调用一次一般用来设置脚本间的引用。Start在对象第一次被激活activeenable true因此可以延迟调用控制激活时间在Awake后第一帧前会触发。OnEnable在每次对象被激活或脚本active/enabled true被启动时调用。每一次调用都会触发4.动态资源加载方式AssetBundle将资源打包成独立.assetbundle文件存放本地或者服务器运行时加载。Addressable支持热更新自动处理依赖。Resource.Load通过固定路径直接加载资源。GameObject itemPrefab Resources.LoadGameObject(resourcePath);5.四元数与欧拉角欧拉角直观unity编辑器中使用的旋转方式是以欧拉角的方式呈现但是欧拉角存在万向死锁问题和插值错误的不可避免的问题。四元数不直观但能解决欧拉角的问题。万向死锁问题旋转时xyz需要有先后顺序不然变换的结果不一当旋转时可能出现轴重合。变换不存在过程只有初始与结果例如先绕x轴旋转10°再绕y轴旋转90°最后绕x轴旋转35°但是因为不存在过程因此实际计算是先绕x轴旋转45°最后绕y轴旋转90°。注Transform组件里的Rotation是四元数但是以欧拉角Vector3的形式展现的。6.Cnaves渲染模式Screen Space-Overlay与摄像机无关显示在屏幕的2D空间且永远在3D物体前面渲染。Screen Space-Camera指定一个摄像机UI会渲染在相机的投射范围内。World SpaceUI相当于场景中的一个物品可以在场景中随意移动位置。注World Space可以用作敌人血条显示或者VR开发等。7.Cnaves Scaler 的 UI 缩放模式Constant Pixel Size保持UI自身像素大小1Pixel不变。Scale With Screen Size根据指定比例显示在屏幕上。Constant Physical Size使UI元素保持物理单位厘米英寸等大小不变。注1.Constant Pixel Size与Constant Physical Size都是与屏幕分辨率无关。2.UI在不同分辨率下的一致性需要考虑UI的位置与尺寸因此使用Rect Transfrom的锚点位置与Cnaves Scaler组件的Scale With Screen Size模式。8.UGUI布局1锚点Anchors与轴心Pivot锚点四个值小三角分别表示相对于父物体左下角的比例相对于父容器的缩放比例与位置。理解可以将父容器左下角看作原点若Min与Max中X或Y相同例如Min X与Max X都为0.6则不随父容器缩放只是位置会发生改变是相对父容器比例的位置。若Min与Max中X或Y不相同也就是三角分开可以看右下角图片每个小三角都与本身缩放蓝点呈现映射关系。轴心定义元素自身旋转与缩放中心可以理解为绕轴旋转与缩放。2布局组件Horizontal / Vertical Layout Group自动排列子元素。Content Size Fitter根据内容动态调整大小。Aspect Ratio Fitter保持宽高比。9.协程本质运行在主线程之上通过迭代器实现模拟异步行为协程之间是顺序执行而不是多线程并发在每帧update之后检查yied条件是否满足通过yield return暂停协程后主线程继续处理其他操作如渲染待条件满足时Unity将协程的后续代码重新加入主线程队列。协程本身不涉及多线程但能避免主线程阻塞。过程Update 协程处理 LateUpdate1.启动协程Unity会将协程的迭代器加入“待处理队列”2.每帧Unity会遍历队列中的所有协程满足条件就继续执行后续否则跳过该协程。使用方式void Start() { //启动协程 myCoroutine StartCoroutine(DelayedAction(2.0f)); //停止协程 StopCoroutine(myCoroutine); StopAllCoroutines(); } IEnumerator DelayedAction(float delayTime) { Debug.Log(协程开始将延迟 delayTime 秒); yield return new WaitForSeconds(delayTime); Debug.Log(延迟结束执行动作); }注: 1.A脚本的协程无法在B脚本中通过引用停止该协程。2.如果对象被销毁依附的协程也会停止。若不希望协程停止将其挂在例如DontDestroyOnLoad 对象等持久化对象上。3.避免频繁开启停止协程会产生GC压力。实际应用黑屏颜色渐变异步加载延迟执行生成物品等面试问题汇总yield return null 与 0 没有本质区别都是等待一帧后执行后续逻辑。协程嵌套的应用常见场景加载等待完全黑屏再执行切换场景。协程的执行顺序一般先启动先执行。10.异步加载1.基本概念作用可以在不阻塞游戏主线程的情况下加载资源。好处加载资源的同时游戏继续运行提高性能加载大型场景时可以实现平滑转换。使用方式Resources.LoadSceneAsync(index) 或者 使用Addressables工具实现。注需要使用协程来完成异步加载操作协程作为调度工具使用将耗时的I/O或计算任务交给后台线程主线程只检查进度。2.语法使用1async与awaitasync修饰方法的关键词用来编写异步代码。方法返回类型通常为void,Task,TaskT。await等待一个Task或者Awaitable对象完成期间不会阻塞主线程。2Awaitable可等待对象是一套规则await后面需要是Awaitable类型而Task是Awaitable的一种而已。3SceneManager场景管理的核心类用于加载卸载与切换场景。11.事件系统Unity事件系统委托与回调函数-CSDN博客文章浏览阅读974次点赞14次收藏11次。事件系统可以理解为有一个呼叫者【唯一性】发出一种特定的信号激活事件的函数一个或多个监听者监听它所监听信号事件注册/撤销如果匹配则监听者会实施相应动作回调函数。_unity事件系统https://blog.csdn.net/stariser/article/details/146403667?fromshareblogdetailsharetypeblogdetailsharerId146403667sharereferPCsharesourcestarisersharefromfrom_link注事件event是对委托的封装并且更加安全外部必须注册和取消订阅来触发事件12.单例模式1.分类饿汉式提前创建好线程安全与懒汉式用到才创建延迟加载2.作用只存在一个实例并提供全局唯一的访问入口。3.缺点违反了依赖倒置原则。13.六大设计原则1.单一职责原则一个类只干一件事。2.开闭原则对扩展开放对修改关闭增加而不是修改。3.里氏替换原则子类必须完全替换父类且不破坏原有逻辑。4.接口隔离原则接口需要小而专不强迫类实现用不到的方法。5.依赖倒置原则依赖抽象不依赖具体实现。6.迪米特法则一个对象应该尽量不干涉其他对象。13.垃圾回收GCUnity垃圾回收GC_unity gc.collect-CSDN博客文章浏览阅读828次点赞9次收藏5次。3装箱变量转化为object类型与拆箱变量转为基本类型可以使用.ToString使得代码编译减少装箱操作从而减少堆上内存分配。注C不支持GC需要手动管理内存使用new申请内存空间使用完后通过delete释放掉但可能出现忘记释放或者指针丢失的情况。1谨慎使用new并且避免在Update等周期函数中使用arrayclass等分配在堆上。3Unity的GC采取不压缩内存块不会从离散变连续的机制可能导致内存碎片化。3多使用对象池与Cache缓存_unity gc.collecthttps://blog.csdn.net/stariser/article/details/147769683?fromshareblogdetailsharetypeblogdetailsharerId147769683sharereferPCsharesourcestarisersharefromfrom_link14.C#特性关键词[Serializable] 序列化自定义类[SerializeField]显示私有变量到Inspector窗口[Flags]枚举组合[Header(标题文本)]可以在Inspector窗口显示文本[Range(Min,Max)]可视化并限制数值范围[ToolTip(说明文本)]代码悬停显示提示文本[RequireComponent(组件名)]强制添加组件一般写在类前15.Unity内置对象池作用1.避免频繁创建与销毁对象导致GC压力与内存碎片化。2.重复利用已经创建的对象降低CPU和内存开销。3.统一管理生成与回收避免代码冗余。使用方式var objectPool new ObjectPoolT( createFunc: () new T(), // 创建新对象的委托 actionOnGet: (obj) obj.SetActive(true), // 取出时的操作 actionOnRelease: (obj) obj.SetActive(false), // 放回时的操作 actionOnDestroy: (obj) Destroy(obj), // 销毁对象的委托 collectionCheck: true, // 防止重复放回的检查调试用 defaultCapacity: 10, // 默认池容量 maxSize: 100 // 池最大容量超限时销毁对象 ); void UsePool(){ GameObject obj objectPool.Get(); //获取对象 objectPool.Release(obj); //放回对象池 objectPool.Dispose(); //清空对象池并销毁所有对象 objectPool.Clear(); //清空对象池中空闲对象 }注此种使用匿名函数的写法需要另外有类似UsePool这样使用对象池的函数才能被其他脚本使用也可以写在冒号之后写具体函数名就可以直接使用了。actionOnGet等其实本质是委托写的函数会添加到各委托中。注意事项1.根据需求分配足够的对象给予初始容量超出最大容量自动销毁多余对象。2.激活/禁用代替销毁在获取对象时重置属性保证每个Get()都有对应的Release()。16.常见架构1MonoBehaviour 架构面向对象核心思想通过继承Mono的脚本挂载到GameObject上使得每个对象独立处理逻辑。优势小规模项目UI交互和角色操控等。劣势大量Obj的Update逐个执行导致主线程卡顿。2MVC架构核心思想数据Model显示View与逻辑Controller分离。使用方式1.Model存储玩家数据2.View处理玩家输入与数据显示3.Controller协调两者其实就是调用其中的变量与方法进行整合优势UI交互与网络同步。劣势严格的分层会导致增加代码复杂度。3Event - Driven架构核心思想通过事件解耦模块通信优势低耦合系统成就系统和音效触发等劣势过度使用会导致调试修改与困难。4分层架构核心思想按照功能划分层级。优势大型项目严格模块划分使用。17.Unity DOTSUnity DOTS-CSDN博客Unity DOTS技术栈包含Burst编译器和JobSystem两大核心。Burst可将C#代码编译为高效本地代码通过[BurstCompile]标记实现性能优化JobSystem通过多线程并行处理任务使用IJob接口定义任务配合NativeArray实现跨线程数据访问。ECS架构则包含Entity实体、Component数据和System逻辑处理三部分通过ForEach并行处理实体数据。该技术栈显著提升了Unity的性能表现特别适用于大规模数据处理场景。https://blog.csdn.net/stariser/article/details/150556773?fromshareblogdetailsharetypeblogdetailsharerId150556773sharereferPCsharesourcestarisersharefromfrom_link18.Image与RawImage1.支持资源类型Image仅支持Sprite一般用在固定形状且适配缩放的静态UI元素。RawImage支持Texture一般用在动态加载或者实时渲染的图像。2.功能特性ImageSliced边缘保持固定比例缩放Tiled平铺重复显示与Filled径向或线性填充并且不支持UV调整。RawImageUV Rect裁切或平移显示区域例如仅显示左半部分或缩放纹理的某一区域支持动态纹理网络图片。3.性能Image可与Sprite Packer图集打包结合使用可优化渲染性能与UI事件系统深度集成。RawImage轻量级直接操作原始纹理。4.材质与渲染Image使用UI/Default材质支持透明度混合和UI遮罩。RawImage使用UI/Unlit/Transparent材质支持无光照的纹理显示。注两者均可绑定自定义Shader而RawImage常用于复杂纹理例如扭曲效果。19.Unity多线程1自动多线程Job SystemBurst CompilerAddressables/AssetBundle物理引擎默认在子线程处理碰撞检测与刚体模拟。批处理导入在导入资源时Unity会使用多线程加速出力。2手动多线程自定义子线程任务void Start() { Thread thread new Thread(() { // 子线程中执行耗时操作 Debug.Log(子线程ID: Thread.CurrentThread.ManagedThreadId); }); thread.Start(); }注子线程不能调用Unity API否则会直接崩溃。Task异步编程模型async Task LoadData() { string data await Task.Run(() { // 子线程中读取文件 return System.IO.File.ReadAllText(data.txt); }); // 回到主线程更新 UI Debug.Log(数据加载完成: data); }注await会暂停当前方法的执行等待Task.Run中的操作完成同时不阻塞主线程。UI事件返回值需要是void并且await无法等待async void方法完成并且其中异常也不会捕获。多线程使用限制与注意事项1.主线程独占操作创建/销毁Obj修改组件属性调用Debug.log与Time.deltaTime访问Physics.Raycast。2.线程同步使用UnityMainThreadDispatcher第三方工具或MainThreadQueue将子线程结果传回主线程。Thread thread new Thread(() { int result HeavyCalculation(); UnityMainThreadDispatcher.Instance.Enqueue(() { textUI.text 结果: result; // 在主线程更新 UI }); });3.竞态条件多线程修改共享数据需用lock或Mutex同步。private object obj new object(); private int _counter 0; private void ThreadSafeIncrement() { lock (obj) { _counter; } }20.序列化与反序列化1.概念将对象状态变量值引用关系等转换为可存储或可传输的格式。2.应用场景与预制体保存Unity将场景中的GameObject及其组件序列化为.unity或.prefab文件。Inspector面板显示公共变量或者[SerializeField]的私有变量显示在Inspector面板。ScriptableObject数据存储创建重复使用的配置数据。数据持久化将数据转换为JSON字符串保存到文件。网络数据传输通过序列化将游戏状态发送到服务器或其他客户端。3.Unity可序列化对象基本数据类型intfloatstringbool等。Unity类型Vector3.QuaternionColor等。自定义的类或结构体需标记[System.Serializable]4.控制序列化字段[HideInInspector]避免显示在Inspector窗口但仍可序列化。[NonSerialized]/[System.NonSerialize]不序列化字段。5.自定义序列化ISerializationCallbackReceiver接口public class DataVersioning : MonoBehaviour, ISerializationCallbackReceiver { public void OnAfterDeserialize() { //序列化后的特殊处理 } public void OnBeforeSerialize() { // 序列化前的特殊处理 } }SO与SPSerializedProperty管理复杂数据[CustomEditor(typeof(MyComponent))] public class MyComponentEditor : Editor { //定义inspector面板显示UI内容与交互逻辑 public override void OnInspectorGUI() { SerializedProperty dataProp serializedObject.FindProperty(data); //根据dataProp类型生成对应UI控件 EditorGUILayout.PropertyField(dataProp); //用户修改该值需调用此方法应用在实际MyComponent对象上 serializedObject.ApplyModifiedProperties(); } }注SP是操作序列化字段的工具类SO是存储数据的容器。21.Unity点击交互的实现方式1射线检测private void Update() { mousePosition Mouse.current.position.ReadValue(); // 从相机发射一条指向鼠标位置的射线 pos mainCamera.ScreenToWorldPoint(mousePosition); pos.z 0; ray mainCamera.ScreenPointToRay(mousePosition); RaycastHit2D hit Physics2D.Raycast(ray.origin , ray.direction, maxDistance, targetLayer); // 执行射线检测 if (Physics2D.Raycast(ray.origin,ray.direction ,maxDistance, targetLayer)) { // 射线命中物体使用命中点作为世界位置 CurrentWorldPosition hit.point; Debug.Log($射线命中: {hit.collider.gameObject.name}世界位置: {CurrentWorldPosition}); } else { Debug.Log($未命中物体使用 fallback 位置: {CurrentWorldPosition}); } }注目标物体需要有Collider。2物理碰撞检测public class SimpleClick : MonoBehaviour { private void OnMouseDown() { Debug.Log(点击了: gameObject.name); } }注目标物体需要有Collider并且不适用于UI元素。3事件系统1.UI控件public class UIClickHandler : MonoBehaviour, IPointerClickHandler { public void OnPointerClick(PointerEventData eventData) { Debug.Log(点击了 UI 物体: gameObject.name); } }2.3D与2D物体public class ObjectClickHandler : MonoBehaviour { private void Start() { //给当前物体添加EventTrigger组件 EventTrigger trigger gameObject.AddComponentEventTrigger(); //创建一个事件条目 EventTrigger.Entry entry new EventTrigger.Entry(); //设置事件类型为“PointerClick” entry.eventID EventTriggerType.PointerClick; entry.callback.AddListener((data) OnClick()); //将条目添加到EventTrigger的事件列表中 trigger.triggers.Add(entry); } private void OnClick() { Debug.Log(点击了场景物体: gameObject.name); } }4新输入系统优点支持多设备输入高度可配置化。22.相机基本设置1.Clear Flags清除屏幕方式SkyBox用天空盒填充未渲染区域Solid Color用纯色填充适合 2D 游戏Depth Only仅清除深度信息用于多相机叠加Don’t Clear不自动清除需手动处理慎用2.Projection投影模式Perspective透视3D效果物体近大远小。Orthographic正交2D 效果无视距离适合2D游戏。3.Clipping Planes剪裁平面Near渲染的最近距离Far渲染的最远距离过大会影响性能4.Viewport Rect定义相机渲染的屏幕区域例如设置x0.5y0.5让相机渲染右半屏幕5.Culling Mask选择渲染的Layer物体。6.Target Texture将相机画面渲染到Render Texture上。23.NavMesh寻路1.烘培导航网格场景中标记可行走区域静态物体打开Window/AI/Navigation若没有则需要导包调整烘焙参数。点击Bake,即可生成NaveMesh。2.脚本控制NavMeshAgentprivate void Update() { if (!playerNav.hasPath !playerNav.pathPending) { //开启寻路 playerNav.SetDestination(target.position); } if (!playerNav.pathPending playerNav.remainingDistance playerNav.stoppingDistance !playerNav.hasPath) { //关闭寻路 playerNav.ResetPath(); } }注pathPending表示路径计算完毕 hasPath表示路径是否存在当到达或者重置则不存在路径remainingDistance表示剩余距离stoppingDistance表示停止距离。3.动态障碍处理为动态障碍物添加NavMeshObstacle组件。设置组件中Carve属性勾选修改NavMesh不勾选代理靠近时绕开局部避障。4.分离区域的连接NavMesh Link组件连接分离NavMesh。设置Start Point与End Point动态控制分离区域的断开与连接修改起始点/NavMesh.SetLinkActive(targetLink,bool);24.数据持久化1.PlayerPerfs存储数据是全局共享高耦合性且安全性低因此只适合存储少量基本数据。int highScore 1000; //存储highScore设置变量为HighScore PlayerPrefs.SetInt(HighScore, highScore); //获取Score如果没有返回默认值3 int score PlayerPrefs.GetInt(Score, 3); PlayerPrefs.Save();2.Json轻量易用的数据持久化方案。// 保存数据 string json JsonUtility.ToJson(data);//对象转成JSON字符串 System.IO.File.WriteAllText(SavePath(fileName), json);//写入本地文件 // 读取数据 string json System.IO.File.ReadAllText(path);//读取Json字符串 SomeClass loadedPlayer JsonUtility.FromJsonT(json);//Json字符串转成对象注公开的变量以及[SerializeField]修饰的私有变量可以储存。25.DoTween插件使用1.初始化可以自动初始化也可以手动。DOTween.Init(bool recycleAllByDefault false, bool useSafeMode true, LogBehaviour logBehaviour LogBehaviour.ErrorsOnly) DOTween.Init();注recycleAllByDefault true动画使用完会放入对象池不会直接销毁useSafeMode true动画性能慢一些但更安全logBehaviour根据模式会记录不同信息2.timeScale对动画的影响在创建的动画后加上.SetUpdate(true)方法就可以这样在游戏暂停(Time.timeScale 0)的时候动画依旧在运行知道动画结束。3.动画返回值Tween4.移动过渡//to目标点duration持续时间snapping true每次移动整数值。 transform.DOMove(Vector3 to, float duration, bool snapping); transform.DOMoveX(10, 2f, false); transform.DOLocalMove(new Vector3(10f, 2f, 0), 10f, false); transform.DOLocalMoveX(10, 2f, false); //endValue跳跃目标点jumpPower跳跃强度决定跳跃高度 transform.DOJump(Vector3 endValue, float jumpPower, int numJumps, float duration, bool snapping)); transform.DOLocalJump(new Vector3(10, 0, 0), 10, 3, 2f, false);5.旋转过渡//to目标值duration过渡时间mode旋转模式fast最短路径旋转不会超过360度FastByond360旋转会超过360度 transform.DORotate(Vector3 to, float duration, RotateMode mode);//欧拉角 transform.DORotateQuaternion(Quaternion to, float duration)//四元数 //towards目标点duration过渡时间axisConstraint旋转的约束轴只旋转此轴up默认为Vector.up transform.DOLookAt(Vector3 towards, float duration, AxisConstraint axisConstraint AxisConstraint.None, Vector3 up Vector3.up)6.缩放过渡transform.DOScale(float/Vector3 to, float duration) transform.DOScaleX/DOScaleY/DOScaleZ(float to, float duration)7.文本动画//打字机效果会覆盖原先的文字显示新的文字。 GetComponentText().DOText(string str, float duration);8.震动效果//持续时间强度在哪个轴上震动 transform.DOShakePosition(1,Vector3 vector);9.冲击效果//punch:被打击的目标点duration过渡时间vibrato振动频率elasticity震荡效果0-1 transform.DOPunchPosition(Vector3 punch, float duration, int vibrato, float elasticity, bool snapping) transform.DOPunchRotation(Vector3 punch, float duration, int vibrato, float elasticity) transform.DOPunchScale(Vector3 punch, float duration, int vibrato, float elasticity)26.Text与TextMeshPro区别UGUI TextTextMeshPro渲染技术位图字体有向距离场矢量渲染性能合批限制多DrawCall高合批能力强特效无额外顶点开销DrawCall低质量缩放易模糊且抗锯齿弱任意缩放边缘锐利抗锯齿强字体资源管理多字号需要多套图集内存占用大一张SDF图集支持全字号内存占用低底层渲染技术区别Text位图字体渲染Unity将字符预渲染到一张固定分辨率的纹理图集每个字符是像素位图TextMeshPro有向距离场矢量渲染字符图集存的是字符轮廓的距离场信息。27.静态图集与动态图集1.核心目标两者都是要将多个小尺寸Sprite合并为一张大纹理减少纹理切换降低DrawCall。2.静态图集编辑器下离线预制提前合并的图集资源。注不能热更新。3.动态图集游戏运行下实时动态创建按需合并纹理的图集方案。区别静态图集动态图集资源生命周期打包进游戏由开发者决定在内存中创建自动回收销毁性能开销加载后直接采样渲染无CPU开销有CPU开销内存占用单张纹理内存占用低按需加载利用率高内存占用高可维护性差需要重新打包图集强新增资源无需提前规划应用场景固定不变的核心界面与无热更需求的项目热更资源动态加载UI数据28.合批1DrawCallCPU调用图形API向GPU发送一次渲染指令的过程。2静态合批1原理将标记为Batching Static的静止物体合并。2合批条件物体必须完全静止共享同一材质实例3动态合批1原理运行时每帧CPU自动将符合的小型动态物体的顶点转换到世界空间合并到同一个顶点缓冲区。2合批条件共享同一材质实例单个网格顶点数300个物体必须使用完全一致的全局缩放未开启GPU Instancing4UGUI合批1概念同一Canves下满足合批规则的多个UI元素的网格数据合并到一个顶点缓冲区仅用一次DrawCall提交GPU渲染。2合批条件处在同一Canves下共享同一个图集以及相同的材质实例渲染顺序连续不能被打断合批网格间不能插入无法合批的元素3优化方案使用图集动静分离动态与静态UI使用不同Canves动态UI避免频繁创建/删除减少重建次数。文本最好用TextMeshPro或者图片避免UI元素过多与层级复杂影响合批速度。注合批会进行深度/材质/纹理排序最后判断相邻元素是否可以合批。尽量不使用Mask4重建CPU计算网格UI的RectTransfrom尺寸与锚点变化视觉元素的改变都触发重建。29.AssetBundle(AB包)1打包流程给资源打标记BuildPipeline.BuildAssetBundles(path,BuildAssetBundleOptions.None,BuildTarget.StandalongWindows )进行打包操作2加载与卸载打包后会获得一个Mainfest文件需要第一个加载获取所有AB依赖关系。加载LoadFromFile/LoadFromFileAsync(path)从本地直接读取进行加载。获取LoadAssetT(name)从AssetBundle中获取目标资源。卸载AssetBundle.Unload(bool) false仅卸载AB包本体的归档资源不会卸载已加载资源true卸载AB包本体与已加载资源。3打包策略1按业务模块打包全局公共依赖包通用Shader基础字体全局音效系统公共包UI系统的公共组件战斗系统的通用特效等业务模块包战斗对话等单独模块单实例独立包大型场景过场动画等作用按需加载模块解耦需要精细化管理2同类型资源打包同一类型/格式/平台的资源打到同一AB包例如所有MP3格式的音频打到audio.ab。作用管理简单包体更小无法按需加载修改一个资源要更新整个包。3按资源粒度打包三种策略单资源打包10MB以上的大资源零冗余按需加载AB包数量激增加载性能差。逻辑单元复合包例如角色预制体材质动画UI界面图集加载性能好内存管理方便需要精细化规划。全资源包项目所有资源打包到少数AB包管理简单无依赖问题无法按需加载。4特殊资源打包Shader将项目中所有Shader全部打包到同一个全局Shader公共包。图集散图与图集一起打包Unity会自动优化或者单独打包图集结果是一样的。4依赖管理两个及以上AB包所依赖的资源提取到公共资源中。加载AB前先加载依赖卸载AB后再卸载依赖资源。5引用计数每个AB包一个引用计数器记录其被依赖的次数。例如加载两个AB包时它们都依赖另一个AB包那么另一个AB包计数1收到这两个AB包卸载请求时另一个AB包计数-1。计数为0调用Unload卸载AB包。30.预制体嵌套与变体1嵌套预制体预制体内部包含另一个预制体作为其子对象。修改子同步父除非父内已修改属性则不同步修改父不影响子。父内编辑子不影响子源文件。多级嵌套2预制体变体基预制体派生而来的预制体资源。变体完全继承基预制体。基预制体的修改同步所有派生变体除非变体覆盖的属性基预制体的修改不同步该属性变体修改不会影响基预制体。支持多级派生变体本身是作为独立资源使用的可以实例化与嵌套等操作。