25.Unity基础基础知识总结

  1. 25.总结
    1. 25.1 知识点
      1. 学习的主要内容
      2. 总结讲什么
      3. Unity基础中知识点的重要性
      4. 如何学好Unity
      5. 强调
    2. 25.2 核心要点速览
      1. Mathf
        1. 常用基础方法(一般计算一次)
        2. 插值运算(Lerp)深度解析
        3. 三角函数与角度转换
      2. 坐标系
        1. 四大坐标系对比
        2. 坐标转换核心方法
          1. 世界 ↔ 本地(Transform 方法)
          2. 世界 ↔ 屏幕(Camera 方法)
          3. 世界 ↔ 视口(Camera 方法)
      3. Vector3
        1. 基础属性(实例成员)
        2. 静态方法(基础运算)
      4. Quaternion
        1. 构造与属性
        2. 核心方法(旋转控制)
      5. 延迟函数
        1. 核心方法
        2. 对象状态对延迟函数的影响
        3. 延迟函数 vs 协程(Coroutine)
      6. 协同程序
        1. 协程方法
        2. 多线程与协程对比表
      7. 特殊文件夹
      8. Resources
        1. 同步加载
        2. 异步加载
        3. 资源卸载
      9. SceneManager
        1. 场景同步加载
        2. 场景异步加载
          1. 事件回调异步加载场景
          2. 协程异步加载场景
        3. 常用方法和属性
      10. LineRenderer
        1. LineRenderer组件参数
        2. LineRenderer参数和方法
      11. 物理系统-范围检测
        1. 范围检测基础
        2. 核心方法
      12. 射线检测
    3. 25.3 面试题精选
      1. 基础题
        1. 1. Mathf.Lerp 的两种用法有何区别?分别适合什么场景?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. 世界坐标系、本地坐标系、屏幕坐标系、视口坐标系各自的原点和轴方向是什么?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. Vector3.magnitude、normalized、sqrMagnitude 三者的区别与性能考量?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. Invoke 与 InvokeRepeating 的区别?对象失活或销毁时延迟函数如何表现?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      2. 进阶题
        1. 1. TransformPoint 与 TransformDirection 的核心区别是什么?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. Vector3.Angle 返回的角度范围是多少?如何判断目标在左侧还是右侧?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. Quaternion.Euler 与欧拉角直接赋值 transform.eulerAngles 有何风险?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. StartCoroutine 与 Invoke 的核心区别是什么?各自适合什么场景?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        5. 5. Resources.Load 与 AssetBundle 加载资源的主要区别?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        6. 6. Physics.OverlapBox 与 Physics.CheckSphere 的区别?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      3. 深度题
        1. 1. Quaternion.Slerp 与 Quaternion.Lerp 的区别?为何旋转插值推荐 Slerp?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. 协程的底层原理是什么?yield return null 与 yield return new WaitForSeconds 有何本质区别?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. 场景异步加载时,allowSceneActivation 为 false 时加载进度停在 0.9 的原因?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. Physics.Raycast 中 LayerMask 的位运算原理是什么?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章

25.总结


25.1 知识点

学习的主要内容

总结讲什么

Unity基础中知识点的重要性

如何学好Unity

强调


25.2 核心要点速览

Mathf

常用基础方法(一般计算一次)

方法 说明 参数/返回值 示例代码 游戏场景
Mathf.PI 圆周率(3.14159265358979) float(只读) print(Mathf.PI); // 3.141593 圆周长、弧度计算
Mathf.Abs(float f) 取绝对值 f:数值
返回:绝对值
Mathf.Abs(-5f); // 5 距离计算、伤害绝对值处理
Mathf.Clamp(float val, float min, float max) 钳制数值(超出范围取边界值) val:原始值
min/max:边界
Mathf.Clamp(HP, 0, 100); 血量、进度条限制
Mathf.Lerp(float a, float b, float t) 线性插值(t 0→1时a→b平滑过渡) a:起始值
b:目标值
t:插值系数
pos = Mathf.Lerp(startPos, endPos, 0.5f); 平滑移动、渐变动画
Mathf.RoundToInt(float f) 四舍五入取整 f:浮点数
返回:整数
Mathf.RoundToInt(3.6f); // 4 分数显示、帧数统计
Mathf.Sqrt(float f) 平方根 f:数值
返回:平方根
Mathf.Sqrt(25f); // 5 距离计算(替代 Vector3.Distance)
Mathf.CeilToInt(float f) 向上取整(≥f的最小整数) f:浮点数
返回:整数
Mathf.CeilToInt(1.3f); // 2 资源计数(购买数量向上取整)
Mathf.FloorToInt(float f) 向下取整(≤f的最大整数) f:浮点数
返回:整数
Mathf.FloorToInt(9.6f); // 9 资源计数(可用资源整数量)
Mathf.Max(params float[] values) 返回多个值中的最大值 values:可变长参数列表
返回:最大值
Mathf.Max(1, 2, 3, 4, 5); // 5 比较角色属性(如攻击力最大值)
Mathf.Min(params float[] values) 返回多个值中的最小值 values:可变长参数列表
返回:最小值
Mathf.Min(1, 2, 3, 4, 5); // 1 比较敌人防御(找最小防御敌人)
Mathf.Pow(float f, float p) 返回f的p次幂 f:底数
p:指数
返回:幂值
Mathf.Pow(2, 3); // 8 伤害计算(技能伤害随等级增长)
Mathf.IsPowerOfTwo(int value) 判断是否是2的n次方 value:整数
返回:布尔值
Mathf.IsPowerOfTwo(4); // true 纹理尺寸判断(图形处理需求)
Mathf.Sign(float f) 返回f的符号(正数/0→1,负数→-1) f:数值
返回:1或-1
Mathf.Sign(-10); // -1 方向判断(角色移动方向正负)

插值运算(Lerp)深度解析

用法 代码示例 效果 适用场景
用法一:先快后慢 pos = Mathf.Lerp(pos, target, Time.deltaTime * speed); 初始速度快,逐渐趋近目标(阻尼效果) 镜头跟随、物体平滑停止
用法二:匀速接近 t += Time.deltaTime; pos = Mathf.Lerp(start, end, t); t累加,匀速到达目标(t≥1时固定为end) 倒计时、线性动画
扩展:颜色插值 color = Color.Lerp(Color.red, Color.blue, t); t 0→1时红→蓝平滑过渡 UI渐变、技能特效

三角函数与角度转换

方法/常量 说明 参数/返回值 示例代码 游戏场景
Mathf.Rad2Deg 弧度转角度常量(1弧度≈57.29578°) float(只读) float deg = rad * Mathf.Rad2Deg; 欧拉角显示、UI角度标注
Mathf.Deg2Rad 角度转弧度常量(1°≈0.01745329弧度) float(只读) float rad = deg * Mathf.Deg2Rad; 三角函数计算、旋转方向
Mathf.Sin(float rad) 正弦函数(输入弧度) rad:弧度
返回:正弦值
Mathf.Sin(90 * Mathf.Deg2Rad); // 1 正弦波运动(摆锤、波浪效果)
Mathf.Cos(float rad) 余弦函数(输入弧度) rad:弧度
返回:余弦值
Mathf.Cos(0 * Mathf.Deg2Rad); // 1 方向向量计算(敌人巡逻路径)
Mathf.Atan2(float y, float x) 反正切函数(返回弧度,计算y/x的角度) y/x:坐标差值
返回:弧度
float angle = Mathf.Atan2(y, x) * Mathf.Rad2Deg; 角色朝向、子弹追踪

坐标系

四大坐标系对比

坐标系 定义 原点 轴方向 典型场景
世界坐标系 全局唯一,所有物体的绝对位置基准 场景中心(0,0,0) X→右,Y→上,Z→前(默认) 物体位置存储、碰撞检测
本地坐标系 相对于父对象的局部坐标系 父对象的位置 随父对象旋转/缩放而变化 子对象相对父对象的位置调整
屏幕坐标系 基于屏幕像素的2D坐标系 左下角(0,0) X→右,Y→上,Z→深度(摄像机距离) 鼠标位置获取、UI元素定位
视口坐标系 归一化的屏幕坐标系(0-1范围) 左下角(0,0) X→右,Y→上,Z→深度(0-1) 分屏显示、全屏适配

坐标转换核心方法

世界 ↔ 本地(Transform 方法)
方向 方法 说明 参数/返回值 游戏场景
世界→本地(点) InverseTransformPoint(Vector3 worldPos) 将世界点转为本地坐标(含位置+缩放+旋转) worldPos:世界点
返回:本地点
子对象相对于父对象的位置计算
世界→本地(方向) InverseTransformDirection(Vector3 worldDir) 仅转换方向(忽略缩放,保留旋转) worldDir:世界方向
返回:本地方向
子弹方向相对于坦克的朝向调整
本地→世界(点) TransformPoint(Vector3 localPos) 将本地点转为世界坐标(含父对象变换) localPos:本地点
返回:世界点
炮塔位置转世界坐标生成子弹
本地→世界(方向) TransformDirection(Vector3 localDir) 仅转换方向(忽略缩放,保留旋转) localDir:本地方向
返回:世界方向
角色朝向转世界方向(技能释放)
世界 ↔ 屏幕(Camera 方法)
方向 方法 说明 关键参数 游戏场景
世界→屏幕 WorldToScreenPoint(Vector3 worldPos) 世界点转屏幕坐标(Z为到摄像机的距离) worldPos:世界点
返回:屏幕点(x,y,depth)
头顶血条位置计算(UI锚点)
屏幕→世界 ScreenToWorldPoint(Vector3 screenPos) 屏幕点转世界坐标(需设置Z轴,默认Z=0为近裁剪平面) screenPos:屏幕点(需设Z)
返回:世界点
鼠标点击生成物体(需Z=10)
世界 ↔ 视口(Camera 方法)
方向 方法 说明 坐标范围 游戏场景
世界→视口 WorldToViewportPoint(Vector3 worldPos) 世界点转视口坐标(X/Y∈[0,1],Z为深度) worldPos:世界点
返回:视口点(0-1)
检测物体是否在屏幕内(视口坐标>0且<1)
视口→世界 ViewportToWorldPoint(Vector3 viewportPos) 视口点转世界坐标(X/Y∈[0,1],Z为深度) viewportPos:视口点(需设Z)
返回:世界点
分屏游戏中左半屏生成物体(X=0.5)

Vector3

基础属性(实例成员)

方法/属性 说明 参数/返回值 示例代码 游戏场景 注意事项
magnitude 向量的模长(只读) float(返回长度) Vector3 dir = target - transform.position;<br>float distance = dir.magnitude; 敌人距离检测、射程判断 等价于Mathf.Sqrt(x²+y²+z²),性能略低于Distance方法
normalized 单位向量(只读,方向不变,长度1) Vector3(返回单位向量) Vector3 normDir = dir.normalized; 方向移动(如角色朝向) 若原向量为零向量,返回零向量(避免除以零)
sqrMagnitude 模长平方(只读,性能更高) float(返回长度²) if (dir.sqrMagnitude < 25) 触发攻击; 快速距离比较(避免开平方) 用于判断“是否在半径5内”时,比magnitude快约50%

静态方法(基础运算)

方法 说明 参数/返回值 示例代码 游戏场景 几何意义
Distance(a, b) 两点间距离(等价于(b-a).magnitude) a,b:Vector3
返回:float
float dist = Vector3.Distance(A, B); 子弹射程、寻路范围 欧几里得距离公式
Angle(from, to) 两向量夹角(0°~180°,度数) from,to:Vector3
返回:float
float angle = Vector3.Angle(forward, dir); 扇形攻击范围、视野检测 基于点乘计算,忽略方向(仅角度)
Cross(a, b) 叉乘(左手坐标系,返回垂直于a、b的向量) a,b:Vector3
返回:Vector3
Vector3 up = Vector3.Cross(right, forward); 判断左右方位(如敌人侧击) 右手法则(数学)→ 左手法则(Unity)
Dot(a, b) 点乘(返回标量,a·b = |a||b|cosθ) a,b:Vector3
返回:float
float dot = Vector3.Dot(forward, dir); 方向相似性判断(如面向目标) 正数→方向相近,负数→方向相反
Lerp(a, b, t) 线性插值(t∈[0,1],a到b的直线过渡) a,b:Vector3
t:float
返回:Vector3
pos = Vector3.Lerp(start, end, Time.deltaTime*3); 平滑移动、镜头跟随 t>1时固定为b,t<0时固定为a
Slerp(a, b, t) 球形插值(保持向量长度,球面过渡) a,b:Vector3
t:float
返回:Vector3
dir = Vector3.Slerp(forward, targetDir, 0.1f); 平滑旋转、物体轨迹 常用于方向向量插值,避免“翻折”
MoveTowards(current, target, maxDistanceDelta) 向目标移动(自动限制步长) current,target:Vector3
maxDistanceDelta:float
返回:Vector3
transform.position = Vector3.MoveTowards(pos, target, speed*dt); 角色寻路、敌人追击 等价于Lerp+Clamp,更安全

Quaternion

构造与属性

方法/属性 类型 说明 参数/返回值 示例代码 游戏场景 注意事项
Quaternion() 构造函数 初始化四元数(默认单位四元数) - Quaternion q = new Quaternion(); 空旋转初始化 等价于Quaternion.identity
AngleAxis(angle, axis) 静态 绕轴旋转(角度→四元数) angle:float(度数)
axis:Vector3
返回:Quaternion
Quaternion q = Quaternion.AngleAxis(90, Vector3.up); 绕Y轴旋转90°(如门开合) 轴向量无需归一化,内部自动处理
Euler(x, y, z) 静态 欧拉角转四元数(按Z→X→Y顺序旋转) x,y,z:float(度数)
返回:Quaternion
Quaternion q = Quaternion.Euler(30, 0, 0); 欧拉角转四元数(角色转头) 可能引发万向节死锁,避免直接修改欧拉角
eulerAngles 实例属性 四元数转欧拉角(只读,自动处理-180~180°) Vector3(返回欧拉角) Vector3 angles = q.eulerAngles; 调试旋转角度 非连续旋转时可能跳跃(如179°→-179°)
identity 静态属性 单位四元数(无旋转) Quaternion(只读) transform.rotation = Quaternion.identity; 重置旋转(如复位操作) 等价于new Quaternion(0,0,0,1)

核心方法(旋转控制)

方法 类型 说明 参数/返回值 示例代码 游戏场景 对比/优化
Lerp(a, b, t) 静态 线性插值(非球面,可能翻转) a,b:Quaternion
t:float
返回:Quaternion
q = Quaternion.Lerp(rotA, rotB, 0.5f); 快速插值(如UI旋转) 比Slerp快20%,但可能“翻折”(适合非方向敏感场景)
Slerp(a, b, t) 静态 球形插值(保持旋转方向,球面过渡) a,b:Quaternion
t:float
返回:Quaternion
transform.rotation = Quaternion.Slerp(rot, targetRot, dt*5); 平滑转向(如角色转头) 计算开销略高,适合方向敏感场景(如镜头旋转)
LookRotation(dir, up) 静态 看向目标方向(自动处理Up轴) dir:Vector3(目标方向)
up:Vector3(默认Vector3.up)
返回:Quaternion
Quaternion look = Quaternion.LookRotation(target - pos); 角色/镜头看向目标(敌人) 等价于Transform.LookAt,但更灵活(可自定义Up轴)
operator * (q1, q2) 运算符 四元数乘法(q1先旋转,q2后旋转) q1,q2:Quaternion
返回:Quaternion
transform.rotation *= Quaternion.AngleAxis(10, Vector3.up); 绕自身轴连续旋转(飞机翻滚) 左乘:世界坐标系;右乘:本地坐标系(默认右乘)
operator * (q, vec) 运算符 向量绕四元数旋转 q:Quaternion
vec:Vector3
返回:Vector3
Vector3 newDir = q * Vector3.forward; 子弹方向计算(扇形发射) 等价于Transform.TransformDirection(vec)

延迟函数

核心方法

方法 作用 参数 返回值 执行时机 典型场景
Invoke(method, time) 延时执行一次方法 method: 函数名(字符串)
time: 延迟时间(秒)
第1次在time秒后执行 倒计时提示、技能冷却触发
InvokeRepeating(method, time, repeat) 延时重复执行方法 method: 函数名
time: 首次延迟
repeat: 重复间隔(秒)
第1次time秒后,之后每repeat秒执行 定时刷新(敌人巡逻、自动射击)
CancelInvoke([method]) 取消延迟函数 method: 可选(取消指定函数,不填则取消所有) 立即生效 对象销毁前清理任务(停止重复播放)
IsInvoking([method]) 判断是否存在待执行的延迟函数 method: 可选(检查指定函数,不填则检查所有) bool 实时判断 避免重复开启延迟(防止多次点击)

对象状态对延迟函数的影响

对象状态 Invoke/InvokeRepeating CancelInvoke 恢复执行
激活(Active) 正常执行 正常取消 -
失活(Inactive) 继续执行(不受影响) 正常取消 激活后继续(仅InvokeRepeating)
销毁(Destroy) 立即终止 无效 无法恢复
脚本禁用(Disable) 继续执行(生命周期未结束) 正常取消 启用后继续(仅InvokeRepeating)

延迟函数 vs 协程(Coroutine)

对比项 延迟函数(Invoke) 协程(Coroutine)
执行控制 简单(字符串函数名) 灵活(可传参、中途中断)
性能 较高(底层优化) 中等(迭代器开销)
参数支持 不支持(需代理) 支持(通过IEnumerator传参)
生命周期依赖 独立于对象激活状态 依赖MonoBehaviour生命周期
适用场景 简单定时任务(冷却、提示) 复杂流程控制(动画插值、异步加载)

协同程序

协程方法

分类 方法 作用 执行机制 适用场景 核心特性
启动 StartCoroutine(ie) 开启协程(迭代器函数) 主线程分时执行,依赖yield控制 异步加载、批量操作(创建1000个物体) 可传参,通过迭代器分步执行
关闭 StopCoroutine(ie/c) 停止指定协程(推荐用返回的Coroutine对象) 立即终止 中途取消(如加载失败) StopAllCoroutines()清空所有
暂停标记 yield return X - null/数字:下一帧
- WaitForSeconds(t):等待t秒
- WaitForFixedUpdate():物理帧
- WaitForEndOfFrame():渲染后
调度器根据X决定恢复时机 分步逻辑(动画插值、截图) 迭代器本质,代码块拆分为多段执行
生命周期 - 组件失活继续执行,物体/组件销毁终止 - - 依赖MonoBehaviour生命周期,适合Unity对象操作

多线程与协程对比表

对比项 多线程(Thread) 协程(Coroutine)
本质 操作系统层面的并行执行,独立于主线程 基于C#迭代器的分时执行,在主线程分支运行
访问Unity对象 不能直接访问Unity相关对象(如transform) 可正常访问Unity对象
性能开销 开销大,创建和销毁线程有资源消耗 开销小,基于迭代器实现
执行顺序 并行执行,执行顺序不确定 分时执行,可控制执行时机
适用场景 复杂逻辑计算(如A星寻路)、网络消息接收 异步加载(文件、场景)、批量创建对象
生命周期管理 需手动关闭,否则会持续运行 组件或物体销毁、物体失活时停止(组件失活除外)

特殊文件夹

路径/文件夹 获取方式 创建要求 读写权限 打包后状态 典型用途 注意事项
Application.dataPath print(Application.dataPath) 自动生成(无需创建) 编辑模式:可读可写
发布后:只读
包含所有资源(只读) 编辑模式调试路径(加载外部配置) 发布后不可写,避免运行时修改
Resources 无(通过Resources.Load访问) 手动创建(Assets下) 编辑/发布:只读 压缩加密(仅Resources.Load可用) 动态加载资源(UI预制体、音效) 打包后无法直接访问路径,避免存放过大资源
StreamingAssets print(Application.streamingAssetsPath) 手动创建(Assets下) 编辑/PC:可读可写
移动:只读
不压缩(保留原始格式) 存放需自定义加载的初始资源(AB包、配置文件) 移动平台仅可读,PC可读写
persistentDataPath print(Application.persistentDataPath) 自动生成(无需创建) 全平台:可读可写 不打包(运行时生成) 存储动态数据(用户存档、下载资源) 路径唯一,适合热更新和持久化存储(推荐使用)
Plugins 无(自动识别) 手动创建(Assets下) 编辑/发布:只读 包含插件(按需编译) 存放平台专属插件(iOS/Android SDK) 不同平台文件需分目录(如Plugins/iOS/Android)
Editor 无(仅编辑器可见) 手动创建(Assets下) 仅编辑器:可读可写 不打包(编辑器脚本专用) 存放编辑器扩展脚本(自定义面板) 内容不会打入游戏包,编辑器模式下生效
Standard Assets 无(自动识别) 手动创建(Assets下) 编辑/发布:只读 包含资源(正常打包) 存放Unity官方标准资源或项目基础资源 避免滥用,按需提取资源;处理好编译顺序冲突

Resources

同步加载

方法 说明 参数/返回值 示例代码 适用场景 注意事项
Resources.Load(path) 同步加载资源(最常用) path: 资源路径(无扩展名)
返回: Object
GameObject cube = Resources.Load<GameObject>("Prefabs/Cube"); 小资源(UI、音效) 阻塞主线程,大资源慎用
LoadAll(path) 加载文件夹下所有资源(按类型过滤) path: 文件夹路径
返回: Object[]
Object[] textures = Resources.LoadAll("Textures"); 批量加载同目录资源 同名资源按类型区分,需强制转换
Load(path) 泛型加载(自动类型转换) T: 目标类型
返回: T
AudioClip bgm = Resources.Load<AudioClip>("Music/BGM"); 明确类型的资源(推荐) 无需手动as,代码更简洁
GameObject 加载 需配合Instantiate实例化 - Instantiate(Resources.Load<GameObject>("Player")); 预制体动态生成 直接加载GameObject不实例化会占用内存,但无法卸载

异步加载

方法 说明 执行机制 示例代码 适用场景 核心优势
LoadAsync(path) 异步加载(返回ResourceRequest) 新开线程加载,主线程检测完成 ResourceRequest req = Resources.LoadAsync<Texture>("BigTex"); 大资源(模型、高清纹理) 避免主线程卡顿
回调监听 req.completed += OnLoadEnd; 加载完成触发回调 void OnLoadEnd(AsyncOperation op) { tex = op.asset as Texture; } 简单加载后逻辑 代码简洁,不支持多资源并行加载
协程加载 yield return req;while (!req.isDone) 协程分时检测加载状态 IEnumerator LoadCoroutine() { yield return req; 渲染纹理(); } 复杂逻辑(进度条、多资源) 支持并行加载,灵活控制加载流程
进度跟踪 req.progress(0~1,非精确) 实时获取加载进度 progressBar.value = req.progress; 显示加载进度条 移动端可能因压缩导致进度跳跃

资源卸载

方法 说明 适用资源 示例代码 最佳实践 禁忌
UnloadAsset(asset) 卸载指定资源(非GameObject) 纹理、音效、文本等非实例化资源 Resources.UnloadAsset(tex); 释放不再使用的单次加载资源 禁止卸载GameObject预制体(会报错)
UnloadUnusedAssets() 卸载未使用的缓存资源(配合GC.Collect) 所有未引用的Resources资源 Resources.UnloadUnusedAssets(); GC.Collect(); 场景切换时清理内存 需在主线程调用,避免频繁调用
GameObject 卸载 实例化对象需Destroy()释放 实例化的预制体 Destroy(instance.gameObject); 动态生成的对象(子弹、UI) 仅销毁实例,预制体缓存仍存在

SceneManager

场景同步加载

实现方式:使用 SceneManager.LoadScene 进行场景同步加载,需引用 UnityEngine.SceneManagement 命名空间。

using UnityEngine.SceneManagement;

// 场景同步切换
SceneManager.LoadScene("Lesson21_场景异步加载Test");

缺点:切换场景时会删除当前场景所有对象,若场景对象过多会导致卡顿。

场景异步加载

事件回调异步加载场景

原理:利用 SceneManager.LoadSceneAsync 异步加载场景,通过 AsyncOperationcompleted 事件回调处理加载完成逻辑。

// 封装的场景异步加载方法
private void LoadSceneAsyncWithCallback(string sceneName)
{
    // 异步加载场景
    AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName);
    // 加载完成回调
    asyncOperation.completed += (aO) =>
    {
        print("加载结束");
    };
    asyncOperation.completed += AsyncLoadOver;
}

// 异步加载场景回调
private void AsyncLoadOver(AsyncOperation ao)
{
    print("AsyncLoadOver");
}

注意事项:即使对象销毁,异步加载回调仍会执行,因回调存储在事件中。

协程异步加载场景

原理:通过协程调用 SceneManager.LoadSceneAsync,加载过程中可执行其他逻辑(如更新进度条)。

// 异步加载场景协程函数
IEnumerator CoroutineAsyncLoadScene(string name)
{
    // 异步加载场景
    AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(name);

    print("异步加载过程中打印的信息");

    // 利用场景异步加载的进度更新进度条(不太准确)
    while (!asyncOperation.isDone)
    {
        print(asyncOperation.progress);
        yield return null;
    }

    // 等待异步加载结束
    yield return asyncOperation;
    print("异步加载结束后打印的信息");
}

常用方法和属性

分类 属性/方法 描述
属性 activeScene 获取或设置当前活动场景(运行场景,操作基于此场景)
属性 sceneCount 获取当前加载的场景数量(管理多个同时加载的场景)
属性 sceneCountInBuildSettings 获取Build Settings中场景总数(了解项目场景数量)
方法 GetSceneAt(int index) 根据索引获取已加载的场景(索引0到sceneCount - 1)
方法 GetSceneByName(string name) 根据名称获取已加载的场景(未找到返回空Scene对象)
方法 GetSceneByPath(string path) 根据路径获取已加载的场景(路径相对于Assets文件夹)
方法 UnloadSceneAsync(int sceneBuildIndex) 异步卸载指定索引的场景(释放内存资源)
方法 UnloadSceneAsync(string sceneName) 异步卸载指定名称的场景(释放内存资源)

LineRenderer

LineRenderer组件参数

分类 参数 说明 常用值/操作
场景点编辑 Simplify Preview 开启后线段预览更明显(简化密集点显示) 勾选(调试用)/ 取消(正式)
Tolerance 点简化宽容度(值越大,线段越粗略) 1(默认,密集点时调大)
编辑点操作 Subdivide Selected 框选相邻点后插入新点(细化拐角) 鼠标框选+点击(需启用编辑模式)
添加点模式 Input Mode 点创建方式:
- Mouse Position:摄像机位置创建
- Physics Raycast:射线碰撞点创建
Physics Raycast(勾选)
LayerMask 射线检测层(仅响应指定层的点击) 勾选目标层(如“Ground”“UI”)
Min VertexDistance 拖动创建点的最小间隔(避免过密) 0.1~0.5米(根据手感调整)
通用属性 Loop 首尾点连接(闭合图形/开放线段) true(攻击范围)/ false(轨迹线)
PositionCount 线段总点数(需先设置,再赋值) 2(直线)~ 100(复杂曲线)
Use World Space 坐标系模式:
- true:世界坐标
- false:本地坐标
false(角色激光线)
渲染属性 Start/End Width 线段首尾宽度(支持曲线插值) 0.01f(纤细)~ 0.5f(粗壮)
Start/End Color 线段渐变颜色(需材质支持) Color.red → Color.blue(渐变)
Corner/End Vertices 拐角/末端圆角精度(值越大越圆滑) 2(默认)~ 5(高精度圆角)
Material 线段材质(支持纹理/着色器,如火焰、激光) 自定义材质(需关联主纹理)
光照相关 Generate Lighting Data 启用光照计算(材质需光源) true(有光照场景)/ false(无光照)
Cast/Receive Shadows 投射/接收阴影(增加真实感) 按需勾选(默认关闭以优化性能)
高级设置 Alignment 线段对齐方式:
- View:始终朝向相机
- Transform Z:沿物体Z轴方向
View(UI指引线)/ Transform Z(模型轮廓)
Texture Mode 纹理映射模式:
- Stretch:单次拉伸
- Tile:平铺重复
Stretch(激光纹理)/ Tile(铁链纹理)
性能优化 Dynamic Occludee 动态遮挡剔除(减少不可见线段渲染) 勾选(复杂场景)
排序控制 Sorting Layer 渲染层级(避免被UI遮挡) 自定义层级(如“Foreground”)

LineRenderer参数和方法

功能 API 说明 注意事项
动态创建线段 AddComponent() 给GameObject添加LineRenderer组件 需先创建空物体
设置闭合状态 lineRenderer.loop = true; 闭合线段(首尾相连) 需配合PositionCount ≥ 2
设定宽度 lineRenderer.startWidth = 0.02f;
lineRenderer.endWidth = 0.02f;
设置线首尾宽度,支持动态修改 实时刷新需在Update中调用
设定颜色 lineRenderer.startColor = Color.white;
lineRenderer.endColor = Color.red;
设置线首尾颜色,支持动态修改 实时刷新需在Update中调用
设置材质 material = Resources.Load<Material>("火焰材质");
lineRenderer.material = material;
赋值自定义材质,支持纹理动画 材质需包含主纹理(Main Tex)
设置点个数 lineRenderer.positionCount = 4; 设置或获取顶点数 设置点时,要先设置点的个数
批量设置点 lineRenderer.SetPositions(new Vector3[] { new Vector3(0,0,0), new Vector3(0,0,5), new Vector3(5,0,5)}); 一次性设置所有点 需先定义PositionCount,数组长度需 ≤ PositionCount
单点修改 lineRenderer.SetPosition(3, new Vector3(5, 0, 0)); 单独修改某点坐标 index从0开始,坐标基于useWorldSpace的设置
坐标系切换 lineRenderer.useWorldSpace = false; 切换为本地坐标系(线段随物体移动) 动态切换需谨慎,可能导致坐标混乱
设置光照影响 lineRenderer.generateLightingData = true; 配置线以生成法线和切线,让场景光照影响线 若材质需要光照效果,需开启此选项

物理系统-范围检测

范围检测基础

分类 要点 关键细节
定义 瞬时检测指定范围内的对象(无实体碰撞器,仅计算) 用于攻击范围、触发判定等瞬时逻辑
必备条件 - 对象需含碰撞器(Collider)
- 检测代码执行时触发
无刚体也可检测(区别于碰撞事件)
层级过滤 LayerMask 位运算(左移+或运算) 1 << LayerMask.NameToLayer("Enemy") 表示仅检测Enemy层
触发器处理 QueryTriggerInteraction 枚举:
- UseGlobal(全局设置)
- Collide(检测触发器)
- Ignore(忽略触发器)
全局设置路径:Edit > Project Settings > Physics > Queries Hit Triggers

核心方法

API 形状 参数 返回值 典型场景 优化建议
OverlapBox 盒状 中心坐标, 半尺寸, 旋转, 层掩码, 触发器模式 Collider[](动态数组) 矩形攻击范围(地刺、AOE) 避免高频调用(每次生成新数组)
OverlapBoxNonAlloc 盒状 中心坐标, 半尺寸, 预分配数组, 层掩码, 触发器模式 int(碰撞数) 高频检测(如每帧扫描) 预分配数组(colliders = new Collider[10])减少GCAlloc
OverlapSphere 球形 中心坐标, 半径, 层掩码, 触发器模式 Collider[](动态数组) 圆形范围(角色拾取、技能半径) 配合LayerMask过滤非目标层
OverlapSphereNonAlloc 球形 中心坐标, 半径, 预分配数组, 层掩码, 触发器模式 int(碰撞数) 性能敏感场景(子弹爆炸检测) 提前计算半径(避免重复计算)
OverlapCapsule 胶囊状 端点1, 端点2, 半径, 层掩码, 触发器模式 Collider[](动态数组) 柱状范围(角色近战攻击、NPC视野) 用Vector3.ProjectOnPlane计算地面投影
OverlapCapsuleNonAlloc 胶囊状 端点1, 端点2, 半径, 预分配数组, 层掩码, 触发器模式 int(碰撞数) 复杂地形检测(爬墙判定) 缓存端点坐标(减少重复赋值)

射线检测

分类 核心内容 关键细节
基础概念 瞬时发射射线,检测与碰撞器的交点(无实体,仅计算) 适用:鼠标选择、射线攻击、视线阻挡判定
条件:目标需有碰撞器(无需刚体)
Ray 类 - 构造:new Ray(origin, direction)
- 摄像机射线:Camera.ScreenPointToRay(鼠标位置)
origin:射线起点
direction:方向向量(非终点)
屏幕点转射线用于UI/场景交互
核心API Physics.Raycast(单碰撞)
参数:(射线/起点, 方向, out 碰撞信息, 距离, 层掩码, 触发器模式)
返回:bool
用途:检测首个碰撞目标(如射击命中)
层掩码:1 << 层号(如1 << 8)
Physics.RaycastAll(多碰撞)
参数:(射线/起点, 方向, 距离, 层掩码, 触发器模式)
返回:RaycastHit[](无序数组)
用途:获取所有碰撞目标(如区域内敌人)
Physics.RaycastNonAlloc(预分配)
参数:(射线/起点, 方向, 预分配数组, 距离, 层掩码, 触发器模式)
返回:int(碰撞数)
优化:避免GCAlloc,适合高频检测
RaycastHit - collider:碰撞器
- point:交点坐标
- normal:碰撞面法线
- distance:起点到交点距离
normal用于特效朝向(如弹孔法线对齐)
point用于生成命中特效(如子弹痕迹)
参数顺序 必记顺序:
1. 射线/起点
2. 方向(非必填,重载支持)
3. out 碰撞信息(单碰撞)
4. 距离(0=无限)
5. 层掩码
6. 触发器模式
易错:层掩码误填为第2参数(正确:第4/5位)
示例:Raycast(ray, out hit, 100, 1<<8)
触发器处理 QueryTriggerInteraction枚举:
- Collide(检测触发器)
- Ignore(忽略)
- UseGlobal(全局设置)
全局设置路径:Project Settings > Physics > Queries Hit Triggers(默认检测触发器)
性能优化 - 预分配数组:RaycastHit[] hits = new RaycastHit[10]
- 缓存射线:避免重复创建(如Camera.main缓存)
NonAlloc比RaycastAll少生成临时数组,适合高频场景(如技能检测)
典型场景 1. 鼠标选物体:ScreenPointToRay + Raycast(层过滤UI)
2. 射线攻击:检测首个碰撞目标(distance限制射程)
3. 视线阻挡:Raycast返回distance与预设值比较
示例:FPS射击检测墙体遮挡:if (hit.distance < 敌人距离) 被遮挡

25.3 面试题精选

基础题

1. Mathf.Lerp 的两种用法有何区别?分别适合什么场景?

题目

Mathf.Lerp(a, b, t) 中参数 t 的使用方式不同会带来什么效果差异?「先快后慢」和「匀速接近」两种写法分别怎么实现?

深入解析
  • 用法一(先快后慢)current = Mathf.Lerp(current, target, Time.deltaTime * speed),每帧用当前位置作为起点,t 固定较小值,初始差距大时变化快,接近目标时变化慢,产生阻尼效果。
  • 用法二(匀速接近)t += Time.deltaTime; current = Mathf.Lerp(start, end, t),t 从 0 累加到 1,线性过渡,t≥1 时固定为目标值。
  • 前者适合镜头跟随、物体平滑停止;后者适合倒计时、线性动画。
答题示例

第一种每帧用当前值当起点,t 固定,越近越慢,像阻尼;第二种 t 累加,匀速走完。

镜头跟随用第一种,倒计时用第二种。

参考文章
  • 2.3D数学-Mathf数学计算公共类

2. 世界坐标系、本地坐标系、屏幕坐标系、视口坐标系各自的原点和轴方向是什么?

题目

请简述 Unity 中四大坐标系的原点位置、轴方向以及典型使用场景。

深入解析
  • 世界坐标系:原点为场景中心(0,0,0),X→右、Y→上、Z→前,用于物体绝对位置存储、碰撞检测。
  • 本地坐标系:原点为父对象位置,轴方向随父对象旋转/缩放变化,用于子对象相对父对象的位置调整。
  • 屏幕坐标系:原点为屏幕左下角(0,0),X→右、Y→上、Z→摄像机距离,用于鼠标位置获取、UI 元素定位。
  • 视口坐标系:原点为左下角(0,0),X/Y 范围均为 0~1,用于分屏显示、全屏适配。
答题示例

世界坐标全局唯一,本地坐标相对父对象;屏幕坐标以像素为单位,视口坐标归一化到 0~1。

鼠标位置用屏幕坐标,分屏适配用视口坐标。

参考文章
  • 4.3D数学-坐标系

3. Vector3.magnitude、normalized、sqrMagnitude 三者的区别与性能考量?

题目

获取向量长度、方向、长度平方分别用哪个属性?为什么说 sqrMagnitude 性能更高?什么场景适合用 sqrMagnitude?

深入解析
  • magnitude:返回向量模长(开平方后的实际长度),等价于 Mathf.Sqrt(x²+y²+z²)
  • normalized:返回单位向量(方向不变,长度为 1),零向量返回零向量。
  • sqrMagnitude:返回模长平方,省去开平方运算,性能比 magnitude 高约 50%。
  • 适合用于距离比较:判断「是否在半径 5 内」时,比较 sqrMagnitude < 25 即可,无需计算真实距离。
答题示例

magnitude 是真实长度,normalized 是单位向量,sqrMagnitude 是长度平方。

只比较距离大小时用 sqrMagnitude 省开方,性能更好。

参考文章
  • 5.3D数学-Vector3向量-向量模长和单位向量

4. Invoke 与 InvokeRepeating 的区别?对象失活或销毁时延迟函数如何表现?

题目

InvokeInvokeRepeating 各自执行几次?对象被 SetActive(false)Destroy 后,已注册的延迟函数会怎样?

深入解析
  • Invoke:延时执行一次,参数为方法名(字符串)和延迟时间。
  • InvokeRepeating:延时后重复执行,参数为方法名、首次延迟、重复间隔。
  • 对象失活:延迟函数继续执行,不受影响;激活后 InvokeRepeating 会继续。
  • 对象销毁:延迟函数立即终止,无法恢复。
  • 脚本禁用:延迟函数继续执行(生命周期未结束)。
答题示例

Invoke 执行一次,InvokeRepeating 重复执行。

失活不影响延迟函数,销毁则立即终止;脚本禁用也不影响。

参考文章
  • 14.MonoBehavior中的重要内容-延迟函数

进阶题

1. TransformPoint 与 TransformDirection 的核心区别是什么?

题目

将本地坐标转为世界坐标时,TransformPointTransformDirection 分别处理什么类型的数据?是否受缩放影响?

深入解析
  • TransformPoint:处理本地空间中的点(位置),受父对象的位置、旋转、缩放共同影响。用于「在角色前方 2 米生成物体」等场景。
  • TransformDirection:处理方向向量,只受旋转影响,不受缩放影响。用于「将角色本地前进方向转为世界方向」。
  • 还有 TransformVector:受旋转和缩放影响,不受位置影响。
  • 对应的逆变换:InverseTransformPointInverseTransformDirectionInverseTransformVector
答题示例

Point 处理位置,受缩放影响;Direction 处理方向,只受旋转影响。

在角色前方生成物体用 TransformPoint,获取角色朝向用 TransformDirection。

参考文章
  • 4.3D数学-坐标系

2. Vector3.Angle 返回的角度范围是多少?如何判断目标在左侧还是右侧?

题目

Vector3.Angle(from, to) 返回的角度范围是多少?为什么它无法区分左右?如何结合叉乘判断目标在左侧还是右侧?

深入解析
  • Angle 返回 0°~180° 的无符号角度,基于点乘计算 cosθ = (a·b)/(|a||b|)无法区分方向
  • 叉乘判断左右Vector3 cross = Vector3.Cross(forward, toTarget),在 Unity 左手坐标系中:
    • cross.y > 0 → 目标在右侧
    • cross.y < 0 → 目标在左侧
  • 叉乘结果垂直于两向量所在平面,方向由左手法则决定。
答题示例

Angle 只返回 0~180 度,不分左右。

用 Cross 叉乘,结果 y 分量正负可判断左右:正为右,负为左。

参考文章
  • 7.3D数学-Vector3向量-向量点乘
  • 8.3D数学-Vector3向量-向量叉乘

3. Quaternion.Euler 与欧拉角直接赋值 transform.eulerAngles 有何风险?

题目

为什么 Unity 推荐用四元数处理旋转而不是直接操作欧拉角?什么是「万向节死锁」?Quaternion.Euler 如何避免这个问题?

深入解析
  • 欧拉角:直观但存在万向节死锁问题——当绕某轴旋转 90° 时,另外两个轴可能重合,导致丢失一个自由度。
  • 四元数:无万向节死锁,插值平滑,是 Unity 内部存储旋转的方式。
  • Quaternion.Euler(x, y, z) 将欧拉角转为四元数,避免直接修改 eulerAngles 带来的死锁风险。
  • 读取 eulerAngles 时可能跳跃(如 179°→-179°),因为内部是四元数转换结果。
答题示例

欧拉角直观但有万向节死锁风险;四元数无此问题且插值平滑。

用 Quaternion.Euler 转换后再赋值 rotation,避免直接改 eulerAngles。

参考文章
  • 10.3D数学-Quaternion四元数-为何使用四元数
  • 11.3D数学-Quaternion四元数-四元数是什么

4. StartCoroutine 与 Invoke 的核心区别是什么?各自适合什么场景?

题目

协程 StartCoroutine 与延迟函数 Invoke 在参数传递、执行控制、生命周期依赖上有何不同?各举一个典型使用场景。

深入解析
  • 参数支持:Invoke 不支持传参(需借助代理或全局变量);协程支持传参(通过 IEnumerator 方法参数)。
  • 执行控制:Invoke 简单但只能延时/重复;协程可中途 yield 暂停、条件等待、分帧执行
  • 生命周期依赖:Invoke 独立于对象激活状态(失活仍执行);协程依赖 MonoBehaviour 生命周期(对象失活时协程停止)。
  • 性能:Invoke 底层优化较好;协程有迭代器开销。
  • 场景:Invoke 适合简单定时(冷却、提示);协程适合复杂流程(异步加载、动画插值、分帧创建大量物体)。
答题示例

Invoke 简单但不能传参,失活仍执行;协程灵活可传参可暂停,但依赖对象激活。

简单冷却用 Invoke,异步加载或分帧处理用协程。

参考文章
  • 14.MonoBehavior中的重要内容-延迟函数
  • 15.MonoBehavior中的重要内容-协同程序

5. Resources.Load 与 AssetBundle 加载资源的主要区别?

题目

Resources.Load 加载资源有什么限制?为什么说生产环境更推荐使用 AssetBundle 或 Addressables?

深入解析
  • Resources 文件夹:打包时所有资源会被打入主包,无法按需加载,增加包体大小和内存占用。
  • Resources.Load:同步加载会阻塞主线程,异步加载 LoadAsync 可缓解但仍需等待。
  • AssetBundle:资源独立打包,可按需下载、卸载、热更新,适合大型项目。
  • Addressables:Unity 官方推荐的资源管理方案,封装了 AssetBundle,提供更友好的 API。
  • Resources 适合小型项目或配置文件;生产环境推荐 AssetBundle/Addressables。
答题示例

Resources 打包时全进主包,无法按需加载,增加包体。

AssetBundle 可独立打包、按需下载、热更新,适合大型项目。

参考文章
  • 17.Resources资源动态加载-Unity中特殊文件夹
  • 18.Resources资源动态加载-Resources同步加载

6. Physics.OverlapBox 与 Physics.CheckSphere 的区别?

题目

范围检测中 Physics.OverlapBoxPhysics.CheckSphere 各自返回什么?分别适合什么场景?

深入解析
  • OverlapBox:返回碰撞器数组 Collider[],获取盒形范围内所有碰撞到的物体,适合获取范围内敌人列表、拾取物列表。
  • CheckSphere:返回 bool,只判断球形范围内是否有碰撞体,不返回具体对象,适合判断「前方是否有障碍物」。
  • 类似的还有 OverlapSphere(返回数组)、OverlapCapsule 等。
  • 性能:Check 系列只判断有无,比 Overlap 系列更快。
答题示例

OverlapBox 返回碰撞器数组,用于获取范围内物体列表;CheckSphere 返回布尔,只判断有无碰撞。

要列表用 Overlap,只判断有无用 Check。

参考文章
  • 23.核心系统-物理系统-范围检测

深度题

1. Quaternion.Slerp 与 Quaternion.Lerp 的区别?为何旋转插值推荐 Slerp?

题目

四元数插值中,Slerp(球形线性插值)与 Lerp(线性插值)在效果和性能上有何差异?为什么旋转插值推荐使用 Slerp?

深入解析
  • Lerp:线性插值,在四元数空间中直线路径,可能产生角速度不均匀甚至「翻折」现象,适合非方向敏感场景(如 UI 旋转)。
  • Slerp:球形插值,在四元数空间中沿大圆弧路径,保持恒定角速度,旋转更平滑自然。
  • 性能:Lerp 比 Slerp 快约 20%,但旋转效果不如 Slerp 稳定。
  • 选择:角色转向、镜头跟随等方向敏感场景用 Slerp;UI 简单旋转可用 Lerp。
  • 四元数插值 t 值通常用 Time.deltaTime * speed,实现平滑过渡。
答题示例

Lerp 走直线可能翻折,Slerp 走球面弧线更平滑。

角色转向用 Slerp,UI 简单旋转可用 Lerp 省性能。

参考文章
  • 12.3D数学-Quaternion四元数-四元数常用方法

2. 协程的底层原理是什么?yield return null 与 yield return new WaitForSeconds 有何本质区别?

题目

Unity 协程基于 C# 的什么机制实现?yield return nullyield return WaitForSeconds 在底层处理上有何不同?

深入解析
  • 底层原理:协程基于 C# 迭代器(IEnumerator)yield 语句实现。Unity 在每帧检测协程的 MoveNext,根据 yield 返回值决定何时继续执行。
  • yield return null:返回 null,Unity 在下一帧继续执行该协程。
  • yield return new WaitForSeconds(t):返回 WaitForSeconds 对象,Unity 会等待指定秒数后再继续执行,底层比较 Time.time 与记录的结束时间。
  • yield return new WaitForEndOfFrame:等待渲染完成后继续。
  • yield return new WaitForFixedUpdate:等待下一个 FixedUpdate 后继续。
  • 性能优化:避免在循环中 new WaitForSeconds(),应缓存复用。
答题示例

协程基于迭代器,Unity 每帧调 MoveNext 决定是否继续。

yield null 下一帧继续;WaitForSeconds 等指定时间后继续,底层比较时间戳。

参考文章
  • 15.MonoBehavior中的重要内容-协同程序
  • 16.MonoBehavior中的重要内容-协同程序原理

3. 场景异步加载时,allowSceneActivation 为 false 时加载进度停在 0.9 的原因?

题目

使用 SceneManager.LoadSceneAsync 异步加载场景时,将 allowSceneActivation 设为 false 后,为什么进度会停在 0.9?如何正确使用这个特性?

深入解析
  • allowSceneActivation = false:场景加载完成后不会自动激活,进度停在 0.9 表示「加载完成但未激活」。
  • 设计意图:允许在加载完成后做一些准备工作(如显示提示、初始化数据),再手动设置 allowSceneActivation = true 激活场景。
  • 正确用法
    1. 开始异步加载,设置 allowSceneActivation = false
    2. 等待 progress >= 0.9f(表示加载完成)
    3. 执行准备工作(显示提示、初始化等)
    4. 设置 allowSceneActivation = true 激活场景
  • 注意:进度 0.9 是 Unity 的约定值,实际判断应 progress >= 0.9f
答题示例

allowSceneActivation 为 false 时,加载完成停在 0.9,表示「已加载未激活」。

可在此时做准备工作,再设为 true 激活场景,实现加载完成后的可控切换。

参考文章
  • 21.场景异步加载

4. Physics.Raycast 中 LayerMask 的位运算原理是什么?

题目

Physics.Raycast 的 LayerMask 参数如何表示「只检测某些层」?1 << LayerMask.NameToLayer("Enemy") 这个写法是什么意思?

深入解析
  • LayerMask 本质:32 位整数,每一位对应一个层(0~31),1 表示检测该层,0 表示忽略。
  • 位运算原理
    • 1 << n:将 1 左移 n 位,得到第 n 层的掩码。例如 1 << 8 表示第 8 层。
    • LayerMask.NameToLayer("Enemy"):返回层名对应的层索引(0~31)。
    • 1 << LayerMask.NameToLayer("Enemy"):得到 Enemy 层的掩码。
  • 组合多个层:用按位或 |,如 (1 << 8) | (1 << 9) 表示检测第 8 和第 9 层。
  • 排除层:用按位取反 ~,如 ~(1 << 2) 表示忽略第 2 层(Ignore Raycast 常用)。
  • 性能:指定 LayerMask 可减少不必要的碰撞检测,提高性能。
答题示例

LayerMask 是 32 位整数,每位代表一层。1 << n 得到第 n 层的掩码。

组合多层用 |,排除层用 ~。指定 LayerMask 可减少无效检测。

参考文章
  • 24.核心系统-物理系统-射线检测


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏