第三人称视角类的游戏有很多,比如《原神》、《崩坏:星穹铁道》、《剑星》、《绝地求生》等。这些游戏中,角色的移动方向取决于玩家的输入和相机的方向,例如玩家在键盘上按下D键,则角色会相对于相机方向向右移动,本篇文章就来揭晓这背后的实现方式。
1. 基于骨骼动画的移动
1.1 骨骼设置
首先选中一个骨骼动画,单击 Inspector 面板里的 Animation 选项卡按钮:
我们以行走动画为例,如果我们想让动画中出现的模型偏移来改变角色的实际位置,那么我们就要取消勾选 XZ轴 的 Bake into Pose:
如果是跳跃动画,则需要取消勾选 Y轴 的 Bake into Pose。
1.2 位移同步
假设目前我们的角色有一个胶囊体(characterController)和一个动画器(animator),并正在播放与位移相关的动画,如下代码实现了动画的运动偏移对模型造成了一个实际的位移:
// 根运动事件
private void OnAnimatorMove()
{
OnRootMotion(animator.deltaPosition, animator.deltaRotation);
}
private void OnRootMotion(Vector3 deltaPosition, Quaternion deltaRotation)
{
// 加入重力影响
deltaPosition.y = gravity * Time.deltaTime;
// 对玩家进行一个实际的位移
characterController.Move(deltaPosition);
}
1.3 模型朝向纠正
接下来,我们要根据玩家的输入和相机的朝向来实现类似于《原神》的角色移动方向的机制,核心代码十分简单,并不需要我们亲自编写旋转算法,拿来即用:
void Update()
{
// 玩家输入向量:x - 水平输入,y - 垂直输出
Vector2 moveVector = PlayerInput.input.Player.Move.ReadValue<Vector2>().normalized;
// 转向过渡
float rotateSpeed = 5f;
// -----------核心代码-----------
// 将玩家的输入组合成一个三维向量
Vector3 input = new Vector3(moveVector.x, 0, moveVector.y);
// 拿到相机的朝向
float y = Camera.main.transform.rotation.eulerAngles.y;
// 求得角色的目标移动方向
Vector3 targetDic = Quaternion.Euler(0, y, 0) * input;
// 让模型旋转到目标方向
transform.rotation = Quaternion.Slerp(transform.rotation,
Quaternion.LookRotation(targetDic), Time.deltaTime * rotateSpeed);
}
2. 非骨骼动画的模型朝向纠正
private void PlayerMoveControl() {
// 让模型旋转到目标方向
if (transform.eulerAngles != targetDic)
transform.rotation = Quaternion.Slerp(transform.rotation,
Quaternion.LookRotation(targetDic), Time.deltaTime * rotateSpeed);
// 处理玩家输入方向
moveVector = inputControl.Player.Move.ReadValue<Vector2>().normalized;
if (moveVector == Vector2.zero)
return;
Vector3 inputDirection = new Vector3(moveVector.x, 0, moveVector.y);
// 拿到相机的朝向
float cameraDic = Camera.main.transform.eulerAngles.y;
// 更新角色的目标移动方向
targetDic = Quaternion.Euler(0, cameraDic, 0) * inputDirection;
// 让角色朝该方向移动
controller.Move(targetDic * moveSpeed * Time.deltaTime);
}