Unity学习笔记——基础(贰)
学习笔记主要来源于唐老狮的Unity课程,经过个人简单整理而成。目前笔记可能有些地方写的不够好,若发现问题后续会继续完善。笔记总共三个部分:
三、基础知识
1、游戏物体GameObject
Unity 的 GameObject 类用于表示任何可以存在于场景中的事物。
(1)常用成员变量
this.gameObject.name // 名字
this.gameObject.activeSelf // 对象是否激活
this.gameObject.isSstatic // 对象是否静态
this.gameObject.layer // 层级
this.gameObject.tag // 标签
this.gameObject.transform // 对象变换组件
(2)对象创建与销毁
GameObject.CreatePrimitive(type); // 创建自带几何体
GameObject.Instantiate(original); // 实例化对象(克隆)
GameObject.Destroy(obj); // 销毁对象
GameObject.Destroy(obj , time); // 延迟销毁
GameObject.DestroyImmediate(obj); // 立即销毁
GameObject.DontDestroyOnLoad(obj); // 过场景不被销毁
(3)对象查找
GameObject.Find(name); // 在场景中查找对象
GameObject.FindGameObjectWithTag(tag); // 在场景中查找指定tag的对象
GameObject.FindGameObjectsWithTag(tag); // 在场景中查找指定tag的多个对象
GameObject.FindObjectsOfType<T>(); // 在场景中查找指定类型的对象(属于Object类的方法)
(4)常用成员方法
this.gameObject.AddComponent<T>(); // 添加脚本
this.gameObject.GetComponent<T>(); // 获取脚本
this.gameObject.CompareTag(tag); // 对比标签(等价:this.gameObject.tag == tagName;)
this.gameObject.SetActive(value); // 设置对象激活状态
(5)执行方法
this.gameObject.SendMessage(methodName); // 执行对象上指定名称的方法(在对象所有脚本中寻找)
this.gameObject.BroadcastMessage(methodName); // 执行自己和子对象的指定名方法
this.gameObject.SendMessageUpwards(methodName); // 执行自己和父对象的指定名方法
2、时间Time
用于从 Unity 获取时间信息。
常用静态变量如下:
Time.timeScale; // 时间缩放比例
Time.deltaTime; // 帧间隔时间
Time.unscaledDeltaTime; // 帧间隔时间,不受timeScale影响
Time.time // 游戏从开始到现在的时间
Time.unscaledtime // 游戏从开始到现在的时间,不受timeScale影响
Time.fixedDeltaTime // 物理帧间隔时间
Time.fixedUnscaledDeltaTime // 物理帧间隔时间,不受timeScale影响
Time.frameCount // 从游戏开始到现在跑了多少帧
3、向量Vector
Unity 提供了Vector2和Vector3类分别表示2D和3D空间中的向量和点。
里面提供了很多关于向量操作的函数,这里以Vector3为例。
(1)获取常见的向量
Vector3.zero; // 零坐标
Vector3.right; // 世界坐标正右方
Vector3.left; // 世界坐标正左方
Vector3.forward; // 世界坐标正前方
Vector3.back; // 世界坐标正后方
Vector3.up; // 世界坐标正上方
Vector3.down; // 世界坐标正下方
(2)向量模长与单位化
vec.magnitude; // 向量模长
vec.normalized; // 单位向量
(3)常用方法
Vector3.Distance(a,b); // 计算两点间的距离
Vector3.Dot(a, b); // 点乘
Vector3.Angle(a, b); // 计算两个向量间的夹角
Vector3.Cross(a, b); // 叉乘
Vector3.Lerp(start, end, t); // 线性插值
Vector3.Slerp(start, end, t); // 球形插值
- 关于线性插值与球形插值
线性插值是在两点间的直线进行插值。球形插值中,向量被视为方向而不是空间中的点,通过角度进行插值。

4、变换Transform
用于处理游戏对象的位置、旋转和缩放,以及与父和子游戏对象的层级关系。
(1)常用属性
this.transform.position; // 世界坐标位置
this.transform.localPosition; // 本地坐标位置
this.transform.eulerAngles; // 欧拉角
this.transform.localEulerAngles // 本地坐标的欧拉角
this.transform.lossyScale; // 缩放
this.transform.localScale; // 本地坐标的缩放
this.transform.forward; // 物体正前方
this.transform.up; // 物体正上方
this.transform.right; // 物体正右方
(2)变换
this.transform.Translate(translation, relativeTo); // 朝指定方向和距离移动。参数2表示相对坐标系,默认为self
this.transform.Rotate(eulers, relativeTo); // 绕指定轴旋转
this.transform.Rotate(axis, angle, relativeTo); // 绕指定轴旋转(重载)
this.transform.RotateAround(point, axis, angle); // 绕某个点的指定轴旋转
this.transform.LookAt(target); // 看向某个对象
this.transform.LookAt(worldPosition); // 看向某个点
- 关于
Translate方法,由于两个参数都可以填入世界坐标或本地坐标,总共有四种可能:
transform.Translate(Vector3.forward * Time.deltaTime, Space.World); // 始终向世界坐标Z轴正方向移动
transform.Translate(transform.forward * Time.deltaTime, Space.World); // 始终朝物体正前方移动
transform.Translate(Vector3.forward * Time.deltaTime, Space.Self); // 始终朝物体正前方移动
transform.Translate(transform.forward * Time.deltaTime, Space.Self); // 不推荐使用,自身坐标系下,transform.forward会导致重复计算,导致方向错误
(3)父子关系
this.transform.parent; // 父对象
this.transform.childCount; // 子对象数量
this.transform.SetParent(parent,worldPositionStays); // 设置父对象。参数2表示是否保持原本的世界坐标位置不动
this.transform.DetachChildren(); // 与子对象断开父子关系
this.transform.Find(name); // 找到子对象(可以找到失活对象,通过"/"号分隔可以找到子对象的子对象)
this.transform.GetChild(index); // 通过索引获取子对象
this.transform.IsChildOf(parent); // 判断是否是parent的子对象
this.transform.GetSiblingIndex(); // 获取作为子对象的索引
this.transform.SetAsFirstSibling(); // 设置为第一个子对象
this.transform.SetAsLastSibling(); // 设置为最后一个子对象
this.transform.SetSiblingIndex(索引); // 设置自己的位置
(5)坐标系转换
Transform提供了世界坐标与本地坐标相互转换的方法,具体在坐标系那节有详细写出。
5、调试Debug
Debug.Log(message); // 打印信息
Debug.LogError(message); // 打印错误信息
Debug.LogWarning(message); // 打印警告信息
Debug.DrawLine(start, end, color, duration); // 调试画线
Debug.DrawRay(start, dir, color, duration); // 调试发射射线
6、输入Input
Unity 通过两个独立的系统提供输入支持:一是默认的老输入系统Input Manager,另一个是新输入系统Input System(需安装包)。Input System篇幅较多,这里只讲默认的Input Manager。
- 在
Project Settings/Player/Other Settings/Active Input Handling中,可以选择新老输入系统的切换。 Input Manager的一些按键可在Project Settings/Input Manager中进行相关设置。
(1)键盘输入
Input.GetKeyDown(keyCode); // 键盘按下
Input.GetKeyUp(keyCode); // 键盘抬起
Input.GetKey(keyCode); // 键盘长按
(2)鼠标输入
方法中传入的数字代表:0左键,1右键,2中键。
Input.mousePosition; // 鼠标位置(屏幕坐标系)
Input.mouseScrollDelta; // 鼠标滚轮滚动(-1往下滚,1往上滚)
Input.GetMouseButtonDown(button); // 鼠标按下
Input.GetMouseButtonUp(button); // 鼠标抬起
Input.GetMouseButton(button); // 鼠标长按
(3)按键检测
Input.anyKey; // 是否有任意键或鼠标长按
Input.anyKeyDown; // 是否有任意键或鼠标按下
(4)获取轴向
Input.GetAxis(axisName); // 获取某个键的值
Input.GetAxisRaw(axisName); // 获取某个键的值(只有-1、0、1三个固定值)
7、鼠标Cursor
Cursor.visible; // 鼠标是否可见
Cursor.lockState; // 锁定鼠标状态
Cursor.SetCursor(texture, hotspot, cursorMode); // 设置鼠标图片(参数:图片,偏移位置,光标模式)
8、屏幕Screen
Screen 类可用于获取支持的分辨率列表、切换当前分辨率、 隐藏或显示系统鼠标指针。
(1)分辨率
Screen.currentResolution; // 获取当前屏幕分辨率
Screen.width; // 获取屏幕窗口当前宽
Screen.height; // 获取屏幕窗口当前高
Screen.SetResolution(width,height,fullscreen); // 设置分辨率
(2)设置
Screen.sleepTimeout; // 屏幕休眠模式
Screen.fullScreen; // 运行时是否全屏模式
Screen.fullScreenMode; // 全屏模式
- 全屏模式枚举:
FullScreenMode.ExclusiveFullScreen; // 独占全屏
FullScreenMode.FullScreenWindow; // 全屏窗口
FullScreenMode.MaximizedWindow; // 最大化窗口
FullScreenMode.Windowed; // 窗口模式
(3)移动设备
Screen.autorotateToLandscapeLeft; // 是否允许手机自动旋转为左横向,Home在左
Screen.autorotateToLandscapeRight; // 是否允许手机自动旋转为右横向,Home在右
Screen.autorotateToPortrait; // 是否允许手机自动旋转为纵向,Home在下
Screen.autorotateToPortraitUpsideDown; // 是否允许手机自动旋转为纵向,Home在上
9、摄像机Camera
摄像机是供玩家观看世界的设备。
(1)Camera组件
-
Clear Flags:背景清除模式,控制相机每次渲染时如何处理背景。 -
Culling Mask:剔除遮罩,相机只渲染对应层级的物体。 -
Projection:投影模式。 -
Clipping Planes:裁剪平面,控制相机的可见范围。 -
Viewport Rect:视口矩形,控制相机画面在屏幕上的绘制位置,主要用于分屏游戏。 -
Depth:渲染深度决定相机的渲染顺序,深度值越大,越晚渲染。
Rendering Path:渲染路径,控制相机使用的渲染管线。Target Texture:渲染纹理,将相机画面渲染到一张纹理上,常用于制作小地图(需在 Project 面板创建Render Texture)Occlusion Culling:遮挡剔除,开启后,被其他物体遮挡的对象不会被渲染,优化性能。Allow HDR:是否允许高动态范围渲染,提升画面光影表现。Allow MSAA:是否允许抗锯齿,减少画面边缘锯齿。Allow Dynamic Resolution:是否允许动态分辨率,根据设备性能自动调整分辨率。Target Display:目标显示器,指定相机画面输出到哪个显示器。
(2)获取摄像机
Camera.main // 获取主摄像机
Camera.allCamerasCount // 获取摄像机数量
Camera.allCameras // 得到所有摄像机
(3)坐标转换
Camera提供了一系列坐标系转换的方法,具体在坐标系那节有详细写出。
(4)委托
Camera.onPreCull; // 摄像机剔除前处理
Camera.onPreRender; // 摄像机渲染前处理
Camera.onPostRender; // 摄像机渲染后处理
10、光源系统
(1)Light组件
-
Type:光源类型 -
Color:光源颜色 -
Mode光源模式 -
Intensity:光源亮度 -
Indirect Multiplier:间接光强度乘数,控制光线反弹的强度 -
Shadow Type:阴影类型 -
RealtimeShadows:实时阴影参数Strength:阴影强度,阴影的暗度。Resolution:阴影分辨率。Bias:阴影偏移,阴影推离光源的距离。Normal Bias:法线偏移,阴影投射面沿法线方向收缩的距离,优化阴影边缘锯齿。Near Panel:近裁剪面,控制渲染阴影的近裁剪面距离,避免近处物体阴影异常。
-
Cookie:投影遮罩,为光源添加纹理遮罩,比如模拟透过窗户、树叶的光影效果。 -
Draw Halo:球形光环开关,开启后光源周围会显示球形光晕效果,模拟镜头光晕。 -
Flare:添加镜头耀斑效果,模拟强光下的镜头反光。 -
Render Mode:渲染模式,控制光源的渲染优先级和方式。 -
Culling Mask:剔除遮罩,选择性照亮指定层级的物体。
(2)光源设置Lighting
从Window/Rendering/Lighting打开,可以调整与场景中的光照有关的设置。这里只讲Environment选项卡的部分内容。
- 环境设置Environment
Skybox Material:天空盒材质。Sun Source:太阳来源,指定场景中代表太阳的方向光。Environment Lighting:环境光设置.
- 其他设置OtherSetting
Fog:雾效设置。Halo Texture:光源周围光环的纹理。Halo Strength:光环强度。Flare Fade Speed:耀斑淡出时间,控制耀斑出现后消失的速度。Flare Strength:耀斑的可见性强度,控制耀斑的明亮程度。Spot Cookie:聚光灯的剪影纹理,用于自定义聚光灯的投影形状。
11、物理系统
(1)碰撞条件
两个物体发生碰撞,必须同时满足:
- 两个物体都必须带有Collider组件。
- 至少一个物体带有Rigidbody组件。
两个物体发生碰撞时,会调用OnCollisionXXX生命周期函数。
(2)触发条件
当至少一方的碰撞体勾选了Is Trigger,则变成触发器,此时物体碰撞时不产生物理效果,只执行碰撞处理,即调用OnTriggerXXX生命周期函数。
(3)物理层级
在Project Settings/Physics的Layer Collision Matrix中,可以控制不同层级间是否可以发生碰撞。
(4)刚体RigidBody
刚体是一个物理组件,它允许游戏对象根据物理规则进行逼真的运动,刚体可使游戏对象的行为方式受物理引擎控制。
(5)碰撞器Collider
碰撞体组件可定义用于物理碰撞的游戏对象的形状。Unity中有很多形状的碰撞体,它们都有一些重要的共同参数:
Is Trigger:触发器,开启后不再参与物理碰撞,仅触发OnTriggerXXX事件。Material:物理材质,设置碰撞体的摩擦、弹性等物理交互效果。
(6)物理材质
用于设置碰撞体表面上的属性,例如摩擦力和弹性。
(7)恒定力组件
Constant Force组件可以为刚体提供持续的力。
(8)2D效应器
Area Effector 2D:区域效应器,在指定区域内,对物体施加恒定的力和扭矩。Buoyancy Effector 2D:浮力效应器,模拟流体效果,让物体产生上浮、下沉和水中阻力。Point Effector 2D:点效应器,模拟磁铁效果,对物体产生吸引或排斥力。Platform Effector 2D:平台效应器,实现 2D 游戏中常见的 “单向平台” 效果。Surface Effector 2D:表面效应器,模拟传送带效果,让接触表面的物体沿固定方向移动。
12、刚体Rigidbody
(1)Rigidbody组件
-
Mass:质量,单位为千克。 -
Drag:物体移动时受到的空气阻力。 -
Angular Drag:角阻力,物体旋转时受到的空气阻力。 -
Use Gravity:是否使用重力。 -
Is Kinematic:运动学刚体,开启后物体不再被物理引擎驱动,只能通过Transform操作移动,常用于移动平台、铰链关节等场景。 -
Interpolate:插值设置。None:不使用插值运算。Interpolate:根据前一帧的变换数据进行平滑处理,减少移动抖动。Extrapolate:根据下一帧的估计变换进行平滑处理,适合高速运动物体。
-
Collision Detection:碰撞检测模式。-
Discrete:离散检测,在物理间隔时间中检测碰撞。 -
Continuous:连续检测,通过collider线性向前移动到下一帧的投影点来实现检测。对动态碰撞体(具有刚体)使用离散碰撞检测,对静态碰撞体(没有刚体)使用连续碰撞检测。 -
Continuous Dynamic:连续动态检测。对设置为连续和连续动态的对象使用连续碰撞检测,对静态碰撞体(没有刚体)使用连续碰撞检测,其他碰撞体使用离散碰撞检测。 -
Continuous Speculative:连续推测检测,基于预测的连续检测。性能通常比连续碰撞检测低。
-
-
Constraints:运动约束,锁定物体的位置或旋转,防止某个方向的移动或转动。
(2)关于碰撞检测模式
碰撞检测模式具体可以查看官方文档:Unity - 手册: 选择碰撞检测模式
两个物体发生碰撞时具体采用的碰撞检测模式如图:

(3)重要属性
rigidbody.velocity; // 速度
(4)加力
rigidbody.AddForce(force); // 添加力(世界坐标)
rigidbody.AddRelativeForce(force); // 添加力(本地坐标)
rigidbody.AddTorque(torque); // 添加扭矩力(世界坐标)
rigidbody.AddRelativeTorque(torque); // 添加扭矩力(本地坐标)
rigidbody.AddExplosionForce(force, position, radius); // 添加爆炸的力
- 力模式
ForceMode.Acceleration; // 给物体施加一个持续的加速度,忽略物体质量
ForceMode.Force; // 给物体施加一个持续的力,与物体质量相关
ForceMode.Impulse; // 给物体施加一个瞬间的力,与物体质量相关
ForceMode.VelocityChange; // 直接给物体设置一个瞬时速度,忽略质量和作用时间
(5)休眠与唤醒
Unity为了优化性能,会自动让静止的刚体进入休眠状态,停止物理计算。
if (rigidBody.IsSleeping()) // 刚体是否处于休眠状态
{
rigidBody.WakeUp(); // 唤醒刚体,让它重新参与物理计算
}
(6)Rigidbody2D组件
2D的刚体和3D的刚体类似,不过有一些属性不同,这里举出比较重要的:
Body Type:刚体类型。Dynamic:动态类型。Material:物理材质,物理材质的优先级如下:碰撞体 > 刚体 > 默认。Simulated:开启后,2D 刚体及其子物体的 2D 碰撞器、关节都会参与物理模拟。Use Auto Mass:是否让 Unity 根据碰撞器面积自动计算物体质量。Sleeping Mode:休眠模式。
Kinematic:运动学刚体Use Full Kinematic Contacts:开启后,运动学刚体可以与所有类型的 2D 刚体产生碰撞,否则只与Dynamic刚体碰撞。
Static:静态类型,相当于无限质量的不可移动对象,至于Dynamic刚体碰撞。
13、碰撞器Collider
(1)常用碰撞器
3D:
- Box Collider:盒子碰撞器
- Sphere Collider:球体碰撞器
- Capsule Collider:胶囊碰撞器
- Cylinder Collider:圆柱碰撞器
- Mesh Collider:网格碰撞器
- Wheel Collider:车轮碰撞器
- Terrain Collider:地形碰撞器
2D:
- Box Collider 2D:矩形碰撞器
- Circle Collider 2D:圆形碰撞器
- Capsule Collider 2D:胶囊碰撞器
- Polygon Collider 2D:多边形碰撞器
- Edge Collider 2D:边缘碰撞器
- Composite Collider 2D:组合碰撞器
(2)Collision类
用于描述碰撞的信息,在OnCollisionXXX中作为参数出现。
private void OnCollisionEnter(Collision collision)
{
collision.collider; // 获取碰撞到的对象的碰撞器
collision.gameObject; // 获取碰撞对象的GameObject
collision.transform; // 获取碰撞对象的Transform组件
collision.contactCount; // 获取碰撞接触点的数量
collision.contacts; // 获取所有接触点的坐标数组
collision.GetContact(index); // 获取位于指定index处的接触点
}
(3)Collider类
所有碰撞体的基类,在OnTriggerXXX中作为参数出现。
private void OnTriggerEnter(Collider other)
{
other.enabled; // 开启/关闭这个碰撞体
other.gameObject; // 获取碰撞体所在的GameObject
other.transform; // 获取碰撞体所在物体的Transform组件
other.bounds; // 获取碰撞体的包围盒
other.isTrigger; // 是否是触发器
other.ClosestPoint(worldPos); // 碰撞体上离worldPos最近的点
other.ClosestPointOnBounds(worldPos); // 碰撞体的包围盒上离worldPos最近的点
other.Raycast(ray, out hitInfo, maxDistance); // 判断射线能不能射到当前这个物体
}
14、音频系统
Unity 音频系统的核心是发声者-听者模型,音频源Audio Source用于播放音频,监听器Audio Listener用于监听音源。
(1)音频剪辑AudioClip
AudioClip即音频源使用的音频数据,常用的音频文件格式有:mp3、ogg、aiff。AuidoClip的属性如下:
-
Force To Mono:将多声道音频转为单声道。 -
Load In Background:让音频文件在后台线程加载,不阻塞主线程。 -
Ambisonic:立体混响。 -
Load Type:加载类型 -
Preload Audio Data:是否预加载音频数据(是则进入场景时就加载,否则第一次播放才加载)。 -
Compression Format:压缩格式 -
Sample Rate Setting:采样率设置。
(2)音频源AudioSource
AudioClip:关联要播放的音频文件。Output:音频输出目标,默认输出到AudioListener。Mute:静音。Bypass Effects:快速开关该音源上的所有滤波器效果。Bypass Listener Effects:快速开关所有音频监听器效果。Bypass Reverb Zones:快速开关所有混响区效果。Play On Awake:对象创建时自动播放音频。Loop:循环播放。Priority:音频优先级,决定多音源同时播放时的资源分配。Volume:音频音量大小。Pitch:音频音高。Stereo Pan:立体声位置,控制 2D 音频的左右声道位置。Spatial Blend:空间混合,控制音频受 3D 空间影响的程度,0 为纯 2D 音频,1 为纯 3D 音频。Reverb Zone Mix:控制音频到混响区的输出信号量。3D Sound Settings:3D 音频设置-
Doppler Level:多普勒效果等级,模拟音源移动时的多普勒效应。 -
Spread:设置 3D 音频的扩散范围。 -
Volume Rolloff:音量衰减方式。 -
Min/Max Distance:最小距离内,声音保持最大响度;最小距离外,声音开始减弱;最大距离外,声音停止衰减。
-
(3)音频监听器AudioListener
一个场景只能有 1 个激活的 AudioListener,多个激活的 Listener 会导致音频失真、音量异常,通常挂载在 Main Camera 或 Player 上
(4)AudioSource常用方法
audioSource.Play(); // 播放
audioSource.Stop(); // 停止
audioSource.Pause(); // 暂停
audioSource.PlayDelayed(); // 延迟播放
audioSource.UnPause(); // 接触暂停
audioSource.isPlaying; // 是否播放完毕
(5)获取AudioClip数据
clip.channels; // 声道数
clip.samples; // 单声道的采样总数(剪辑长度)
float[] data = new float[clip.channels * clip.samples]; // 得到音频数据的float数组大小
clip.GetData(data, offset); // 将clip从offset位置开始的音频数据,读取到data数组中
(6)麦克风
Microphone.devices; // 获取所有麦克风信息
Microphone.Start(deviceName, loop, lengthSec, frequency); // 开始录制音频(参数:设备名,是否循环,录制时长,频率)
Microphone.End(deviceName); // 停止录制
15、数学Mathf
(1)基础概念
- 角度:常用的角度单位,定义一周为360^\circ。
- 弧度(rad):国际标准角度单位,定义一周为2\pi弧度。
- 基础关系:\pi\ rad=180°
- 弧度转角度:1\ rad = (\frac{180}{\pi})^\circ \approx 57.3^\circ,即 弧度 × 57.3^\circ = 对应角度。
- 角度转弧度:1^\circ = (\frac{\pi}{180})\ rad \approx 0.01745\ rad,即 角度 × 0.01745\ rad = 对应弧度。
(2)Mathf
Mathf是Unity提供的用于数学计算的工具结构体,提供了数学相关计算。
- 基础数学计算
Mathf.Abs(value); // 绝对值
Mathf.CeilToInt(value); // 向上取整
Mathf.FloorToInt(value); // 向下取整
Mathf.Clamp(value, min, max); // 钳制函数,限制数的范围
Mathf.Max(a, b); // 最大值
Mathf.Min(a, b); // 最小值
Mathf.Pow(value,pow); // 幂函数
Mathf.RoundToInt(value); // 四舍五入
Mathf.Sqrt(value); // 平方根
Mathf.IsPowerOfTwo(value); // 判断一个数是否是2的n次方
Mathf.Sign(value); // 判断正负数(正数1,负数-1)
- 三角函数
Mathf.PI; // PI的值
Mathf.Deg2Rad; // 角度转弧度(角度 * Mathf.Deg2Rad = 对应弧度)
Mathf.Rad2Deg; // 弧度转角度(弧度 * Mathf.Rad2Deg = 对应角度)
Mathf.Sin(value); // 正弦
Mathf.Cos(value); // 余弦
Mathf.ASin(value); // 反正弦
Mathf.ACos(value); // 反余弦
- 插值
Mathf.Lerp(start, end, t); // 插值运算
16、坐标系
Unity3D的坐标系是左手坐标系。
(1)世界坐标系
三个轴向固定,不受物体旋转影响,坐标原点为世界的中心点。

(2)物体坐标系
即本地坐标系,轴向会随物体旋转而变化。

(3)屏幕坐标系
原点为屏幕左下角,向右为X轴正方向,向上为Y轴正方向。宽高可通过Screen.width、Screen.height获取。
(4)视口坐标系
原点为屏幕左下角,向右为X轴正方向,向上为Y轴正方向。坐标中左下角为(0,0),右上角为(1,1)。

(5)坐标系间的相互转换
- 世界坐标系与本地坐标系
this.transform.InverseTransformPoint(Vector); // 世界坐标点转本地坐标(受缩放影响)
this.transform.InverseTransformDirection(Vector); // 世界坐标向量转本地坐标(不受缩放影响)
this.transform.InverseTransformVector(Vector); // 世界坐标向量转本地坐标(受缩放影响)
this.transform.TransformPoint(Vector); // 本地坐标点转世界坐标(受缩放影响)
this.transform.TransformDirection(Vector); // 本地坐标向量转世界坐标(不受缩放影响)
this.transform.TransformVector(Vector); // 本地坐标向量转世界坐标(受缩放影响)
- 世界坐标系与屏幕坐标系
Camera.main.WorldToScreenPoint(position) // 世界坐标转屏幕坐标(转换后z轴表示离摄像机多远)
Camera.main.ScreenToWorldPoint(position) // 屏幕坐标转世界坐标(参数的z轴表示离摄像机多远)
- 世界坐标系与视口坐标系
Camera.main.WorldToViewportPoint(position); // 世界坐标转视口坐标
Camera.main.ViewportToWorldPoint(position); // 视口坐标转世界坐标
- 屏幕坐标系与视口坐标系
Camera.main.ViewportToScreenPoint(position); // 视口坐标转屏幕坐标
Camera.main.ScreenToViewportPoint(position); // 屏幕坐标转视口坐标
17、四元数Quaternion
(1)概述
欧拉角的优点是直观易理解,但是会导致万向节死锁:当某个轴到达某个特殊值时(比如X轴到达90度),绕一个轴的旋转可能会覆盖住另一个轴的旋转,从而失去一维自由度。
四元数是由1个标量和3个虚数分量组成的超复数,形式为 [w, (x, y, z)]。用于在三维空间中精确表示旋转,避免了欧拉角 同一旋转表示不唯一 和 万向锁 问题。
Unity 中表示四元数的结构体是 Quaternion。
(2)轴角对
3D空间中,任意旋转都可以表示为绕着某一个轴旋转一个旋转角得到。
假设绕单位轴 n = (x,y,z) 旋转 β 度,则四元数表示为:
Q = [\cos(\frac{\beta}{2}),\ \sin(\frac{\beta}{2})x,\ \sin(\frac{\beta}{2})y,\ \sin(\frac{\beta}{2})z]
(3)初始化
Quaternion q = new Quaternion(x, y, z, w); // 构造函数
Quaternion q = Quaternion.AngleAxis(angle, axis); // 轴角对
Quaternion.identity; // 单位四元数
(4)欧拉角与四元数相互转换
q.eulerAngles; // 四元数转欧拉角
Quaternion.Euler(x, y, z); // 欧拉角转四元数
(5)插值
Quaternion.Lerp(a, b, t); // 线性插值
Quaternion.Slerp(a, b, t); // 球形插值
(6)获取四元数
Quaternion.LookRotation(forward); // 面向forward所指方向
(7)四元数计算
- q3 = q1 * q2,两个四元数相乘得到新的四元数,表示两个旋转量叠加,相当于旋转。
- v2 = q1 * v1,四元数乘向量得到新的向量,表示向量旋转指定旋转量,相当于旋转向量。(向量放后面)
18、协同程序
协程提供了一种在主线程中执行的方式,可以在不阻塞游戏运行的同时,执行长时间操作或者需要延迟处理的任务。继承了MonoBehaviour的类都可以开启关闭协程函数。
(1)协程与线程的区别
- 线程是单独开一个管道,和主线程并行执行。
- 协程是在原线程上执行,对逻辑进行分时分步执行。
(2)协程声明与yield语句
IEnumerator Func()
{
yield return null; // 下一帧执行
yield return 0; // 任意数字均可,在下一帧执行
yield return new WaitForSeconds(seconds); // 等待指定秒
yield return new WaitForFixedUpdate(); // 等待下一个物理帧更新时执行
yield return new WaitForEndOfFrame(); // 等待LateUpdate后的渲染相关处理完毕后
yield return new WaitUntil(predicate); // 一直等待,直到委托为true时继续往下执行
yield break; // 跳出协程
}
(3)协程开启与关闭
StartCoroutine(routine); // 开启协程
StopCoroutine(routine); // 关闭协程
StopAllCoroutines(); // 关闭所有协程
(4)协程与组件失活销毁的关系
协程开启后,组件和物体销毁时,协程不执行。物体失活后协程不执行。组件失活时协程继续执行。
(5)原理
Unity 中的协程函数,本质上是一个返回 IEnumerator 的迭代器方法。
通过 StartCoroutine(Func()) 开启协程,是将迭代器交给 Unity 的协程调度器管理。调度器根据 yield return 返回的内容,决定何时继续执行迭代器的下一部分逻辑。
我们观察生命周期函数,可以发现在Update函数和帧末有几个yield,这表明Unity主线程循环到这里的时候会自动唤起之前被挂起的并且满足条件的协程。
19、资源动态加载Resources
通过 Resources 类,可以动态加载Resources文件夹下指定路径资源,避免繁琐的拖曳操作。
(1)资源同步加载
Resources.Load(path); // 同步加载单个资源
Resources.Load<T>(path); // 同步加载单个资源
Resources.LoadAll(path); // 同步加载所有资源
(2)资源异步加载
- 方式一:委托
ResourceRequest rq = Resources.LoadAsync<T>(path); // 异步加载单个资源
rq.completed += Func; // 添加资源加载完成后的回调函数
// 可配合协程进行异步加载
rq.isDone; // 是否加载完成
rq.priority; // 进度
rq.asset; // 资源
- 方式二:协程
IEnumerator Load()
{
ResourceRequest rq = Resources.LoadAsync<T>(path);
// 使用yield return
yield return rq; // 等待资源加载完毕再执行
// 或者使用while判断
while (!rq.isDone)
{
Debug.Log(rq.progress); // 打印进度
yield return null;
}
rq.asset; // 获取资源
}
(3)资源卸载
Resources.UnloadAsset(assetToUnload); // 卸载指定资源
Resources.UnloadUnusedAssets(); // 卸载未使用资源
20、场景加载SceneManager
(1)同步加载
SceneManager.LoadScene(sceneName, mode); // 同步加载场景
(2)异步加载
- 方式一:委托
AsyncOperation ao = SceneManager.LoadSceneAsync(sceneName); // 异步加载场景
ao.completed += Func; // 场景加载完后的委托
- 方式二:协程
IEnumerator Load()
{
AsyncOperation ao = SceneManager.LoadSceneAsync(sceneName);
// 使用 yield return
yield return ao; // 等待场景加载完毕再执行
// 或者使用while判断
while (!ao.isDone)
{
Debug.Log(ao.progress); // 打印进度
yield return null;
}
// 重要属性:加载完是否自动切换场景
// 设为false,则 progress = 0.9 会停下,需设置为true才可以切换场景
ao.allowSceneActivation;
}
21、线渲染器LineRenderer
LineRenderer 是 Unity中一个用于画线的组件。
(1)组件介绍
组件顶部三个操作:
- 无编辑操作:仅显示线段,无法直接编辑。
- 编辑点模式(Edit Points):可直接拖拽、修改已有的顶点位置。
- 添加点模式(Create Point):在场景中点击创建新的线段顶点。
属性:
-
Loop:是否将线段首尾相连,形成闭合环形。 -
Positions:线段顶点数组。 -
Width:线段整体宽度。 -
Color:线段颜色渐变。 -
Corner Vertices:拐角细分顶点数,数值越大拐弯越圆润平滑。 -
End Cap Vertices:线段两端端点细分顶点数,控制两头是否圆润。 -
Materials:线段所用材质。 -
Alignment:线段朝向对齐方式 -
Texture Mode:纹理在线段上的排布方式 -
Shadow Bias:阴影偏移值,用来修正线段阴影瑕疵。 -
Generate Lighting Data:是否生成光照数据,参与全局光照烘焙与实时光照计算。 -
Use World Space:是否使用世界空间;勾选后线段点位不受父对象位移旋转影响。 -
Lighting:光照相关 -
Probes:光照探针Light Probes:光照探针模式,控制是否使用光照探针做环境光混合。Reflection Probes:反射探针模式,控制线段是否参与场景反射。
-
Additional Settings:附加设置-
Motion Vectors:运动矢量追踪方式 -
Dynamic Occludee:是否开启动态遮挡,被其他物体挡住时自动隐藏。 -
Sorting Layer:渲染层级图层。 -
Order in Layer:同图层内渲染先后顺序。
-
(2)常用属性
lineRenderer.loop; // 是否首尾相连(闭合线段)
lineRenderer.startWidth; // 设置线段起点宽度
lineRenderer.endWidth; // 设置线段终点宽度
lineRenderer.startColor; // 设置线段起点颜色
lineRenderer.endColor; // 设置线段终点颜色
lineRenderer.material; // 设置材质
(3)常用方法
lineRenderer.positionCount; // 设置线段点个数
lineRenderer.SetPositions(positions); // 一次性设置所有点
lineRenderer.SetPosition(index, position); // 单独设置某个点的位置
lineRenderer.useWorldSpace = false; // 是否使用世界坐标系(false为局部坐标系)
lineRenderer.generateLightingData = true; // 是否让线段受光照影响(接受光照数据参与着色器计算)
22、范围检测与射线检测
(1)范围检测
范围检测用于判断指定区域内是否存在对象。
// 盒状范围检测
Physics.OverlapBox(center, size, orientation, layerMask, queryTriggerInteraction); // 参数5表示是否忽略触发器
Physics.OverlapBoxNonAlloc(center, size, results); // NonAlloc,不产生GC,返回碰撞的数量
// 球体范围检测
Physics.OverlapSphere(...);
Physics.OverlapSphereNonAlloc(...);
// 胶囊体范围检测
Physics.OverlapCapsule(...);
Physics.OverlapCapsuleNonAlloc(...);
(2)射线检测
射线检测用于判断射线是否碰撞到了对象。
- 获取射线
// 获取射线
Ray ray = new Ray(origin, direction); // 声明射线
Ray ray = Camera.main.ScreenPointToRay(pos); // 摄像机屏幕点发出的射线
- 射线检测(重载较多,只列出一部分)
Physics.Raycast(ray, maxDistance, layerMask, queryTriggerInteraction); // 检测射线是否碰撞到了对象
Physics.Raycast(origin, direction, maxDistance, layerMask, queryTriggerInteraction); // 检测射线是否碰撞到了对象(重载)
Physics.Raycast(ray, out hitInfo, maxDistance, layerMask,queryTriggerInteraction); // 获取检测到的单个对象信息
Physics.RaycastAll(ray, maxDistance, layerMask, queryTriggerInteraction); // 获取检测到的多个对象
Physics.RaycastNonAlloc(ray, results, maxDistance, layerMask); // 获取碰撞对象的数量(NonAlloc版本,不产生GC)
(3)HitInfo
射线碰撞信息。
hitInfo.collider.gameObject; // 碰撞的物体
hitInfo.point; // 碰撞点
hitInfo.normal; // 碰撞面的法线
hitInfo.transform; // 碰撞物体的变换信息
hitInfo.distance; // 射线起点到碰撞点的距离
(4)LayerMask获取
若是成员变量,可以在Inspector窗口中选择;或是通过代码获取:
LayerMask.GetMask(layerNames); // 可以方便的获取多个层级
1 << LayerMask.NameToLayer("Monster"); // 若是多个层级,可以使用或运算 |