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

如何让玩家从不同Y位置起跳时跳跃峰值高度一致?

解决浮空球跳跃峰值一致的问题

我来帮你搞定这个跳跃高度不一致的难题!核心问题在于你当前直接固定Y轴速度的方式,没有考虑玩家相对球心的位置差异,也没把drag和重力缩放的影响纳入计算。下面我会一步步推导解决方案,并给出可直接复用的代码。

问题分析

你之前找到的公式都忽略了线性drag(Unity Rigidbody的drag是线性阻尼),而你的drag设为1,这个阻力会显著影响上升过程的速度衰减,导致固定初始速度时,不同起跳位置的峰值高度差异明显。我们需要的是:根据玩家当前位置与目标峰值的高度差,反向计算所需的初始速度,确保最终能到达一致的峰值。

关键参数整理

先明确我们已知的物理参数:

  • 基础重力:Physics.gravity.y = -9.81
  • 重力缩放:playerRigidbody.gravityScale = 7 → 实际重力 G = -9.81 * 7 = -68.67
  • 刚体drag:playerRigidbody.drag = 1
  • 目标峰值:你测试的从Y=0起跳的峰值为1.733022(可以是世界坐标,也可以是相对于球心的偏移量)

推导与实现

考虑drag的情况下,物体的上升运动是一个微分方程,没有简单的解析解,所以我们用数值迭代法(牛顿迭代)来反向求解所需的初始速度。

1. 计算给定初始速度的峰值高度

首先实现一个函数,输入初始速度、实际重力和drag,返回该速度下的跳跃峰值高度:

float CalculatePeakHeight(float initialVelocity, float gravity, float drag)
{
    // 无drag的情况,直接用经典物理公式
    if (Mathf.Approximately(drag, 0f))
    {
        return (initialVelocity * initialVelocity) / (-2 * gravity);
    }

    // 计算到达峰值的时间(速度为0的时刻)
    float term = (-gravity) / (drag * initialVelocity - gravity);
    if (term <= 0f)
    {
        // 初始速度不足以克服重力和阻力,无法向上跳
        return 0f;
    }
    float tPeak = (-1f / drag) * Mathf.Log(term);

    // 计算从起跳至峰值的位移(高度差)
    float displacement = (initialVelocity - gravity / drag) * (-1f / drag) * (Mathf.Exp(-drag * tPeak) - 1f) + (gravity / drag) * tPeak;
    return displacement;
}

2. 牛顿迭代求解所需初始速度

接下来用牛顿迭代法,根据目标高度差反推所需的初始速度:

float FindRequiredInitialVelocity(float targetDeltaY, float gravity, float drag, float initialGuess = 10f)
{
    float v0 = initialGuess;
    const int maxIterations = 10; // 迭代次数,足够收敛
    const float tolerance = 0.001f; // 精度要求,误差小于0.001米即可

    for (int i = 0; i < maxIterations; i++)
    {
        float currentPeak = CalculatePeakHeight(v0, gravity, drag);
        float error = currentPeak - targetDeltaY;

        // 误差足够小,停止迭代
        if (Mathf.Abs(error) < tolerance)
        {
            break;
        }

        // 用数值微分计算导数(峰值高度对初始速度的变化率)
        float deltaV = 0.001f;
        float peakPlus = CalculatePeakHeight(v0 + deltaV, gravity, drag);
        float derivative = (peakPlus - currentPeak) / deltaV;

        // 更新初始速度猜测值
        v0 -= error / derivative;
        // 确保速度为正,避免迭代出无效值
        v0 = Mathf.Max(v0, 0.1f);
    }

    return v0;
}

3. 整合到跳跃逻辑中

最后替换你原来的跳跃代码,根据玩家位置和目标峰值计算所需速度:

// 1. 确定目标峰值的世界Y坐标(根据你的需求调整)
// 例1:保持和原来Y=0起跳时相同的世界峰值
float targetWorldPeakY = 1.733022f;
// 例2:保持相对于球心的峰值偏移(比如球心Y+1.733)
// float targetWorldPeakY = sphereTransform.position.y + 1.733022f;

// 2. 计算需要跳跃的高度差
float deltaY = targetWorldPeakY - playerTransform.position.y;

if (deltaY > 0f) // 只有需要向上跳时才执行
{
    float actualGravity = Physics.gravity.y * playerRigidbody.gravityScale;
    float drag = playerRigidbody.drag;

    // 计算所需的初始Y速度
    float requiredJumpVelocity = FindRequiredInitialVelocity(deltaY, actualGravity, drag);

    // 重置Y速度并施加跳跃力
    Vector3 newVelocity = playerRigidbody.velocity;
    newVelocity.y = 0f; // 清空当前Y速度,避免叠加
    newVelocity.y += requiredJumpVelocity;
    playerRigidbody.velocity = newVelocity;
}

测试验证

  • 先测试无drag的情况:把drag设为0,此时CalculatePeakHeight应该和经典公式结果一致,验证函数正确性。
  • 再测试有drag的情况:分别从球顶和球底起跳,检查峰值是否一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:25:26