游戏物体在场景中实现移动的方面的API解析一
我们玩的游戏中,移动的游戏物体无处不在,Unity3D引擎提供了哪些方法来控制游戏物体的移动呢?控制物体移动的主要有3个组件:Transform(变换组件)、Rigidbody(刚体组件)、CharacterController(角色控制组件)。本篇文章主要介绍Transform组件关于移动方面的API。
我们知道游戏场景中的任何一个游戏物体都有Transform组件,该组件定义了游戏物体在场景空间中的状态,像position(位置)、rotation(旋转)、scale(缩放)等。我们知道,其实物体的移动的本质是不断地改变它的位置。所以,当然我们可以通过Transform组件的相关API来实现物体的移动。
1、Transform.Translate
表示向某方向移动多少距离。有2种调用形式如下:
1 2 3 4 5 6 7 8 9 10 11 12 | void Update() { //调用形式1:Translate (x : float, y : float, z : float, relativeTo : Transform) : void transform.Translate(0, Time.deltaTime * 10, 0, Space.Self); ////调用形式2:Translate (translation : Vector3, relativeTo : Transform) : void //transform.Translate(Vector3.up * Time.deltaTime * 10, Space.Self); } |
上述2种调用形式,运行结果一样。
结论1:形式1中x:float,y:float,z:float与形式2中的Vector3[* 系数]等价。
结论2:relativeTo是指要参考的坐标。Space.self代表相对于物体的局部坐标轴,Space.world代表相对于物体的世界坐标轴。
2、Transform.position
此种方式是通过直接改变position的值来实现物体的移动。不过需要结合Vector3相关的一些API来做如Vector3.Lerp/Vector3.Slerp,Vector3.MoveTowards/Vector3.SmoothDamp等。
(1)Vector3.Lerp(Vector3a, Vector3 b, float t):向量的插值运算,插值运算公式:Resullt=a+(b-a)*t,并且t的有效值被限制在[0,1]之间,t<=0的值,归为t=0;t>=1的值,归为t=1(已测试验证)。使用Vector3.Lerp实现游戏物体从A到B的运动,其实有2种思想原理:
原理1:以一定地方式改变t的值,从有效值0至有效值1的变化。
原理2:以某一固定的t的值,不断地“递归迭代”。
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ///
/// 游戏物体运动的起始位置 /// public Vector3 startPoint; ///
/// 游戏物体运动的结束位置 /// public Vector3 endPoint; void Start() { //起始与结束位置的赋值 startPoint = transform.position; endPoint = new Vector3(transform.position.x, transform.position.y+30f, transform.position.z); } void Update() { //原理1方式调用 transform.position = Vector3.Lerp(startPoint, endPoint, Time.time); ////原理2方式调用 //transform.position = Vector3.Lerp(transform.position, endPoint, Time.deltaTime * 5f); Debug.Log( "transform.position==========" +transform.position); } |
运行结果如下:
以上2种方式都能够达到让游戏物体从A位置移动到B位置。原理1主要是通过改变t值(即Time.time[0,无穷大],范围已经覆盖了有效值[0,1]);原理2主要是通过循环迭代a的值来实现移动的。
(2)Vector3.MoveTowards:与Vector3.Lerp类似,只是增加了最大“位移步伐”的限制。 Vector3 MoveTowards(Vector3 current, Vector3 target, floatmaxDistanceDelta)。
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ///
/// 游戏物体运动的起始位置 /// public Vector3 startPoint; ///
/// 游戏物体运动的结束位置 /// public Vector3 endPoint; ///
/// 移动的速度 /// public float speed = 5f; void Start() { //起始与结束位置的赋值 startPoint = transform.position; endPoint = new Vector3(transform.position.x, transform.position.y + 30f, transform.position.z); } void Update() { float step = speed * Time.deltaTime; transform.position = Vector3.MoveTowards(transform.position, endPoint, step); } |
运行结果跟Vector.Lerp相似。另外,会发现maxDistanceDelta是正值时,当前地点移向目标,如果是负值时当前地点将远离目标。
(3)Vector3.Slerp:球形插值运算。值得注意的是,如果只是用transform.position = Vector3.Slerp(startPoint,endPoint,t)来控制运动的话,游戏物体只会在两点之间做普通的直线运动(已测试验证)。另外,如果想实现游戏物体像太阳一样某一点升起又到某一点降落的弧形轨迹运动,那么还需要做特殊的处理。
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ///
/// 游戏物体运动的起始位置 /// public Vector3 startPoint; ///
/// 游戏物体运动的结束位置 /// public Vector3 endPoint; public float journeyTime = 1.0F; private float startTime; void Start() { startTime = Time.time; //起始与结束位置的赋值 startPoint = transform.position; endPoint = new Vector3(transform.position.x+100f, transform.position.y, transform.position.z+100f); } void Update() { Vector3 center = (startPoint + endPoint) * 0.5F; center -= new Vector3(0, 1, 0); Vector3 riseRelCenter =startPoint - center; Vector3 setRelCenter = endPoint - center; float t = (Time.time - startTime) / journeyTime; transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, t); transform.position += center; } |
运行结果如图:
(4)Vector3.SmoothDamp: 可以让物体从A点平滑地移动到B。
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ///
/// 游戏物体运动的起始位置 /// public Vector3 startPoint; ///
/// 游戏物体运动的结束位置 /// public Vector3 endPoint; ///
/// 移动的速度 /// public Vector3 curSpeed = Vector3.zero; public float maxSpeed = 5f; public float smoothTime = 1f; void Start() { //起始与结束位置的赋值 startPoint = transform.position; endPoint = new Vector3(transform.position.x, transform.position.y + 30f, transform.position.z); } void Update() { // Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed = Mathf.Infinity, float deltaTime = Time.deltaTime); // Vector3 SmoothDamp(Vector3 当前位置, Vector3 目标位置, ref Vector3 当前速度, float 预计花费时间, float 最大限速,自上次调用这个函数的时间 默认为 Time.deltaTime); transform.position = Vector3.SmoothDamp(transform.position, endPoint, ref curSpeed,smoothTime); } |
运行结果类似,只是物体移动过程中,看起来比较匀速地运动。