我们在开发第三人称游戏过程中很容易遇到:我们的玩家角色,他面对北方,背后有一台摄像机,正巧也是面对北方。现在,他向右转90度,面对东方。此时如果让他向前走,那么会出现两种情况。
1.以自身坐标系向前走。他将会向眼睛直视的方向走,实际上他是向东方走,摄像机看到他是向"右"。

2.以世界坐标系向前走。他将会向北方走,摄像机看到他是向"前"。
由此可见,如果相机旋转了的话,人物没有同步旋转,那么以自身坐标系进行移动往往会发生错误,所以在游戏中角色的移动一般都是以世界坐标系进行移动。以世界坐标系进行移动的话,是不考虑物体自身的旋转的。

由此可见,我们需求上的“向前”实际上是从摄像机的角度上出发的,所以势必需要考虑到摄像机的旋转角度,我们的目标是,让角色沿摄像机角度方向前进,从代码角度上来说,就是:Quaternion*Vector3。即四元数旋转的轴向与角度乘以向量,后面具体阐释,先上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class _Move : MonoBehaviour {

    public float moveSpeed = 3f;

    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        Vector3 targetDirection = new Vector3(x, 0, z);
        float y = Camera.main.transform.rotation.eulerAngles.y;
        targetDirection = Quaternion.Euler(0, y, 0) * targetDirection;
        transform.Translate(targetDirection * Time.deltaTime * moveSpeed, Space.World);
    }
}

 以下三行代码初学者较难懂,我给出具体解释:

        Vector3 targetDirection = new Vector3(x, 0, z);

Unity默认方向:

Unity角色3C unity角色移动朝向_c#

首先我们需要获取到世界轴的正方向,即上面的Horizontal代表x轴,Vertical代表z轴,于是我们把获取到的世界轴方向先赋值给targetDirection
        float y = Camera.main.transform.rotation.eulerAngles.y;

光知道方向显然不够,我们还需要获取到摄像机的旋转角度,我们拖动摄像机rotation属性可以轻松得知,我们左右视角的变换是由它的rotation里面y值决定的
        targetDirection = Quaternion.Euler(0, y, 0) * targetDirection;

这一步尤为重要,它的几何含义是让先前的targetDirection向量绕y轴旋转y度,也就是实现让人物的方向向量随着摄像机的角度变化而发生变化。其中对四元数有兴趣的同学可以点进去具体了解。

最后一行移动代码里的Space.World可以提一下,我们平常可能会隐藏此参数不报错,因为不写会默认为Space.Self坐标系。

PS:World坐标系是固定的方向,不会随着物体的旋转而改变。
Self坐标系会随着自身的旋转而改变。