问题描述
如果使用控制器输入的方向直接移动物体,只能使物体在世界坐标系下或者自身坐标系下前后左右移动,就好像很早以前的游戏里的坦克式移动。如果想操作物体相对于相机镜头做前后左右移动,就需要将输入的向量进行坐标系变换。
实现方法
手动坐标系转换可能有一些复杂,好在Unity提供了非常方便使用的坐标系转换用的函数。使用Transform类中的TransformXXX系列的函数即可快速实现坐标系转换。
csharp:Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float speed; // 移动速度
private Transform cameraTransform;
private Transform CameraTransform // 获取主相机的Transform并缓存
{
get
{
if(cameraTransform == null)
{
cameraTransform = Camera.main.transform;
}
return cameraTransform;
}
}
private Transform _transform;
private Transform Transform // 获取自身的Transform并缓存
{
get
{
if(_transform == null)
{
_transform = transform;
}
return _transform;
}
}
private void Update()
{
// 取得水平和竖直方向的输入值
var x = Input.GetAxis("Horizontal");
var y = Input.GetAxis("Vertical");
// 没有输入时不执行后续处理
if (Mathf.Abs(x) < float.Epsilon && Mathf.Abs(y) < float.Epsilon)
{
return;
}
// 由方向输入来创建一个用于控制玩家位移向量
var inputVector = new Vector3(x, 0, y);
// 如果长度大于1则归一化
if(inputVector.sqrMagnitude > 1f)
{
inputVector.Normalize();
}
// 将inputVector从相机坐标系转换到世界坐标系
var direction = CameraTransform.TransformDirection(inputVector);
// 去除y方向上的分量并归一化,然后再乘上原本向量的长度,就可以得到一个长度等于输入向量,且平行于世界坐标系XZ平面的向量了
direction.y = 0;
direction = direction.normalized * inputVector.magnitude;
// 使用变换后的向量进行位移,即可实现在相机镜头下的前后左右位移了
Transform.Translate(speed * Time.deltaTime * direction, Space.World);
Transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
}
}