Mathf与C# 中的Math几乎一样,Math是C#自带的工具类,主要就提供一些数学相关计算方法,Mathf是Unity专门封装的,不仅包含Math中的方法,还多了一些适用于游戏开发的方法
常用方法——一般计算一次
1、圆周率——Mathf.PI
2、取绝对值——Mathf.Abs
3、向上取整——Mathf.CeilToInt
4、向下取整——Mathf.FloorToInt
5、钳制函数——Mathf.Clamp(value, min, max),判断一个数的范围,在[min,max]区间内返回value,超过范围分别返回最大或者最小值
6、获取最大值——Mathf.Max
7、获取最小值——Mathf.Min
8、一个数的n次幂——Mathf.Pow
9、四舍五入——Mathf.RoundToInt
10、返回一个数的平方根——Mathf.Sqrt
11、判断一个数是否是2的n次方——Mathf.IsPowerTwo
12、判断正负数——Mathf.Sign(返回±1,其中0返回正数)
常用方法——一般不停计算
1、插值运算——Lerp
// Lerp函数公式
// t为插值系数,取值范围为0~1
result = Mathf.Lerp(start, end, t) => result = Mathf.Lerp(start, 10, Time.deltaTime)计算公式为:result = start + (end - start) * t;
(1)插值运算用法一:每帧改变start的值,变化速度先快后慢,位置无限接近,但是不会得到end位置
start = Mathf.Lerp(start, 10, Time.deltaTime)(2)插值运算用法二:每帧改变t的值,变化速度匀速,位置每帧接近,当t>=1时,得到结果:
time += Time.deltaTime(time初始为0) result = Mathf.Lerp(start, 10, time) ;实际应用:一个对象跟随另一个对象
练习:使用线性插值实现一个方块跟随另一个方块移动
其中一个方块的移动脚本:
public class move : MonoBehaviour { public float speed = 5; // Update is called once per frame void Update() { float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); transform.Translate(new Vector3(h, 0, v) * speed * Time.deltaTime); } }另一个方块的跟随脚本:
public class follow : MonoBehaviour { public GameObject followObj; // Update is called once per frame void Update() { Vector3 start = transform.position; Vector3 end = followObj.transform.position; start.x = Mathf.Lerp(start.x, end.x, Time.deltaTime); start.z = Mathf.Lerp(start.z, end.z, Time.deltaTime); transform.position = start; } }但其实在Vector3中有直接的插值方法:Vector3.Lerp,因此以上代码可以直接简化为:
transform.position = Vector3.Lerp(transform.position, followObj.transform.position, Time.deltaTime);匀速运动相对复杂一点,首先起始点A、目标点B是不变的,两点的距离是 ,需要改变【t】,那么该参数应该如何改变是匀速运动的关键, 既要匀速运动,那么【t】也一定是匀速改变
我们需要清楚插值函数第三个参数【t】的意义,要注意该参数并不表示时间,只是在实际应用中这个参数的量化通常与时间有关,为了便于区分,将实际移动时间标注为【T】,可以得到经历时间【T】后走过的路径长度 为:。那么该值与的比值一定是在【0,1】之间的,这个比值就可以作为第三个参数
举个例子:假设A(0,0,0),B(10,0,0),speed = 1f,那么distance = 10
当T=0时:dist = 0, t = 0,由插值计算公式:res = start + (end - start) * t得到,res=0
当T=1时,dist = 1,t = 0.1,res = 1,那么这时物体移动到(1,0,0)
当T=2时,dist = 2,t = 0.2,res = 2,那么这时物体移动到(2,0,0)
..........以次类推
可以看出,匀速移动时间与speed有关,而Unity中将【T】拆分为每一帧运行,实际的移动距离是(Time.time - startTime) * speed, 但实际上,在FixedUpdate中才能保证准确的匀速。
最终代码:
public class follow : MonoBehaviour { public GameObject followObj; public float speed = 0.01f; // 以速度2f匀速跟随 private Transform preStart, preEnd; private float cTime; // 当前时间 private float disPerFrame; // 每一帧移动的距离 private float distance; // 两点距离 private void Start() { preStart = gameObject.transform; preEnd = followObj.transform; distance = Vector3.Distance(preStart.position, preEnd.position); cTime = Time.time; } // Update is called once per frame void Update() { Vector3 start = transform.position; Vector3 end = followObj.transform.position; // 如果目标地点的位置改变,那么重新开始计时,并且重新记录起始点 if (end != preEnd.position) { preStart = gameObject.transform; preEnd = followObj.transform; distance = Vector3.Distance(preStart.position, preEnd.position); cTime = Time.time; } float distCovered = (Time.time - cTime) * speed; // 当前已经走过的路程 float percPath = distCovered / distance; // 走过路程的百分比 transform.position = Vector3.Lerp(preStart.position, preEnd.position, percPath); } }



