一、生命周期编辑器模式:Reset() -- 脚本首次挂载或点击Reset时调用运行时初始化:Awake() -- 脚本实例被创建时调用整个生命周期仅一次OnEnable() -- 每次脚本激活时调用可多次首帧:Start() -- 第一次Update之前调用整个生命周期仅一次游戏循环每帧:FixedUpdate() -- 固定时间间隔调用默认0.02s物理相关Update() -- 每帧调用间隔不固定LateUpdate() -- Update之后调用常用于摄像机跟随物理更新后:WaitForFixedUpdate -- yield后在FixedUpdate之后执行协程处理:yield return null / WaitForEndOfFrame 等 -- Update 之后、LateUpdate 之前检查卸载/销毁:OnApplicationQuit() -- 退出程序时OnDisable() -- 禁用时与OnEnable配对可多次OnDestroy() -- 销毁时整个生命周期仅一次【关键区别】Awake | 一次 | 最早 | 初始化自身获取组件引用OnEnable | 多次 | 每次激活 | 事件监听注册、重置状态Start | 一次 | Awake之后 | 依赖其他脚本的初始化逻辑Update | 每帧 | FixedUpdate后 | 大部分游戏逻辑FixedUpdate | 固定 | 物理时钟 | 物理相关操作RigidbodyLateUpdate | 每帧 | Update后 | 摄像机跟随、追尾效果OnDisable | 多次 | 禁用/销毁前 | 事件监听注销、清理OnDestroy | 一次 | 销毁时 | 最终清理二、旋转欧拉角与四元数【欧拉角 (Euler Angles)】- 数据类型Vector3 -- transform.eulerAngles- Unity内部按 Z - X - Y 顺序存储yxz顺序- 直观易理解但存在万向锁问题【万向锁 (Gimbal Lock)】- 当中间轴X 轴旋转到 /-90 度时第一轴Y轴和第三轴Z轴等价- 导致丢失一个旋转自由度- 解决方法使用四元数表示和计算旋转【四元数 (Quaternion)】- 数据类型Quaternion- 由四分量组成(x, y, z, w) -- 不要手动改分量- 无万向锁问题可平滑插值Slerp / Lerp【常用 API】// 欧拉角 - 四元数Quaternion rot Quaternion.Euler(0, 90, 0);// 四元数 - 欧拉角Vector3 angles transform.rotation.eulerAngles;// 插值球形线性均可transform.rotation Quaternion.Slerp(from, to, Time.deltaTime * speed);transform.rotation Quaternion.Lerp(from, to, Time.deltaTime * speed);// 方向旋转transform.rotation Quaternion.LookRotation(direction);// 叠加旋转顺序重要先A后B 对应 B * Atransform.rotation rotB * rotA;// 绕轴旋转transform.rotation * Quaternion.AngleAxis(angle, Vector3.up);// RotateTowards匀速旋转带最大角度限制transform.rotation Quaternion.RotateTowards(from, to, maxDegreesDelta);// transform.Rotate() -- 在欧拉角层面transform.Rotate(0, speed * Time.deltaTime, 0); // 绕自身Y轴旋转// Transform 系列transform.LookAt(target); // 看向目标transform.RotateAround(point, axis, angle); // 绕某点旋转三、Canvas【三种渲染模式】Screen Space - Overlay不需要摄像机始终渲染在所有3D物体上方适用HUD、菜单、血条Screen Space - Camera绑定指定摄像机受摄像机距离/裁剪面影响World Space作为3D物体存在场景中像面片适用血条跟随、3D公告牌、【不同 Canvas 间渲染顺序】Overlay 模式的 Canvas 永远在最上层└── 多个Overlay之间Sort Order 越大越在上层Camera / World Space 模式└── 不同 Sort LayerLayer名称在列表越靠下越上层└── 同一 Sort LayerOrder in Layer 越大越上层【同一 Canvas 内渲染顺序】- 按照 Hierarchy 窗口从上到下的顺序渲染越靠下越在上层- 父子嵌套不影响渲染顺序但子物体天然在Hierarchy下方视觉上遮住父物体- z 轴位置不影响渲染顺序UGUI 是无深度测试的- 若UI设置了 Sort Layer 或 Order in Layer则按其规则优先【渲染知识补充】- Canvas 下的 GraphicRaycaster 负责UI射线检测- 静态 Canvas元素不频繁变动可优化- 变动频繁的UI可拆分为动态/静态两个Canvas以降低Canvas Rebuild重绘开销原理Canvas里所有UI元素都会合并成网格发给GPU渲染但只有一个元素变动其他元素都会重新渲染。这个过程叫Canvas.BuildBatch可以将不频繁变动相对静态的ui元素放到静态Canvas里。将每帧变化的频繁变动的放到另一个动态Canvas里四、Canvas ScalerUI 缩放【三种缩放模式】Constant Pixel Size1像素等于1单位不根据屏幕缩放适用固定分辨率设备Scale With Screen Size根据参考分辨率等比例缩放最常用适用多分辨率适配Constant Physical Size按物理单位厘米/英寸保持大小适用需要真实物理尺寸【Scale With Screen Size 核心参数】Reference Resolution: 1920 x 1080Screen Match Mode: Match Width Or Height// 0 仅匹配宽度// 1 仅匹配高度// 0.5 两者兼顾常用Match: 0.5 // 倾向值0~1 之间的浮点Reference Pixels Per Unit: 100 // 每单位对应的像素数精灵默认100【适配策略】- 屏幕比例不确定时Match 0.5取宽高的平均缩放- 竖屏游戏Match 1按高度适配- 需配合 Anchor锚点和 Pivot 做组件级布局适配五、UGUIUnity GUI【核心组件】Image 显示精灵图片Source ImageRawImage 显示任意纹理Texture2D支持 UV 偏移Text / TextMeshPro 文本显示推荐TMP更清晰更高性能Button 可点击按钮自带过渡效果和 OnClick 事件Toggle 开关/复选框Slider 滑动条Scrollbar 滚动条ScrollRect 滚动视图配合 Mask 实现裁剪InputField 输入框Dropdown 下拉菜单Mask / RectMask2D 裁剪子物体显示区域LayoutGroup 自动布局Horizontal/Vertical/GridContentSizeFitter 根据内容自动调整大小AspectRatioFitter 保持宽高比【UGUI 性能注意】- 避免频繁修改 Canvas 下 UI 元素的属性Color、Position 等会触发Canvas.BuildBatch- 将动态 UI 拆分到子 Canvas 中- RaycastTarget 不需要接收点击的元素应关闭- 文本使用 TextMeshPro 而非 Legacy TextTMP缩放清晰- 移出屏幕外的UI如滚动列表建议 ObjectPool 动态加载六、协程 (Coroutine)【核心概念】- 协程不是多线程由 C# 迭代器IEnumerator yield实现- 所有协程均在主线程执行- 执行时机Update() 结束后遍历所有协程检查 yield 条件Update - 协程处理依次检查所有yield条件 - LateUpdate【常用 yield 指令】null 下一帧的Update之后 | 无GC0 / 100 等int 下一帧的Update之后 | 会装箱产生GCnew WaitForEndOfFrame() 渲染完毕后下一帧前 | 常用于截图new WaitForFixedUpdate() 下一个FixedUpdate后 | 与物理有关new WaitForSeconds(n) 等待n秒后 | 受 Time.timeScale 影响new WaitForSecondsRealtime(n) 等待n秒后 | 不受 timeScale 影响new WaitUntil(func) func返回true后 | 每帧检查new WaitWhile(func) func返回false后 | 每帧检查StartCoroutine() 嵌套 子协程执行完毕后恢复 |break 直接终止无等待 |【协程控制】// 启动Coroutine co StartCoroutine(MyCoroutine());// 停止只能停止自身脚本或自身 StartCoroutine 返回的引用别的脚本不行StopCoroutine(co);StopAllCoroutines(); // 停止当前脚本启动的全部协程// GameObject 被销毁 - 该对象上所有协程自动停止【协程注意事项】1. 执行顺序先启动的协程优先检查条件先恢复执行2. 跨脚本停止A 脚本中的协程无法在 B 中直接停止需通过引用3. 装箱问题yield return 0 会产生 GC建议使用 yield return null4. 不要在协程外使用 yield必须配合 IEnumerator 返回类型七、异步加载 (Async / Await)--------------------------------------------------------------------------------【三种方案对比】SceneManager.LoadSceneAsync() 原生异步场景加载 场景切换Addressables 资源地址化异步加载 资源热更新DLCResources.LoadAsync() 异步加载Resources资源 小项目快速加载【async / await 机制】若 await 的是 Task.Run 任务内部逻辑跑子线程结束后自动切回主线程执行后续代码若 await 的是 Task.Delay、Unity 异步资源等全程主线程不存在切换线程await 本身不负责创建线程只负责「等待 调度恢复上下文」。async void Start() // void返回 危险外部无法获取任务引用继而无法得知任务何时结束而且无法捕捉异常async Task StartAsync() // Task返回调用方可以await等待async TaskT GetData() // TaskT可返回结果- async 把方法标记为异步状态机- 方法内部自上而下执行遇到 await 时1. 先执行 await 后面的表达式2. 发起异步操作等待完成3. 完成后自动切回主线程继续往下执行- 优点跑在主线程、零 GCAwaitable 支持、可 return 值、代码结构线性直观【Task.Run】async Task LoadFileAsync() {// Task.Run 把耗时操作放入线程池子线程string data await Task.Run(() File.ReadAllText(file.txt));// 回到主线程Unity 同步上下文textMesh.text data;}- Task.Run() 中的代码在子线程不能调用 Unity API- await 完成后自动回到 Unity 主线程SynchronizationContext【异步与协程对比】协程 (Coroutine) async/await返回值 无IEnumerator yield 可以TaskT异常处理 不方便 原生支持GC yield WaitForSeconds有GC 0 GC使用Awaitable代码风格 类同步风格 更接近同步线程 仅主线程 主线程子线程均可【异步操作常用扩展】// 将 AsyncOperation 转为可等待await sceneLoadOperation;八、事件系统 (Event System)--------------------------------------------------------------------------------【委托 (Delegate) 基础】Action 无参数无返回 简单通知ActionT1..T16 有参数无返回 带参数的通知FuncTResult 无参数有返回 计算/获取FuncT,R..T16 有参数有返回 带参数的计算PredicateT 一个参数返回bool 条件判断delegate 自定义 任意参数任意返回 特殊需求【事件组成与运作流程】触发者 - 调用事件唤起函数 - 事件(Event)被唤起 - 所有注册的回调函数依次执行【event 关键字的作用】1. 外部只能用 / - 来注册和注销不能直接赋值2. 不能整体替换事件上的回调链如 myEvent null3. 外部不能直接调用事件只能由发布者内部调用4. 语义上清晰标识这是事件而非普通委托【完整事件示例】// 事件发布者public class Player {public event Actionint OnHealthChanged; // 带参数的事件public event Action OnDeath; // 无参事件private int health 100;public void TakeDamage(int damage) {health - damage;OnHealthChanged?.Invoke(health); // 唤起事件if (health 0) OnDeath?.Invoke();}}// 事件订阅者public class UIController : MonoBehaviour {void Start() {Player player FindObjectOfTypePlayer();player.OnHealthChanged UpdateHpBar;player.OnDeath ShowGameOver;}void OnDestroy() {player.OnHealthChanged - UpdateHpBar; // 必须注销}void UpdateHpBar(int hp) { ... }void ShowGameOver() { ... }}【注销与内存泄漏】- 必须注销订阅者在销毁/禁用时一定要 -- 不注销会导致1) 内存泄漏 2) 已销毁对象被回调 - NullReferenceException- 通用注销方法在 OnDisable() 或 OnDestroy() 中移除九、单例模式 (Singleton Pattern)【饿汉式】public class SingletonEager {// 类加载即创建天生线程安全private static readonly SingletonEager _instance new SingletonEager();public static SingletonEager Instance _instance;private SingletonEager() { } // 私有构造函数防止外部 new}【懒汉式】public class SingletonLazy {private static SingletonLazy _instance;public static SingletonLazy Instance {get {if (_instance null)_instance new SingletonLazy();return _instance;}}private SingletonLazy() { }}【Unity 中的 MonoBehaviour 单例】public class GameManager : MonoBehaviour {public static GameManager Instance { get; private set; }void Awake() {if (Instance ! null Instance ! this) {Destroy(gameObject); // 已有实例销毁重复return;}Instance this;DontDestroyOnLoad(gameObject); // 跨场景保留}}【优缺点】优点- 全局唯一访问入口代码简洁- 控制实例数量内存可控- 跨场景、跨模块数据共享缺点- 违反依赖倒置原则高层依赖具体实现- 隐藏了依赖关系难以测试- 强耦合模块间不再通过接口通信【解决耦合问题】- 结合依赖注入DI/ Service Locator 模式- 在测试环境中注入 Mock 对象替代单例- 使用 Zenject / VContainer 等 DI 框架Unity 推荐十、六大设计原则--------------------------------------------------------------------------------1. 单一职责原则 (SRP)- 一个类只承担一种职责只有一个引起它变化的原因- 例PlayerMovement 只负责移动PlayerAttack 只负责攻击2. 开闭原则 (OCP)- 对扩展开放对修改封闭- 通过继承、策略模式等扩展功能而不是修改原有类- 例新武器类型不需要改 PlayerAttack只需添加新 Weapon 子类3. 里氏替换原则 (LSP)- 子类对象必须能完全替换父类对象不破坏程序逻辑- 父类能做的事子类必须也能做不能说不支持- 例Bird 类的 Fly() 方法Penguin 子类不能抛异常4. 接口隔离原则 (ISP)- 接口应小而专不应让实现者被迫实现不需要的方法- 例IWalkable、IFlyable、ISwimable 分离而不是一个 IMovable 全包含5. 依赖倒置原则 (DIP)- 高层模块和低层模块都应依赖抽象接口/抽象类- 例Player 依赖 IWeapon不依赖具体的 Sword / Bow 类6. 迪米特法则 (LoD / 最少知识原则)- 一个对象应对其他对象有最少了解只与直接朋友通信- 链式调用如 a.GetB().GetC().DoSomething() 不推荐- 例Player 不应直接操控 Weapon.Bullet.Trail而是通过 Weapon 的接口十一、对象池【核心设计】[对象池]|-- 空闲队列已回收、待激活的对象|-- 活跃列表正在使用的对象|-- 预设引用用于 Instantiate 新对象|-- 最大容量超出则不再创建/改为销毁【基本实现】public class ObjectPoolT where T : Component {private QueueT _pool new QueueT();private T _prefab;private int _maxSize;public ObjectPool(T prefab, int initSize, int maxSize) {_prefab prefab;_maxSize maxSize;for (int i 0; i initSize; i) {T obj Object.Instantiate(_prefab);obj.gameObject.SetActive(false);_pool.Enqueue(obj);}}public T Get() {if (_pool.Count 0) {T obj _pool.Dequeue();obj.gameObject.SetActive(true);return obj;}return Object.Instantiate(_prefab);}public void Release(T obj) {obj.gameObject.SetActive(false);if (_pool.Count _maxSize)_pool.Enqueue(obj);elseObject.Destroy(obj.gameObject);}}【作用】- 避免频繁 Instantiate / Destroy 导致的 GC 压力和内存碎片化- 重复利用已创建对象降低 CPU 和内存开销- 统一管理生成与回收避免代码冗余【常见应用场景】- 子弹、特效、掉落物品- 列表 Item配合 ScrollRect 回收复用- 敌人、NPC【Unity 内置方案 (2021 LTS)】using UnityEngine.Pool;ObjectPoolBullet _bulletPool new ObjectPoolBullet(createFunc: () Instantiate(bulletPrefab),actionOnGet: (b) b.gameObject.SetActive(true),actionOnRelease: (b) b.gameObject.SetActive(false),actionOnDestroy: (b) Destroy(b.gameObject),maxSize: 50);十二、架构模式--------------------------------------------------------------------------------【1. MonoBehaviour 架构】每个 GameObject 挂载继承 MonoBehaviour 的脚本对象自己处理自己的逻辑。- 最简单、最直观- 适用于原型、小项目【2. MVC 架构】Model - 数据与状态View - UI 显示只负责表现Controller - 业务逻辑连接Model与View- Model 不依赖 ViewView 监听 Model 变化- 多用于 UI 交互与网络同步- 优点数据-显示-逻辑分离缺点增加代码复杂度【3. MVP / MVVM】- MVPPresenter 主动更新 ViewUnity常与MVC混用【4. 事件驱动架构 (Event-Driven)】模块间通过事件通信无需直接依赖。- 核心目标解耦模块之间的直接依赖- 实现方式EventAggregator / MessageBus / Signal- 优点高内聚低耦合模块独立开发- 缺点事件流向难以追踪过度使用导致调试困难【5. ECS (Entity Component System)】- 属于编程范式详见下一章十三、Unity DOTSData-Oriented Technology Stack【三大组成部分】1. ECS (Entity Component System)概念 对应 OOP 说明Entity GameObject 只是一个ID不包含数据Component MonoBehaviour 字段 纯数据struct只包含状态System MonoBehaviour 逻辑 处理拥有特定组件的实体// Entity: 仅为一个ID标识Entity entity entityManager.CreateEntity();// Component: 纯数据实现 IComponentDatapublic struct MoveSpeed : IComponentData {public float Value;}// System: 处理逻辑筛选带MoveSpeedTranslation组件的实体public partial struct MoveSystem : ISystem {public void OnUpdate(ref SystemState state) {foreach (var (trans, speed) inSystemAPI.QueryRefRWTranslation, RefROMoveSpeed()) {trans.ValueRW.Value speed.ValueRO.Value * SystemAPI.Time.DeltaTime;}}}2. Job SystemC# Job System- 将计算任务分配到多个线程并行执行- 配合 ECS 实现大规模并行计算- 实现 IJob / IJobParallelFor 接口的结构体[BurstCompile]public struct MyJob : IJobParallelFor {public NativeArrayfloat Results;public void Execute(int index) {Results[index] Mathf.Sqrt(index);}}void Update() {var job new MyJob { Results resultsArray };JobHandle handle job.Schedule(arrayLength, batchCount);handle.Complete(); // 主线程等待完成}3. Burst Compiler- 将 C# 代码Job 结构体编译为高度优化的原生机器码- 只能应用于 struct、NativeContainer、纯值类型不能有托管引用- 使用方法在实现了 IJob 接口的结构体上添加 [BurstCompile] 标签[BurstCompile] // 此标签启用 Burst 编译struct FastJob : IJob {public NativeArrayint Data;public void Execute() { ... }}十四、Unity 多线程--------------------------------------------------------------------------------【自动多线程引擎自动处理】Job System 配合 ECS / Burst大规模数据并行计算Burst Compiler 把 Job 编译为高性能本地代码Addressables/AssetBundle 资源加载在后台线程异步处理PhysX 物理引擎 碰撞检测、刚体模拟默认在子线程运行导入Import处理 导入模型/纹理等资产时自动多线程加速Audio 音频解码与混音在独立线程Networking UnityWebRequest 在后台线程执行网络IO【手动多线程】[Thread线程]void Start() {Thread thread new Thread(() {// 子线程执行耗时操作Debug.Log(子线程ID: Thread.CurrentThread.ManagedThreadId);// 注意子线程中不能调用 Unity API});thread.IsBackground true; // 设为后台线程主线程结束自动终止thread.Start();}[Task任务]async Task LoadDataAsync() {// Task.Run 在子线程执行string data await Task.Run(() File.ReadAllText(data.txt));// await 完成后自动回到主线程textMeshProUGUI.text data; // 安全调用 Unity API}[Parallel / PLINQ]Parallel.For(0, arrayLength, i {results[i] HeavyCalculation(data[i]);});【子线程注意事项】禁止调用 Unity API Transform、GameObject等大部分API不可在子线程调用使用 NativeContainer NativeArrayT、NativeListT 可在 Job 中安全访问线程安全 共享数据需加锁lock或用无锁数据结构主线程回调 子线程结果需通过 SynchronizationContext 回到主线程后台线程 thread.IsBackground true 防止线程阻止进程退出十五、补充知识点--------------------------------------------------------------------------------15.1 Update / FixedUpdate / LateUpdate 详细区别--------------------------------------------------------------------------------FixedUpdate 固定默认0.02s 固定间隔 物理操作Rigidbody、碰撞Update 每帧 不固定 普通逻辑、输入检测LateUpdate 每帧 不固定 摄像机跟随、追尾效果- FixedUpdate 零次或多次调用取决于帧率- 不要在 FixedUpdate 里写基于 Time.deltaTime 的逻辑平滑移动一般物体物理相关应在 FixedUpdate 使用 Time.fixedDeltaTime 固定步长--------------------------------------------------------------------------------15.2 Time 类常用属性--------------------------------------------------------------------------------Time.time 游戏运行总时间Time.deltaTime 上一帧到当前帧的时间间隔Time.fixedDeltaTime FixedUpdate 固定时间间隔Time.unscaledDeltaTime 不受 timeScale 影响的 deltaTimeTime.timeScale 时间缩放0暂停1正常Time.realtimeSinceStartup 真实时间不受 timeScale 影响--------------------------------------------------------------------------------15.3 预制体 (Prefab)--------------------------------------------------------------------------------- 预制体变体Prefab Variant基于已有预制体的派生版本- 预制体覆盖 (Override)实例上修改的属性可以 Apply 回预制体或 Revert- PrefabUtility 和 PrefabStage 用于编辑器扩展的预制体操作- 嵌套预制体Nested Prefab一个预制体内部引用另一个预制体--------------------------------------------------------------------------------15.4 动画系统 (Animator Animation)--------------------------------------------------------------------------------- Animation旧版组件直接播放 AnimationClip- Animator新版状态机系统使用 AnimatorController- 参数类型Float, Int, Bool, Trigger- 过渡条件Has Exit Time, Duration, Conditions- 动画层Layer实现上下半身分离、Avatar Mask- IK反向动力学OnAnimatorIK() 层中设置手部/脚部位置- BlendTree混合树如 Idle-Walk-Run 基于速度的混合- 状态机行为 (StateMachineBehaviour)在状态进入/退出时执行自定义逻辑--------------------------------------------------------------------------------15.5 物理系统--------------------------------------------------------------------------------组件Rigidbody 刚体物理模拟Rigidbody2D 2D 刚体Collider 碰撞体Bounds检测Collider2D 2D 碰撞体Joint 关节Hinge, Spring, Fixed等CharacterController 角色控制器非物理驱动的移动Physics.Raycast 射线检测Physics.OverlapSphere 球形范围检测Rigidbody 移动方式- velocity 直接设置速度- AddForce 施加力- MovePosition 平滑移动到目标配合 FixedUpdate- transform.position 不推荐绕过物理影响碰撞检测--------------------------------------------------------------------------------15.6 输入系统--------------------------------------------------------------------------------Input Manager (旧) Input.GetAxis(), Input.GetKey()Input System (新) 基于 Action 的跨平台输入系统推荐// 新 Input System 示例PlayerInputActions input;void Awake() {input new PlayerInputActions();input.Player.Jump.performed ctx OnJump();}void OnEnable() input.Enable();void OnDisable() input.Disable();--------------------------------------------------------------------------------15.7 PlayerPrefs轻量数据存储--------------------------------------------------------------------------------PlayerPrefs.SetInt(highScore, 100);PlayerPrefs.SetFloat(volume, 0.8f);PlayerPrefs.SetString(playerName, User);PlayerPrefs.Save();int score PlayerPrefs.GetInt(highScore, 0); // 不存在返回0PlayerPrefs.DeleteKey(highScore);PlayerPrefs.DeleteAll();- 仅适用于少量简单数据高分、设置等- 不适用于大量数据/复杂结构用 JSON File 或 SQLite--------------------------------------------------------------------------------15.8 ScriptableObject--------------------------------------------------------------------------------[CreateAssetMenu(fileName NewItem, menuName Inventory/Item)]public class ItemData : ScriptableObject {public string itemName;public Sprite icon;public int maxStack;}- 数据容器作为资源文件保存在项目中- 适用于道具数据、技能配置、关卡数据、角色属性等- 优点内存友好数据只有一份引用、便于策划配置、可独立修改--------------------------------------------------------------------------------15.9 序列化--------------------------------------------------------------------------------- [SerializeField] 将 private 字段在 Inspector 中显示- [HideInInspector] 将 public 字段在 Inspector 中隐藏- [System.Serializable] 使自定义类/结构体可序列化- [Range(min, max)] 在 Inspector 中以滑动条控制- [Header(标题)] 分组标签- JsonUtility 或 Newtonsoft.Json 实现 JSON 序列化/反序列化- ISerializationCallbackReceiver 控制序列化前后回调--------------------------------------------------------------------------------15.10 性能优化要点--------------------------------------------------------------------------------Draw Call 减少渲染批次Static Batching, GPU Instancing, SRP BatcherLOD 远处物体使用低模Occlusion Culling 不可见物体不渲染对象池 复用 GameObjects字符串拼接 使用 StringBuilder空引用遍历 GetComponent 查缓存避免在 Update 频繁调用Resources 文件夹 不使用时资源也会进包慎放大量资源Overdraw UI 重叠导致像素重复绘制尽量减少重叠层级Profiler 性能分析工具窗口定位瓶颈--------------------------------------------------------------------------------15.11 常用调试--------------------------------------------------------------------------------Debug.Log(普通日志);Debug.LogWarning(警告);Debug.LogError(错误);Debug.Assert(condition, 断言失败时输出);Debug.DrawLine(start, end, Color.red); // Scene视图绘制线条Debug.DrawRay(origin, direction);Debug.Break(); // 暂停编辑器--------------------------------------------------------------------------------15.12 Build Settings 与平台--------------------------------------------------------------------------------- Build Pipeline内置管线 / URP / HDRP- Player Settings 重要配置Resolution PresentationSplash ImageScripting BackendMono vs IL2CPPApi Compatibility Level.NET Standard 2.0 或 .NET FrameworkStripping Level- IL2CPP将 C# 编译为 C 再编译为本地代码性能优于 Mono- Managed Stripping Level控制代码裁剪程度过高可能误删反射使用的代码--------------------------------------------------------------------------------15.13 常用命名空间--------------------------------------------------------------------------------using UnityEngine; // 核心using UnityEngine.UI; // UGUIusing UnityEngine.SceneManagement; // 场景管理using UnityEngine.EventSystems; // 事件系统using UnityEngine.AI; // NavMeshusing System.Collections; // 协程using System.Collections.Generic; // List, Dictionaryusing System.Linq; // LINQ注意GCusing System.Threading.Tasks; // async/await--------------------------------------------------------------------------------15.14 零散但重要的知识点--------------------------------------------------------------------------------- [RequireComponent(typeof(X))]约束脚本挂载时自动添加必需组件- gameObject 和 transformMonoBehaviour 内置的快捷属性- GetComponent 性能GetComponentT() 有开销应在 Awake/Start 中缓存避免在 Update 中调用- TryGetComponentUnity 2019.3不分配 GC 的安全获取- Find 系列FindObjectOfType / GameObject.Find 遍历整个场景性能开销大仅适合初始化Awake- 空合并与空传播myEvent?.Invoke() - 无订阅者时不报错- 操作符重载四元数 *旋转叠加Vector3 - * 等- Layer TagLayer 用于物理和渲染过滤Tag 用于逻辑分类- SceneManagerLoadScene, LoadSceneAsync, UnloadSceneAsync- Resources.Load vs Addressables前者不推荐用于正式项目