You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity第一人称FPS:为带冲刺功能的角色添加左右相机晃动效果

FPS侧移相机左右晃动实现方案(保留自由环顾)

需求说明

完成Brackey的FPS移动教程并添加冲刺机制后,需要为相机添加左右侧移时的左右晃动效果(非常见的上下晃动),同时保留相机自由环顾的功能。玩家对象结构为:Player根对象下包含CharacterController、PlayerMovement脚本,以及CameraHolder子对象,相机挂载在CameraHolder下。

现有PlayerMovement代码

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

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float speed = 12f;
    public float gravity = -9.81f;
    public float jumpHeight = 3f;
    public Camera cam;

    public int MaxFOV = 90;
    public float timeFOV = 0.03f;

    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;

    Vector3 velocity;
    bool isGrounded;

    // Update is called once per frame
    void Update()
    {
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if(isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        float s = Input.GetAxis("Fire3") + 1;

        if(s == 2)
        {
            cam.fieldOfView = Mathf.Lerp(cam.fieldOfView, MaxFOV, timeFOV);
        }
        else
        {
            cam.fieldOfView = Mathf.Lerp(cam.fieldOfView, 60, timeFOV);
        }

        Vector3 move = transform.right * x + transform.forward * z * s;

        controller.Move(move * speed * Time.deltaTime);

        if(Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }

        velocity.y += gravity * Time.deltaTime;

        controller.Move(velocity * Time.deltaTime);
    }
}

实现方法

核心思路

通过水平移动输入值(Horizontal轴)计算相机父物体(CameraHolder)的局部X轴偏移,用平滑插值实现自然的左右晃动,同时不干扰相机的旋转环顾功能。

修改后的完整代码

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

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float speed = 12f;
    public float gravity = -9.81f;
    public float jumpHeight = 3f;
    public Camera cam;

    public int MaxFOV = 90;
    public float timeFOV = 0.03f;

    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;

    // 新增相机晃动控制参数
    public Transform cameraHolder; // 拖入场景中的CameraHolder对象
    public float sideWobbleAmount = 0.15f; // 晃动幅度,可按需调整
    public float wobbleSmoothSpeed = 6f; // 晃动平滑速度,避免生硬抖动
    private Vector3 originalCameraLocalPos; // 记录相机初始位置

    Vector3 velocity;
    bool isGrounded;

    void Start()
    {
        // 初始化相机初始局部位置
        originalCameraLocalPos = cameraHolder.localPosition;
    }

    // Update is called once per frame
    void Update()
    {
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if(isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        float s = Input.GetAxis("Fire3") + 1;

        // 相机左右晃动逻辑
        // 反向偏移:左移时相机右偏,右移时左偏,符合视觉惯性
        float targetXOffset = -x * sideWobbleAmount;
        // 冲刺时可增大晃动幅度:targetXOffset = -x * sideWobbleAmount * s;
        Vector3 targetPos = originalCameraLocalPos + new Vector3(targetXOffset, 0, 0);
        // 平滑过渡到目标位置
        cameraHolder.localPosition = Vector3.Lerp(cameraHolder.localPosition, targetPos, wobbleSmoothSpeed * Time.deltaTime);

        if(s == 2)
        {
            cam.fieldOfView = Mathf.Lerp(cam.fieldOfView, MaxFOV, timeFOV);
        }
        else
        {
            cam.fieldOfView = Mathf.Lerp(cam.fieldOfView, 60, timeFOV);
        }

        Vector3 move = transform.right * x + transform.forward * z * s;

        controller.Move(move * speed * Time.deltaTime);

        if(Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }

        velocity.y += gravity * Time.deltaTime;

        controller.Move(velocity * Time.deltaTime);
    }
}

自定义调整建议

  • 若想让冲刺时晃动更强烈,可将晃动幅度的计算改为:float targetXOffset = -x * sideWobbleAmount * s;
  • 调整sideWobbleAmount(幅度)和wobbleSmoothSpeed(平滑度)参数,匹配你的操作手感
  • 若希望晃动带旋转效果而非纯位移,可替换位置偏移逻辑为旋转控制:
    float targetRotationY = -x * 2f; // 旋转角度,按需调整
    cameraHolder.localRotation = Quaternion.Lerp(cameraHolder.localRotation, Quaternion.Euler(0, targetRotationY, 0), wobbleSmoothSpeed * Time.deltaTime);
    

内容的提问来源于stack exchange,提问作者yesn't

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:48:11