文章总结:
第一人称:FaceDirection(面朝方向)与 鼠标的方向一致。
移动:moveDirection 为 FaceDirection.forward * 上下方向的输入 + FaceDirection.right * 左右方向的输入。
旋转:人物的forward 永远跟随FaceDirection.forward 。
第三人称:FaceDirection(面朝方向)为摄像机位置指向人物的位置(忽略y轴影响)。
移动:非锁定:moveDirection 永远为 人物的forward;锁定:moveDirection 为 transform.forward * 上下方向的输入 + transform.right * 左右方向的输入。
旋转:非锁定:moveDirection 为 FaceDirection.forward * 上下方向的输入 + FaceDirection.right * 左右方向的输入; 锁定:moveDirection为从人物指向敌人。
在人物上挂载有FaceDirection(存储角色应该移动的前方),在第一人称下FaceDirection是人物的面向(也是摄像机的朝向),而在第三人称下FaceDirection指的是摄像机相关(想象一个在地面上的摄像机)的面向(即忽略掉摄像机的Y轴)。同时挂有FirstCamPos,存储第一人称摄像机应该所在的位置。
一:第一人称
摄像机朝向有两种方案:
(1)始终朝向鼠标所指的方向。(2)始终朝着人物面向的前方。
FirstPersonCamera类:
要点:1:使用全局变量记录要旋转的值
2:调用 Quaternion.Euler 同时调整摄像机的角度和人物面朝方向的角度
//第一人称视角下摄像机的行为
public class FirstPersonCamera : MonoBehaviour
{
[Header("第一人称视角相机 参数")]
public float senX; //X轴灵敏度
public float senY; //Y轴灵敏度
[Header("组件")]
public Transform playerFaceDirection; //人物面向的方向
public Transform camPosition;
private PlayerController playerController;
private MouseController mouseInput;
private float xRotation;
private float yRotation;
private void Awake()
{
mouseInput = new MouseController();
playerController = playerFaceDirection.GetComponentInParent<PlayerController>();
}
private void OnEnable()
{
mouseInput.Enable();
GlobalEvent.switchToFirstPersonEvent += OnSwitchToFirstPerson;
GlobalEvent.CallSwitchToFirstPersonEvent();
}
private void OnDisable()
{
mouseInput.Disable();
GlobalEvent.switchToFirstPersonEvent -= OnSwitchToFirstPerson;
}
private void OnSwitchToFirstPerson()
{
//在从第三人称转到第一人称的时候 需要调整yRotation xRotation
yRotation = Vector3.Angle(playerFaceDirection.forward, Vector3.forward);
xRotation = 0;
if (Vector3.Cross(playerFaceDirection.forward, Vector3.forward).y > 0) yRotation *= -1;
}
private void Update()
{
transform.position = camPosition.position;
Vector2 mouse = mouseInput.GamePlay.MouseMove.ReadValue<Vector2>();
yRotation += mouse.x * Time.deltaTime * senX; //绕y轴的旋转(控制左右)
xRotation -= mouse.y * Time.deltaTime * senY; //绕x轴的旋转(控制上下)
xRotation = Mathf.Clamp(xRotation, -60f, 60f);
//调整摄像机的朝向 选择1:始终朝向鼠标所指的方向 选择2:始终朝向人物面部的前方
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
//transform.forward = camPosition.forward;
playerFaceDirection.rotation = Quaternion.Euler(0, yRotation, 0); //调整人物面朝的方向
}
}
PlayerController类:(移动和旋转)
要点:1:人物根据面朝的方向前后左右移动 2:人物的面向 = faceDirection的面向
3:moveDirection 根据 faceDirectiono的forward和right进行计算
//第一人称方式移动人物
private void MovePlayerInFirstPerson()
{
//如果移动方向有阻碍物:障碍,敌人等 返回
if (playerAnimationInf.IsWalk == false) return;
moveDirection = faceDirection.forward * inputDirection.y + faceDirection.right * inputDirection.x;
if (physicalCheck.HaveBarrierInMoveDirection(transform.position + transform.up * 0.5f, moveDirection, moveDirection.normalized.magnitude * curSpeed * Time.deltaTime * 2)) return;
characterController.Move(moveDirection.normalized * (curSpeed * Time.deltaTime));
}
//第一人称方式旋转人物
private void RotatePlayerInFirstPerson()
{
transform.forward = faceDirection.forward;
}
Cinemachine的参数设置(VirtualMachine,最普通的相机,没有特殊功能,可以随意调整)
二:第三人称
鼠标的移动只会导致摄像机的移动(使用CinemachiineFreeLook),WASD根据的是摄像机的朝向进行转向和移动。
ThirdPersonCamera类:
要点:摄像机的 viewDir = X的坐标 - 摄像机的坐标 (注意忽略y轴)faceDirection.forward=viewDir ( 战斗视角下X为Player右上角一个点,普通视角下X为Player)
//第三人称视角下 摄像机的行为
public class ThirdPersonCamera : MonoBehaviour
{
[Header("组件")]
public Transform faceDirection;
public Transform combatLookAt;
public Transform player;
private CinemachineFreeLook cinemachine;
private void Awake()
{
cinemachine=GetComponent<CinemachineFreeLook>();
}
private void OnEnable()
{
//在从第一人称转到第三人称的时候 需要调整 XAxis.Value
float angle = Vector3.Angle(player.forward, Vector3.forward);
if (Vector3.Cross(player.forward, Vector3.forward).y > 0) angle *= -1;
cinemachine.m_XAxis.Value = angle;
}
private void Update()
{
//faceDirection.position = new Vector3(transform.position.x, cinemachine.LookAt.position.y, transform.position.z);
//faceDirection.LookAt(cinemachine.LookAt);
if (CameraManager.Instance.currentCameraStyle == CameraStyle.ThirdPersonNormal || CameraManager.Instance.currentCameraStyle == CameraStyle.ThirdPersonTopDown)
{
Vector3 viewDir = player.position - new Vector3(transform.position.x, player.position.y, transform.position.z);
faceDirection.forward = viewDir.normalized;
}
else if(CameraManager.Instance.currentCameraStyle==CameraStyle.ThirdPersonCombat)
{
Vector3 viewDir = combatLookAt.position - new Vector3(transform.position.x, combatLookAt.position.y, transform.position.z);
faceDirection.forward = viewDir.normalized;
}
}
}
PlayController类:
要点: 1:人物移动方向永远是面朝的方向 2:人物的面向根据 摄像机的viewDir(忽略掉Y轴后摄像机的面向)和输入共同调整(使用Slerp实现平滑转动)
//第三人称方式移动人物
private void MovePlayerInThirdPerson()
{
//人物的实际移动:始终朝着面朝的方向进行移动
characterController.Move(transform.forward * curSpeed * Time.deltaTime);
}
//第三人称方式旋转人物
private void RotatePlayerInThirdPerson()
{
moveDirection = faceDirection.forward * inputDirection.y + faceDirection.right * inputDirection.x;
if(moveDirection!=Vector3.zero)
{
transform.forward = Vector3.Slerp(transform.forward, moveDirection, rotationSpeed * Time.deltaTime);
}
}
补充:第三人称视角还分成了3个:常规视角,战斗视角,俯视角
常规视角:
Cinemachine设置:
跟随和朝向都是Player,轨道设置如下:
战斗视角:
人物保持在屏幕的左下方(通过将朝向设置为人物右上角的一个位置即可,在摄像机的viewDir计算时要变化),轨道设置如下:
俯视角:基本同常规视角,轨道设置如下:
不同视角的切换:切换动画由CinemachineBrain控制
CameraManager类:
using Cinemachine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraManager : Singleton<CameraManager>
{
[Header("不同摄像机")]
public GameObject firstPersonCamera;
public GameObject thirdPersonNormalCamera;
public GameObject thirdPersonCombatCamera;
public GameObject thirdPersonTopDownCamera;
public CinemachineBrain cinemachineBrain;
[Header("游戏状态")]
public CameraStyle currentCameraStyle; //当前摄像机所处的状态
private void Start()
{
SwitchCameraStyle(CameraStyle.ThirdPersonNormal);
cinemachineBrain.m_DefaultBlend.m_Style = CinemachineBlendDefinition.Style.EaseIn;
}
private void Update()
{
//按键设置
if(Input.GetKeyDown(KeyCode.V))
{
if (currentCameraStyle != CameraStyle.FirstPerson)
SwitchCameraStyle(CameraStyle.FirstPerson);
else SwitchCameraStyle(CameraStyle.ThirdPersonNormal);
}
}
public void SwitchCameraStyle(CameraStyle newStyle)
{
//先设置所有相机为false 在选择激活新相机
firstPersonCamera.SetActive(false);
thirdPersonNormalCamera.SetActive(false);
thirdPersonCombatCamera.SetActive(false);
thirdPersonTopDownCamera.SetActive(false);
if (newStyle == CameraStyle.FirstPerson || currentCameraStyle == CameraStyle.FirstPerson)
cinemachineBrain.m_DefaultBlend.m_Style = CinemachineBlendDefinition.Style.Cut;
else
cinemachineBrain.m_DefaultBlend.m_Style = CinemachineBlendDefinition.Style.EaseIn;
switch (newStyle)
{
case CameraStyle.FirstPerson:
firstPersonCamera.SetActive(true);
GlobalEvent.CallSwitchToFirstPersonEvent();
break;
case CameraStyle.ThirdPersonNormal:
thirdPersonNormalCamera.SetActive(true);
break;
case CameraStyle.ThirdPersonCombat:
thirdPersonCombatCamera.SetActive(true);
break;
case CameraStyle.ThirdPersonTopDown:
thirdPersonTopDownCamera.SetActive(true);
break;
}
currentCameraStyle = newStyle;
}
}
在第一人称切换到第三人称时:保证切换后摄像机在人物的后方
在第三人称切换到第一人称时:需要手动调整yRotation