一、人物移动
在大多数的游戏当中,不仅有玩家本身需要移动,游戏内的许多NPC也需要移动,因此我们可以将“人物移动”的代码拆分成“人物”代码和“移动”代码,这样一来,便可以方便我们后期的维护,并不需要分别为玩家和NPC都写下移动的代码。
1.关于角色移动
[RequireComponent(typeof(Rigidbody))]
public class CharacterMovement: MonoBehaviour
{
private Rigidbody _rigidbody;
public Vector3 CurrentInput { get; private set; }
public float MaxWalkSpeed = 5;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
_rigidbody.MovePosition(_rigidbody.position + CurrentInput * MaxWalkSpeed * Time.fixedDeltaTime);
}
public void SetMovementInput(Vector3 input)
{
CurrentInput = Vector3.ClampMagnitude(input, 1);
}
}
MovePosition意为“新的位置”,可为挂载Rigidbody组件的物体而用,是一个路程单位,而路程=速度*时间,因此可以写为“新的位置=当前的位置+移动速度*时间”,即
_rigidbody.MovePosition(_rigidbody.position + CurrentInput * MaxWalkSpeed * Time.fixedDeltaTime);
用以确保CurrentInput为模长为1的向量:
CurrentInput = Vector3.ClampMagnitude(input, 1);
可以通过以下写法做到一个属性对外只读,对类自身而言可以对其值进行修改
public Vector3 CurrentInput { get; private set; }
使用RequireComponent可以让挂载此C#的物体自带组件
2.关于玩家角色
public class PlayerCharacter: MonoBehaviour
{
private CharacterMovement _characterMovement;
[SerializeField]
private Photographer _photographer;
[SerializeField] private Transform _followingTarget;
private void Awake()
{
_characterMovement = GetComponent<CharacterMovement>();
_photographer.InitCamera(_followingTarget);
}
void Update()
{
UpdateMovementInput();
}
private void UpdateMovementInput()
{
Quaternion rot = Quaternion.Euler(0, _photographer.Yaw, 0);
_characterMovement.SetMovementInput(rot * Vector3.forward * Input.GetAxis("Vertical") +
rot * Vector3.right * Input.GetAxis("Horizontal"));
}
}
[SerializeField]----将私有类型和保护类型可视化到面板上
二、相机跟随
在写下相机跟随的代码前,我们需要先为摄像机创建一个坐标轴
在大多数第三人称游戏中,摄像机并不会完完全全地跟随玩家角色,大多数游戏里当玩家向前移动时,操控者都可以移动视角达到看玩家的正面,以达到向前移动时仍可以观察四周
在Unity中Project Settings自带的方法中,就存在自带的一个坐标轴:
MouseX,MouseY给出是一个“距离”,即鼠标所移动的距离
而Horizontal(水平的)与Vertical(竖直的)给出的则是一个比率
即当其数值为0的时候,则静止;数值为1的时候,则移动;0.5则为半速移动
因此,显然Horizontal相比于MouseX更适合做摄像机移动的坐标轴,我们便可
复制Horizontal,改名为“CameraRateX”,并设定为第4坐标系
复制Vertical,改名为“CameraRateY”,并设定为第5坐标系,将此作为摄像机坐标轴
public class Photographer : MonoBehaviour
{
public float Pitch { get; private set; }
public float Yaw { get; private set; }
public float mouseSensitivity = 5;
public float cameraRotatingSpeed = 80;
public float cameraYSpeed = 5;
private Transform _target;
private Transform _camera;
[SerializeField] private AnimationCurve _armLengthCurve;
private void Awake()
{
_camera = transform.GetChild(0);
}
public void InitCamera(Transform target)
{
_target = target;
transform.position = target.position;
}
void Update()
{
UpdateRotation();
UpdatePosition();
UpdateArmLength();
}
private void UpdateRotation()
{
Yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
Yaw += Input.GetAxis("CameraRateX") * cameraRotatingSpeed * Time.deltaTime;
Pitch += Input.GetAxis("Mouse Y") * mouseSensitivity;
Pitch += Input.GetAxis("CameraRateY") * cameraRotatingSpeed * Time.deltaTime;
Pitch = Mathf.Clamp(Pitch, -90, 90);
transform.rotation = Quaternion.Euler(Pitch, Yaw, 0);
}
private void UpdatePosition()
{
Vector3 position = _target.position;
float newY = Mathf.Lerp(transform.position.y, position.y, Time.deltaTime * cameraYSpeed);
transform.position = new Vector3(position.x, newY, position.z);
}
private void UpdateArmLength()
{
_camera.localPosition = new Vector3(0, 0, _armLengthCurve.Evaluate(Pitch) * -1);
}
}
其中Pitch为绕X轴旋转,Yaw为绕竖直方向的Y轴旋转
Yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
Yaw += Input.GetAxis("CameraRateX") * cameraRotatingSpeed * Time.deltaTime;
Pitch += Input.GetAxis("Mouse Y") * mouseSensitivity;
Pitch += Input.GetAxis("CameraRateY") * cameraRotatingSpeed * Time.deltaTime;
mouseSensitivity为鼠标灵敏度
其中“+=”:用于指定响应事件时要调用的方法,这类方法称为事件处理程序,叫注册/订阅事件,用在操作类名后
在大多数第三人称游戏中,往上拖动视角可以看向天空,但若一直往上拉,则会导致像太空类游戏一样视角倒转,因此需要规定摄像机可旋转的最大范围
Pitch = Mathf.Clamp(Pitch, -90, 90);
在大多数第三人称游戏中,当把视角往下拉,摄像机则会越来越靠近人物,这是为了防止摄像机看到地下,因此,我们需要一个添加一条曲线并设定摄像机臂长方法
此外,我们可以创建一个空物体放置在玩家的头部,以确保相机一直跟随着玩家的头部
[SerializeField] private AnimationCurve _armLengthCurve;
private void UpdateArmLength()
{
_camera.localPosition = new Vector3(0, 0, _armLengthCurve.Evaluate(Pitch) * -1);
}
将曲线的两点设为(-90,0.8)和(90,10)
关于在摄像机旋转所用到的欧拉角相关知识,参考:
Unity之C#学习笔记(4):Unity中旋转的表示——四元数 Quaternion(上)_quaternion xyzw_Altair_Alpha_的博客-CSDN博客