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

Unity无RigidBody实现FPS角色摆动效果的技术求助

Unity FPS角色挂钩平滑摆动实现方案

核心问题分析

你的现有代码存在几个关键问题:

  • 直接用Transform.Translate移动角色,没有遵循挂钩点为圆心、绳索长度为半径的圆周运动逻辑,导致摆动无约束且混乱
  • 用Mathf.PingPong控制速度,没有结合物理惯性或玩家输入,摆动生硬且不符合直觉
  • 叉积计算的方向参考了Player的本地位置,而绳索挂载点是GunTip,应该以GunTip的位置作为绳索起点来计算方向

正确实现思路

  • 固定绳索长度:创建挂钩时,记录GunTip到命中点的距离,作为绳索的固定长度,确保角色摆动时不会脱离绳索范围
  • 圆周运动逻辑:以挂钩点为圆心,计算角色当前位置在圆周上的切线方向,结合鼠标输入控制摆动的角速度
  • 平滑物理移动:用CharacterController.Move(若使用CharacterController)或Rigidbody处理角色移动,保证碰撞交互正常,同时用平滑插值让摆动更自然
  • 玩家主动控制:通过鼠标输入调整摆动方向,让玩家可以主动控制摆动的幅度和节奏

修改后的代码示例

假设你的Player使用CharacterController,先定义必要变量:

public CharacterController playerController;
public Transform gunTip; // 拖拽赋值GunTip对象
public GameObject hookPrefab;
public LayerMask hookMask;
private GameObject hook;
private float ropeLength; // 绳索固定长度
private Vector3 swingVelocity; // 摆动速度
private float swingSpeed = 8f; // 摆动角速度
private float smoothDampTime = 0.1f; // 平滑过渡时间
private bool canSwing;

创建挂钩函数修正

void CreateHook()
{
    RaycastHit hit;
    Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);

    if (Physics.Raycast(ray, out hit, 100f, hookMask))
    {
        // 销毁旧挂钩(如果存在)
        if (hook != null) Destroy(hook);
        hook = Instantiate(hookPrefab, hit.point, Quaternion.identity);
        // 记录绳索长度:GunTip到命中点的直线距离
        ropeLength = Vector3.Distance(gunTip.position, hit.point);
        canSwing = true;
        // 初始化摆动速度
        swingVelocity = Vector3.zero;
    }
}

平滑摆动函数实现

void StartSwinging()
{
    if (hook == null || !canSwing) return;

    // 获取挂钩点与当前GunTip位置
    Vector3 hookPoint = hook.transform.position;
    Vector3 currentGunTipPos = gunTip.position;

    // 修正GunTip位置,确保绳索长度固定
    Vector3 toGunTip = currentGunTipPos - hookPoint;
    Vector3 desiredGunTipPos = hookPoint + toGunTip.normalized * ropeLength;

    // 计算摆动切线方向:垂直于绳索方向与世界向上方向的叉积
    Vector3 swingTangent = Vector3.Cross(toGunTip.normalized, Vector3.up).normalized;

    // 用鼠标X轴输入控制摆动方向
    float mouseInput = Input.GetAxis("Mouse X");
    swingVelocity += swingTangent * mouseInput * swingSpeed * Time.deltaTime;

    // 加入阻尼,让摆动自然减速
    swingVelocity = Vector3.Lerp(swingVelocity, Vector3.zero, smoothDampTime * Time.deltaTime);

    // 计算角色目标位置:GunTip期望位置反向偏移GunTip相对于Player的本地坐标
    Vector3 targetPlayerPos = desiredGunTipPos - gunTip.localPosition;
    // 平滑移动角色
    playerController.Move((targetPlayerPos - transform.position + swingVelocity) * Time.deltaTime);
}

额外优化建议

  • 用LineRenderer连接GunTip和挂钩点,可视化绳索,提升体验
  • 限制swingVelocity的最大值,避免摆动幅度过大失控
  • 如果挂钩点在可移动物体上,需要同步挂钩点的位置更新,否则摆动逻辑会失效

内容的提问来源于stack exchange,提问作者Midnight Demise

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 21:45:30