优化第三人称相机

第三人称相机优化方案

概述

将相机控制逻辑从 Update() 迁移到 FixedUpdate() 以提高性能和稳定性。

优化原因

  • 性能提升: FixedUpdate() 以固定时间间隔执行,减少不必要的计算
  • 稳定性增强: 避免帧率波动对相机移动的影响
  • 物理一致性: 与物理系统保持同步,减少抖动

核心代码

private void LateUpdate()
{
    // 安全检查
    if (followTarget == null || !isInitialized) return;

    // 1. 视角控制反转参数设置
    invertXValue = (invertX) ? -1 : 1;
    invertYValue = (invertY) ? -1 : 1;

    // 2. 视角旋转计算
    // 水平视角控制 - 鼠标/手柄X轴控制Y轴旋转
    rotationY += Input.GetAxis("Camera X") * rotationSpeed * invertYValue * Time.fixedDeltaTime;
    // 垂直视角控制 - 鼠标/手柄Y轴控制X轴旋转
    rotationX += Input.GetAxis("Camera Y") * rotationSpeed * invertXValue * Time.fixedDeltaTime;
    // 限制垂直旋转角度范围
    rotationX = Mathf.Clamp(rotationX, minVerticalAngle, maxVerticalAngle);

    // 3. 计算目标旋转
    targetRotation = Quaternion.Euler(rotationX, rotationY, 0);

    // 4. 计算相机位置
    // 焦点位置 = 目标位置 + 偏移量
    var focusPosition = followTarget.position + new Vector3(frameOffset.x, frameOffset.y, 0);
    // 目标位置 = 焦点位置 - 旋转后的距离向量
    targetPosition = focusPosition - targetRotation * new Vector3(0, 0, distance);

    // 5. 平滑插值更新相机变换
    transform.position = Vector3.Lerp(transform.position, targetPosition, smoothSpeed * Time.fixedDeltaTime);
    transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, smoothSpeed * Time.fixedDeltaTime);
}
参数 类型 说明
followTarget Transform 相机跟随的目标对象
rotationSpeed float 视角旋转速度
smoothSpeed float 相机平滑移动速度
distance float 相机与目标的距离
frameOffset Vector2 相机焦点偏移量
minVerticalAngle float 垂直旋转最小角度
maxVerticalAngle float 垂直旋转最大角度

完整代码

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

public class CameraController : MonoBehaviour
{
    //摄像机跟随的目标
    [SerializeField] Transform followTarget;
    [SerializeField] float rotationSpeed = 1.5f;
    //距离
    [SerializeField] float distance;

    //绕y轴的旋转角度——水平视角旋转
    float rotationY;
    //绕x轴的旋转角度——垂直视角旋转
    float rotationX;
    //限制rotationX幅度
    [SerializeField] float minVerticalAngle = -20;
    [SerializeField] float maxVerticalAngle = 45;
    //框架偏移向量——摄像机位置视差偏移
    [SerializeField] Vector2 frameOffset;

    //视角控制反转
    [Header("视角控制反转:invertX是否反转垂直视角,invertY是否反转水平视角")]
    [SerializeField] bool invertX;
    [SerializeField] bool invertY;

    float invertXValue;
    float invertYValue;

    // 帧同步相关参数
    [Header("帧同步设置")]
    [SerializeField] float smoothSpeed = 10f; // 平滑插值速度
    private Vector3 targetPosition;
    private Quaternion targetRotation;
    private bool isInitialized = false;

    private void Start()
    {
        //隐藏光标
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
  
        // 初始化目标位置和旋转
        if (followTarget != null)
        {
            InitializeCamera();
        }
    }

    private void InitializeCamera()
    {
        // 计算初始旋转
        var initialRotation = Quaternion.Euler(rotationX, rotationY, 0);
        var focusPosition = followTarget.position + new Vector3(frameOffset.x, frameOffset.y, 0);
  
        // 设置初始位置和旋转
        transform.position = focusPosition - initialRotation * new Vector3(0, 0, distance);
        transform.rotation = initialRotation;
  
        // 设置目标位置和旋转
        targetPosition = transform.position;
        targetRotation = transform.rotation;
  
        isInitialized = true;
    }

    private void LateUpdate()
    {
        if (followTarget == null || !isInitialized) return;

        //视角控制反转参数
        invertXValue = (invertX) ? -1 : 1;
        invertYValue = (invertY) ? -1 : 1;

        //水平视角控制——鼠标(手柄)x轴控制rotationY
        rotationY += Input.GetAxis("Camera X") * rotationSpeed * invertYValue * Time.fixedDeltaTime;
        //垂直视角控制——鼠标(手柄)y轴控制rotationX
        rotationX += Input.GetAxis("Camera Y") * rotationSpeed * invertXValue * Time.fixedDeltaTime;
        //限制rotationX幅度
        rotationX = Mathf.Clamp(rotationX, minVerticalAngle, maxVerticalAngle);

        //视角旋转参量
        //想要水平旋转视角,所以需要的参量为绕y轴旋转角度
        targetRotation = Quaternion.Euler(rotationX, rotationY, 0);

        //摄像机的焦点位置
        var focusPosition = followTarget.position + new Vector3(frameOffset.x, frameOffset.y, 0);
  
        //摄像机放在目标后面指定距离的位置
        targetPosition = focusPosition - targetRotation * new Vector3(0, 0, distance);

        // 使用平滑插值更新相机位置和旋转
        transform.position = Vector3.Lerp(transform.position, targetPosition, smoothSpeed * Time.fixedDeltaTime);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, smoothSpeed * Time.fixedDeltaTime);
    }



    //水平方向的旋转,返回摄像机的水平旋转四元数。
    public Quaternion PlanarRotation => Quaternion.Euler(0, rotationY, 0);

    /// <summary>
    /// 设置相机距离
    /// </summary>
    public void SetDistance(float newDistance)
    {
        distance = newDistance;
    }

    // 获取当前相机距离
    public float GetDistance => distance;

    /// <summary>
    /// 设置平滑速度
    /// </summary>
    public void SetSmoothSpeed(float speed)
    {
        smoothSpeed = speed;
    }
}

待扩展

  • 添加相机碰撞检测系统
  • 实现相机震动效果
  • 支持多目标切换
  • 添加相机FOV动态调整
posted @ 2025-08-04 14:16  EanoJiang  阅读(29)  评论(0)    收藏  举报