使用数学公式定义玩家速度

Using a mathematical formula to define player speed

我正在制作简单的游戏,通过向玩家施加力来移动玩家。但是,我不希望他的加速度保持不变——我希望它根据当前速度而变化。我制作了简单的加速脚本来执行此操作,但没有达到预期的效果:

float acceleration
{
    get { return speed/inversedAcceleration; }
}

void FixedUpdate () {
    rb.AddForce(transform.forward * speed);
    if (speed < maxSpeed)
        speed += acceleration * Time.deltaTime;    
}

我也试过的新方法:

float timer = 1.0f;

public float velocity { get { return Mathf.Sqrt(timer)*10; } }

void FixedUpdate()
{
    timer += Time.deltaTime;
    rb.AddForce(transform.forward * velocity);
}

逻辑有点绕,因为我试验了一段时间没有成功。现在,我认为我应该将其更改为使用数学公式 f(x)=sqrt(x) 作为我速度的模型,而不是我当前使用的某种有理函数形式的模型。我如何更改代码来执行此操作,同时仍然使用 AddForce() 以便玩家能够正确地与其他对象进行物理交互?

因为你想让所有的物理公式保持一致(重新发明运动学是棘手的),一个物理解决方案可能是使物体质量成为其速度的函数(例如 m=m_0+k*v^2 得到像你这样的东西 sqrt方法)。

因此,当物体质量较大(即行进速度更快)时,力 F=ma 将导致较低的加速度。

听起来很熟悉?嗯,这就是 E=mc^2 表示物体运动速度非常快的意思。但是,我不建议实施其他相对论效应。

如评论中所述,我的第一个建议是避免手动跟踪对象的速度 - Unity 的物理系统通过 Rigidbody.velocity.magnitude 使这一点易于准确访问。您可以使用它与 maxSpeed 进行比较,以确定是否应添加额外的力。

关于您希望速度与 f(x)=sqrt(x) 曲线匹配的愿望,您将需要为此做一些基本的微积分。由于您不想人为地限制速度(因为您仍然希望发生物理交互),您应该改为将加速度限制为一个函数。

要确定用于定义玩家加速度的函数,您需要导出希望速度(理想情况下)匹配的函数。这将为您提供任何给定点的速度变化率 - 根据定义,这就是加速度。

所以假设我们使用函数 f(x)=sqrt(x) 作为理想速度的模型。 sqrt(x) 的导数是 1/(2 * sqrt(x)) - 所以这是定义加速度的函数。现在,我们需要能够确定任何给定速度的加速度,因为这是我们将在代码中使用的关系。这需要一些简单的代数知识——我们需要求解 x 给定 y:

          y = 1/(2 * sqrt(x))
sqrt(x) * y = 1 / 2
    sqrt(x) = 1 / (2 * y)
          x = (1 / (2 * y))^2

现在我们有一个方程式,可以为我们提供任何给定速度所需的加速度。我们现在可以将其放入代码中——根据平方根函数加速到 maxSpeed:

float maxAcceleration = 10;

// Basically x = (1 / (2 * y))^2, but in code
float CalculateAccGivenSpeed(float speed)
{
    // Early exit so we don't bother with undefined results from dividing by 0
    if (speed == 0)
    {
        return Mathf.Infinity;
    }

    float rootAcc = 1 / (2 * speed);
    return rootAcc * rootAcc;
}

void FixedUpdate()
{
    // Only accelerate if speed is lower than maximum allowed
    if (rb.velocity.magnitude < maxSpeed)
    {
        float allowableAcc = CalculateAccGivenSpeed(rb.velocity.magnitude);

        // Constrain acceleration here so rigidbody doesn't explode from stationary
        allowableAcc = Mathf.Min(maxAcceleration, allowableAcc);

        // Using ForceMode.Acceleration so we don't have to worry about mass
        rb.AddForce(transform.forward * allowableAcc, ForceMode.Acceleration);
    }
}

如果您发现加速度过大quickly/slowly,您可以将CalculateAccGivenSpeed()的结果乘以一个标量值。从数学上讲,这将沿 y 轴缩放平方根函数,保留平方根关系,但改变达到给定 y 值(速度)的速率。

希望对您有所帮助!如果您有任何问题,请告诉我。