使用数学公式定义玩家速度
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 值(速度)的速率。
希望对您有所帮助!如果您有任何问题,请告诉我。
我正在制作简单的游戏,通过向玩家施加力来移动玩家。但是,我不希望他的加速度保持不变——我希望它根据当前速度而变化。我制作了简单的加速脚本来执行此操作,但没有达到预期的效果:
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 值(速度)的速率。
希望对您有所帮助!如果您有任何问题,请告诉我。