简介

在unity3d中,有多种方式可以改变物体的坐标,实现移动的目的,其本质是每帧修改物体的position。

通过Transform组件移动物体

Transform 组件用于描述物体在空间中的状态,它包括 位置(position), 旋转(rotation)和 缩放(scale)。 其实所有的移动都会导致position的改变,这里所说的通过Transform组件来移动物体,指的是直接操作Transform来控制物体的位置(position)。

Transform.Translate

该方法可以将物体从当前位置,移动到指定位置,并且可以选择参照的坐标系。 当需要进行坐标系转换时,可以考虑使用该方法以省去转换坐标系的步骤。

public function Translate(translation: Vector3, relativeTo: Space = Space.Self): void;

缺点:无
优点:有一定的惯性感,同样8向平滑,

使用Horizontal与Vertical

1
2
3
4
5
6
7
8
9
10
11
12
void transMove_GetAxis()
{
//相关联的键位才是我们可以变换的这些轴名称和键位,
//可以在projectSettings里的inputManager看到
float h = Input.GetAxis("Horizontal") * speed * Time.deltaTime; //获取水平方向的输入键
float v = Input.GetAxis("Vertical") * speed * Time.deltaTime; //获取垂直方向的输入键

Vector3 move = new Vector3(h, 0, v); //v赋值给y或者z自定
//移动到v3-move的位置,但move的具体坐标就是由用户输入的
transform.Translate(move);

}

使用forward,back,left,right

同样为transform.Translate()方法,
不过是将Input GetKey()改为GetAxis(),
官方给出的示例:public static float GetAxis (string axisName);
如果将轴映射到鼠标,该值会有所不同,并且不会在-1…1 的范围内。
此时,该值为当前鼠标增量乘以轴灵敏度。
通常,正值表示鼠标向右/向下移动,负值表示鼠标向左/向上移动。该值与帧率无关
使用该值时,您无需担心帧率变化问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void transMove_keycode()
{


// 如果我们按下W
if (Input.GetKey(KeyCode.W))
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A))
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S))
{
transform.Translate(Vector3.back * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.Translate(Vector3.right * speed * Time.deltaTime);
}
}

Transform.position

有时重新赋值position能更快实现我们的目标。(快)

方法 :transform.position与transform.localPosition的加减
缺点:整体移动观感较为僵硬,设置Key键代码重复率高,输入受帧率影响
优点:8向移动较为平滑,I/O反馈及时手感还不错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void transMove_position()
{
// 如果我们按下W
if (Input.GetKey(KeyCode.W))
{
transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, transform.localPosition.z + speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A))
{
transform.localPosition = new Vector3(transform.localPosition.x - speed * Time.deltaTime, transform.localPosition.y, transform.localPosition.z);
}
if (Input.GetKey(KeyCode.S))
{
transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, transform.localPosition.z - speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.localPosition = new Vector3(transform.localPosition.x + speed * Time.deltaTime, transform.localPosition.y, transform.localPosition.z);
}
}

通过vector3来移动

Vector3.Lerp, Vector3.Slerp, Vector3.MoveTowards

Vector3 既可以表示三维空间中的一个点,也可以表示一个向量。这三个方法均为插值方法, Lerp为线性插值,Slerp为球形插值, MoveTowards在Lerp的基础上增加了限制最大速度功能。 当需要从指定A点移动到B点时,可以考虑时候这些方法。

Lerp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Transform startPoint;//起始点
public Transform endPoint;//终止点
private float startTime;//开始运行时间
private float btDistance;//点间距

void start(){
startTime=Time.time;
btDistance = Vector3.Distance(startPoint.position, endPoint.position);
}
void v3Move_lerp()
{
// v3-lerp线性插值
float moved = (Time.time - startTime) * speed;//运行开始时间乘以速度已走路程
float fractionOfBtDistance = moved / btDistance; //百分比 =已经走过的路程/ 两点之间的距离—??%
//令物体现在的位置 = 线性插值计算出一定速度下物体在两点间长度的百分之多少
transform.position = Vector3.Lerp(startPoint.position, endPoint.position, fractionOfBtDistance);
}

Slerp

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 Transform startPoint;//起始点
public Transform endPoint;//终止点
private float startTime;//开始运行时间
private float btDistance;//点间距

void start(){
startTime=Time.time;
btDistance = Vector3.Distance(startPoint.position, endPoint.position);
}
void v3Move_Slerp()
{
// The center of the arc
Vector3 center = (startPoint.position + endPoint.position) * 0.5F;

// move the center a bit downwards to make the arc vertical
center -= new Vector3(0, 1, 0);

// Interpolate over the arc relative to center
Vector3 riseRelCenter = startPoint.position - center;
Vector3 setRelCenter = endPoint.position - center;

// The fraction of the animation that has happened so far is
// equal to the elapsed time divided by the desired time for
// the total journey.
float fracComplete = (Time.time - startTime) / btDistance;

transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, fracComplete);
transform.position += center;
}

Vector3.SmoothDamp

该方法是可以平滑的从A逐渐移动到B点,并且可以控制速度,最常见的用法是相机跟随目标。

1
2
3
4
5
6
7
8
public Transform target;
private Vector3 vt = Vector3.zero;
public float smoothTime = 5;

void v3Move_SmoothDamp()
{
transform.position = Vector3.SmoothDamp(transform.position, target.position, ref vt, smoothTime);
}

通过Rigidbody组件移动物体

Rigidbody组件用于模拟物体的物理状态,比如物体受重力影响,物体被碰撞后的击飞等等。

注意:关于Rigidbody的调用均应放在FixedUpdate方法中,该方法会在每一次执行物理模拟前被调用。

Rigidbody.velocity

设置刚体速度可以让物体运动并且忽略静摩擦力,这会让物体快速从静止状态进入运动状态。(有惯性)

1
rb.velocity += new Vector3(0, 0, speed);

Rigidbody.AddForce

给刚体添加一个方向的力,这种方式适合模拟物体在外力的作用下的运动状态。

1
2
3
4
5
6
void rbMove3()
{
// 直接给物体一个力
// 这种方法比起移动更适合去做一些炮弹、子弹、冷兵器对物体造成的冲击效果
rb.AddForce(new Vector3(0, 0, 10));
}

Rigidbody.MovePosition

`
刚体受到物理约束的情况下,移动到指定点。

1
2
3
4
5
6
7
8
void rbMove2()
{
// 逻辑上看成不断高频传送
float h = Input.GetAxis("Horizontal") * speed * Time.deltaTime; //获取水平方向的输入键
float v = Input.GetAxis("Vertical") * speed * Time.deltaTime; //获取垂直方向的输入键
// update 中卡 放到fixedUpdete中
rb.MovePosition(transform.position + new Vector3(h, 0, v));
}

通过CharacterController组件移动物体

CharacterController用于控制第一人称或第三人称角色的运动,使用这种方式可以模拟人的一些行为,比如限制角色爬坡的最大斜度,步伐的高度等。

CharacterController.SimpleMove

用于模拟简单运动,并且自动应用重力,返回值表示角色当前是否着地。

CharacterController.Move

模拟更复杂的运动,重力需要通过代码实现,返回值表示角色与周围的碰撞信息。

【波仔羔训练营-03】Unity的9种移动方式,看似简单实则…_哔哩哔哩_bilibili

Unity Movement Tutorials (catlikecoding.com)

(转)Unity3D中移动物体位置的几种方法 - 哆啦任意门 - 博客园 (cnblogs.com)

【完结】Unity基础教程系列——Unity物体运动11篇 - 知乎 (zhihu.com)