unity控制物体移动和转向

文章目录

      • 简介
      • 一、向量
      • 二、控制物体移动
      • 三、控制物体转向

简介

控制移动和转向的方法很多,教程也很多,照着教程代码输入能实现,反正能试出来,不是什么复杂的事情,但是过段时间后就忘记了,感觉还是没有搞清楚原理,因此趁机弄清楚原理记下来。

一、向量

关于向量的描述,就是有大小和方向的量,unity中大小用magnitude表示,方向用normalized表示。如下:

Vector3 vector = new Vector3(3f, 0f, 3f);
Vector3 vector2 = vector.normalized; // 获取vector的归一化向量,即(0.7f, 0f, 0.7f), vector不变,vector2大小是1
float magnitude = vector.magnitude;	 // magnitude是vector的大小, vector不变
vector.Normalize();					// vector本身被归一化,即变成(0.7f, 0f, 0.7f)

向量的加减,初中数学和初中物理的力学力的合成有学过,不需要这里描述。

二、控制物体移动

控制物体移动通常通过键盘输入方向;或者鼠标点击目标位置,如下图:

unity控制物体移动和转向_第1张图片

上图是unity俯视图,x坐标和z坐标是世界坐标,O点是世界坐标原点,物体在S点,那么物体的位置transform.position就是向量OS或者s,当按下键盘按键D或者向右方向键的时候,输入向量是OM,或者m,那么向量 u = s + m u = s + m u=s+m,向量u或者说就位置T是物体要移动到的位置。代码如下:

float x = Input.GetAxis("Horizontal");   // 获取控制输入
float z = Input.GetAxis("Vertical");
Vector3 m = new Vector3(x,0f,z);		// 创建控制输入向量m
Vector3 u = transform.position + m;		// transform.position就是向量s,计算出要移动到的目标向量位置

上面计算出目标向量位置后,赋值给transform.position就能实现移动。如下:

transform.position = u;	// 通过修改物体位置实现移动

或者用刚体的方法,如下:

Rigidbody rigidbody = GetComponent();	// 获取刚体组件
rigidbody.MovePosition(u);		// 让刚体从当前位置移动到目标位置向量u,即T点的位置

以上代码,通常在Update或者FixedUpdate方法中调用,以Update方法为例,即每一帧调用一次,每次移动更新物体的移动位置transform.position,等下一帧调用的时候,检测到控制还在输入,又在新的物体的位置下加上控制输入向量m,得到新的目标位置移动向量u,实现不断的移动。流程如下:

Created with Raphaël 2.2.0 每一帧执行 读取控制输入,得到控制向量 目标位置向量 = 当前位置向量 + 控制向量 当前位置向量 = 目标位置向量 结束

因为帧率会变动的,而且物体又移动速度的差异,所以实际使用时,每次的移动大小需要考虑速度和帧率的变动,也要考虑控制输入斜向的时候大小会比单个方向大,比如单纯按下右方向,获取到最大的x是1,此时向量大小是1,如果向右和向上同时按下,那么获取到最大x是1以及z是1,此时向量大小要乘以个 2 \sqrt2 2 ,造成斜向移动快。所以实际使用是只取控制向量的方向,大小按照速度和帧率考虑。如果物体速度是speed 米/秒,unity提供了距离上一帧的时间是Time.deltatime秒,可以理解成是Time.deltatime秒/帧,那么speed * Time.deltatime就是这一帧移动的米数,可以作为这一帧移动向量的大小。

如果用刚体的方法实现移动,实际的代码会是下面的样子:

/* 没有根动画的移动 */
public float speed = 1f;	// 允许设置速度

void Start()
{
    rigidbody = GetComponent();  // 获取刚体组件
}

void Update()
{
    float x = Input.GetAxis("Horizontal");
    float z = Input.GetAxis("Vertical");
    Vector3 m = new Vector3(x,0f,z);		// 创建控制输入向量m
    m.Normalize();	// 把控制输入向量归一化,只要方向,这样就不会斜向速度偏快了
	Vector3 u = transform.position + m * speed * Time.deltatime; // 考虑每帧移动的向量大小
	rigidbody.MovePosition(u);		// 让刚体从当前位置移动到目标位置向量
}

如果物体带有根动画的情况下,因为根动画,动画本身会影响位置变化,会涉及到图像渲染更新和物理操作更新的同步问题,改天另外写一篇总结一下。

三、控制物体转向

unity控制物体移动和转向_第2张图片

上图是unity俯视图,x坐标和z坐标是世界坐标。橙色的长方形代表物体,垂直于长方形的向量transform.forward就是物体自身坐标的Z轴,即物体的前向向量。

如果此时按下了W按键或者向上按键,那么在世界坐标的Z轴正方向就会有一个控制向量,表示物体的目标朝向。

可见就是要让物体直接转到输入控制向量的方向,转向是用transform.rotation表示的,这是一个四元数,需要把输入控制向量m转成四元数,代码如下:

float x = Input.GetAxis("Horizontal");   // 获取控制输入
float z = Input.GetAxis("Vertical");
Vector3 m = new Vector3(x,0f,z);		// 创建控制输入向量m
transform.rotation = Quaternion.LookRotation(m);	// Vector3转成4元数Quaternion

这段代码直接实现了转向到输入控制的方向。

但是!以上代码通常也是在Update或者FixedUpdate方法中调用的,这样一帧就转向到位置了,不符合实际情况,应该转向有个过程的,比如转速turnSpeed是90°/秒,即 π / 2 \pi/2 π/2弧度/秒,那么一帧的时间Time.deltatime,转过的角度应该是 t u r n S p e e d ∗ T i m e . d e l t a t i m e turnSpeed * Time.deltatime turnSpeedTime.deltatime,unity提供了一个方法Vector3.RotateTowards,参数传入开始的前向向量和最终的前向向量,以及每次转向允许的最大弧度和最大向量大小,这个方法会返回计算好的这一次应该转向的前向向量,代码如下:

float x = Input.GetAxis("Horizontal");   // 获取控制输入
float z = Input.GetAxis("Vertical");
Vector3 m = new Vector3(x,0f,z);		// 创建控制输入向量m
Vector3 turnForward = Vector3.RotateTowards(transform.forward, m, turnSpeed * Time.deltaTime, 0f);
transform.rotation = Quaternion.LookRotation(turnForward);	// Vector3转成4元数Quaternion

以上代码的第4行的方法,第一个参数就是开始前向向量,即物体当前的Z轴方向,第二个参数是最终的目标前向向量m,第三个就是每帧的转过的弧度。很显然,每帧都转过一个小角度,更新transform.rotationtransform.forward,随着每一帧更新,最终到达目标朝向。

执行转向除了给transform.rotation赋值外,还可以有刚体的方法:

Quaternion rotation = Quaternion.LookRotation(turnForward);  // Vector3转成4元数Quaternion
rigidbody.MoveRotation(rotation);  // 4元数传给刚体方法实现转向

如果要实现背对,最终的朝向向量取反就行了,这个很容易理解。

Vector3 turnForward = Vector3.RotateTowards(transform.forward, -m, turnSpeed * Time.deltaTime, 0f); // m取反实现背对朝向
transform.rotation = Quaternion.LookRotation(turnForward);	// Vector3转成4元数Quaternion

你可能感兴趣的:(游戏开发,Unity,游戏开发,unity,unity3d)