Vector3.LerpUnclamped
public static Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t)
在 a 与 b 之间进行线性插值,当 t 的值超过 0 ~ 1 时,其结果也不限于 a 与 b 之间
Vector3.LerpUnclamped(Vector3.zero, Vector3.one * 12, -1.5f)
// result is (-18, -18, -18)
Vector3.Angle / Vecto3.SigendAngle
计算两个向量夹角,SigendAngle 第三个参数只用于确定符号,两个方法计算结果一致
Vector3.MoveTowards
// vector is position
public static Vector3 MoveTowards(Vector3 currentPos, Vector3 targetPos, float maxDistanceDelta)
将 positioin vector 从 current 移动到 target 每一帧的变化量 step vector
void Update()
{
float step = 2f * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
Vector3.RotateTowards
// vector is dir
public static Vector3 RotateTowards(Vector3 currentDir, Vector3 targetDir, float maxRadiansDelta,
float maxMagnitudeDelta)
将 direction vector 从 current 旋转到 target 每一帧的变化量 step vector
void Update()
{
// 目标向量
Vector3 targetDir = target.position - transform.position;
float step = 2f * Time.deltaTime;
// 得到经过 step 后的中间向量
Vector3 dir = Vector3.RotateTowards(transform.forward, targetDir, step, 0f);
// 旋转到该方向
transform.rotation = Quaternion.LookRotation(dir);
}
Vector3.ProjectOnPlane
public static Vector3 ProjectOnPlane(Vector3 vector, Vector3 planeNormal)
获得将 vector 投影到与 planeNormal 相垂直的平面后的向量,planeNormal 不需要是 normalize 的向量,函数会处理,实现方式相当于如下:
Vector3 ProjectOnPlane(Vector3 vector, Vector3 planeNormal)
{
return vector - planeNormal * Vector3.Dot(vector, planeNormal.normalized);
}
Vector3.Project
public static Vector3 Project(Vector3 vector, Vector3 onNormal)
获得将 vector 投影到 onNormal 上的向量,实现方式相当于如下:
Vector3 Project(Vector3 vector, Vector3 onNormal)
{
return onNormal * Vector3.Dot(vector, onNormal.normalized);
}
Quaternion.LookRotation
// vector is dir
public static Quaternion LookRotation(Vector3 forward, Vector3 upwards = Vector3.up)
看图,就是将 Cube Z 轴对齐到 forward 蓝线方向所需要的 rotation。但如果只是将 Z 轴对齐到 forward,Cube 可不止一种形态,这里的 upwards 的作用就是用来确定其他两个轴的方向,这样 Cube 就只有一种确定的形态。通过 forward 蓝线与 upwards 粉线叉乘得到 X 轴该对齐的红线方向,再通过 forward 与 红线叉乘得到 Y 轴该对齐的绿线方向。
上图示例所使用的代码如下:
void Update()
{
Vector3 forward = target.position - transform.position; // 蓝线
Vector3 x = Vector3.Cross(upwards, forward); // 叉乘得到红线
Vector3 y = Vector3.Cross(forward, x); // 叉乘得到绿线
Debug.DrawLine(transform.position, upwards, Color.magenta);
Debug.DrawLine(transform.position, forward, Color.blue);
Debug.DrawLine(transform.position, x, Color.red);
Debug.DrawLine(transform.position, y, Color.green);
// 计算 rotation
Quaternion lookRotation = Quaternion.LookRotation(forward, upwards);
// 旋转 cube
transform.rotation = Quaternion.RotateTowards(transform.rotation, lookRotation, 0.5f);
}
Quaternion.FromToRotation
// vector is dir
public static Quaternion FromToRotation(Vector3 fromDir, Vector3 toDir)
将 direction vector 从 from 旋转到 to 所需的 rotation
Quaternion.RotateTowards
public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)
将 rotation quaternion 从 from 旋转到 to 每一帧变化的 step rotation
void Update()
{
Vector3 targetDir = target.position - transform.position;
Quaternion fromToRotation = Quaternion.LookRotation(targetDir);
// 或者使用 Quaternion.FromToRotation
Quaternion fromToRotation = Quaternion.FromToRotation(transform.forward, targetDir);
float step = 20f * Time.deltaTime;
// 逐步旋向该 rotation
transform.rotation = Quaternion.RotateTowards(transform.rotation, fromToRotation, step);
}
Towards 方法与 Lerp 方法相似都计算中间值,区别在于,delta 是增量,而 t 是比率, Towards 方法可直接到终点,而 Lerp 需要 t>=1时才能达到终点*
Quaternion * Quaternion
组合两个 rotation,或者说在第一个 rotation 的基础上叠加一个 rotation
// Applies a rotation of 90 degrees per second around the Y axis
float angle = rotateSpeed * Time.deltaTime;
transform.rotation *= Quaternion.AngleAxis(angle, Vector3.up);
Quaternion * Vector3
将 vector 按 rotation 进行旋转
// vector is dir
// 运算中 Quaternion 与 vector 的位置不能交换
// 将 vector 绕 Vector3.up 旋转 45 度
rotatedVector = Quaternion.AngleAxis(45, Vector3.up) * vector;
// 将 vector 绕 Y 轴旋转 45 度
rotatedVector = Quaternion.Euler(0, 45, 0) * vector;
Transform.TransformPoint / Vector / Direction
将 Point,Vector,Direction 由本地坐标转换到世界坐标
// 定义本地坐标 localPosition
Vector3 localPosition = new Vector3(1.5f, 1.5f, 1.5f);
// 将 localPosition 由本地坐标转换到世界坐标
Vector3 worldPosition = this.transform.TransformPoint(localPosition);
// if this.transform is (1.2f, 1.2f, 1.2f), the worldPosition is (2.7f, 2.7f, 2.7f)
在通过上面的方法获取结果时,Vetor 和 Direction 不受 this.transform 的位置影响;Vector 和 Point 受到 缩放(scale)影响。
Transform.localToWorldMatrix
将 Point 由本地坐标转换到世界坐标的矩阵
// 定义本地坐标 localPosition
Vector3 localPosition = new Vector3(1.5f, 1.5f, 1.5f);
// 使用矩阵乘法将 localPosition 由本地坐标转换到世界坐标
Vector3 worldPosition = transform.localToWorldMatrix.MultiplyPoint(localPosition);
// 得到的结果与上面使用 TransformPoint 一样
Rigidbody2D.MovePosition / Rigidbody.MovePosition
MovePosition 将在当前帧的物理更新中计算位移,并在下一帧物理更新中执行位移,可以避免直接操作 transform.position 产生的抖动效果,该方法设计用于 kinematic rigidbodies
RectTransform.anchoredPosition
public Vector2 anchoredPosition
该属性获取,轴心相对于锚点的位置,如果四个锚点不在一个点上,则计算它们的中心点,作为锚点位置
RectTransform.localPosition
public Vector3 localPosition
该属性获取,轴心相对于父级 transform 轴心的位置,与锚点无关
RectTransform.sizeDelta
public Vector2 sizeDelta
该属性获取 RectTransform 的尺寸,与锚点之间距离有关
当锚点在一起时,sizeDelta 与 RectTransform 尺寸一致
当锚点分开时,sizeDelta 是 RectTransform 相对于锚点形成的矩形大多少或少多少
Time.timeScale
该属性不会改变 Update 方法的执行速率,这是由机器渲染性能决定,文档的描述:
Note that the time scale doesn’t actually slow execution but simply changes the time step reported to the Update and FixedUpdate functions via Time.deltaTime and Time.fixedDeltaTime.
改变 timeScale 将改变 Time.deltaTime,由于 Time.time 等时间函数的计算依赖于 Time.deltaTime,所以也会改变,一切与时间相关计算都会影响如,加速、位移、动画等
改变 timeScale 将改变 FixedUpdate 的更新间隔,但 Unity 并不会改变 fixedDeltaTime 的值。一般的,为了保持物理更新速率维持原来的 0.02s,在改变 timeScale 后建议同时改变 fixedDeltaTime
// timeScale * 2,则 deltaTime * 2,则 FixedUpdate 执行速率 * 2
Time.timeScale = 2;
// 将 fixedDeltaTime 设置的执行间隔 * 2,保持物理更新还是按 0.02s 的速度执行
Time.fixedDeltaTime = 0.02s * Time.timeScale;
通过测试,猜测在Unity更新周期内部,使用 deltaTime 或 time 判断是否达到 fixedDeltaTime 所设置的更新间隔,所有 FiexdUpdate 的执行间隔并非只由 fixedDeltaTime 决定。
Camera.ScreenToWorldPoint
public Vector3 ScreenToWorldPoint(Vector3 position)
该函数参数要分为两部分理解, position.x、position.y 是屏幕坐标位置而 position.z 是摄像机与游戏物体的距离。
当摄像机是正交模式(2D)时, position.z=0 可以正确的将屏幕坐标转换为游戏世界坐标
当摄像机是透视模式时,必须指定正确的 z 值,才能得到正确的世界坐标
Mathf.SmoothStep
public static float SmoothStep(float from, float to, float t)
与 Lerp 方法用法一样,区别是插值从开始时逐渐加速到结束时逐渐减速,更加平滑。
Mathf.Atan / Mathf.Atan2
public static float Atan(float f)
返回弧度值,转换为角度值的范围在 [-90, 90] 之间,并且一三象限 [0, 90],二四象限 [-90, 0]
public static float Atan2(float y, float x)
返回弧度值,转换为角度值的范围在 [-180, 180] 之间,并且一二象限 [0, 180],三四象限 [-180, 0]
// point 在逆时针旋转时,角度在 0 ~ 360 之间变化
void Update()
{
Vector3 d= point.position - transform.position;
float angle = Mathf.Atan2(d.y, d.x) * Mathf.Rad2Deg;
if (angle < 0)
angle += 360f;
}