微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

您何时在Unity中乘以Time.deltaTime? 示例1:爆炸示例2:移动示例3:加速

如何解决您何时在Unity中乘以Time.deltaTime? 示例1:爆炸示例2:移动示例3:加速

关于何时应该或不应该将数量乘以Time.deltaTime,似乎存在很多令人困惑/矛盾的建议。所以我想知道,与Unity物理系统有关,何时应该乘以Time.deltaTime

我了解到Time.deltaTime用于使某些动作独立于帧率,但是在某些情况下,不清楚动作是否独立于帧率。例如:

  • 在FixedUpdate中进行rigidbody.veLocity += acceleration*Time.deltaTime;。由于FixedUpdate以恒定的时间步长运行,因此是否不需要乘以Time.deltaTime
  • 正在做rigidbody.AddForce(force*Time.deltaTime,forceMode);。各种ForceMode效果如何?

我已经看到了针对个别情况的解决方案,但是如果有一个简单的直觉可以解决所有这些情况,那就太好了。

解决方法

直觉

乘以Time.deltaTime可以使瞬时操作以连续(或“平滑”)方式起作用。

瞬时操作将导致一定数量的“跳跃”到另一个值。以下操作是即时

  • Rigidbody.[position|velocity|rotation|angularVelocity] += x;
  • Rigidbody2D.[position|velocity|rotation|angularVelocity] += x;
  • Rigidbody.Add[Force|Torque](x,ForceMode.[Impulse|VelocityChange]);
  • Rigidbody2D.Add[Force|Torque](x,ForceMode2D.Impulse);

以上所有操作都会导致数量立即跳x,而与帧的长度无关。

相反,以下操作是连续

  • Rigidbody.Add[Force|Torque](x,ForceMode.[Force|Acceleration]);
  • Rigidbody2D.Add[Force|Torque](x,ForceMode.Force);
  • Rigidbody.velocity = x;(从Rigidbody.position的角度来看是连续的。即,设置速度不会使Rigidbody.position突然跳到新值)

以上所有操作都在框架的整个过程中应用(至少在概念上会发生这种情况;物理系统在内部执行的操作超出了此答案的范围)。为了说明这一点,Rigidbody.AddForce(1,ForceMode.Force)将在整个帧中向对象施加1牛顿的力;位置或速度不会突然跳动。

那么您何时乘以Time.deltaTime

如果您使用的是连续操作,则几乎应该乘以Time.deltaTime。但是,如果您使用的是即时操作,答案取决于是否以连续方式使用该操作。

示例1:爆炸

void Explode() {
    rigidbody.velocity += explosionAcceleration;
}

在这里您不应该乘以Time.deltaTime,因为Explode()仅被调用一次。它无意应用于一系列框架。

示例2:移动

void Update() {
    rigidbody.position += velocity * Time.deltaTime;
}

在这里,您必须乘以Time.deltaTime,因为该对象应该随时间连续移动,并且您还使用了瞬时操作。请注意,可以用连续运算代替,并不需要乘以Time.deltaTime

void Update() {
    rigidbody.velocity = velocity;
}

尽管这并不完全等同于原始值,因为它忽略了rigidbody.velocity的先前值。

示例3:加速

void Update() {
    rigidbody.AddForce(acceleration*Time.deltaTime,ForceMode.VelocityChange);
}

在这里您应该乘以Time.deltaTime,因为您希望速度以一致的速率逐帧增加。请注意,这完全等同于:

void Update() {
    rigidbody.AddForce(acceleration,ForceMode.Acceleration);
}

此代码在整个帧过程中应用加速度。 (在我看来,这段代码也更清晰,更易于理解。

FixedUpdate呢?

进入FixedUpdate不会影响上述任何建议。是的,理论上您可以避免永远不乘以Time.deltaTime,因为帧之间的时间始终是相同的。但是,那么您所有的单位都必须取决于固定的帧频。因此,例如,如果您想以每秒1 m/s帧的速度60移动,则必须在每帧的位置添加1/60=.01666。然后想象一下,如果您更改固定的时间步长会发生什么。您必须更改一些常量才能容纳。

FixedUpdate中执行代码不会突然使该代码独立于帧速率。您仍然必须采取与Update中相同的预防措施。

请注意,您无需在Time.deltaTime内用Time.fixedDeltaTime替换FixedUpdate,因为Unity已经进行了这种替换。

结论

如果要使瞬时操作在一系列帧上平滑动作,请仅乘以Time.deltaTime

很多时候,您可以通过使用连续操作来避免使用Time.deltaTime,而连续操作通常更直观(请参见示例2和3)。但这当然取决于上下文。

,

考虑这一点的一种简单方法是确定:

对象的变换是否被直接操纵?

当对象直接通过其transform.positiontransform.rotation组件移动时,应该在Update()中进行变换的操作,该变换在每个绘制的帧中运行一次。开发人员应该在更新/帧速率介于零和游戏最大帧速率之间变化的情况下构建游戏。完成此操作的方法是将当前和上一帧之间的时间计入每个更新/帧的运动(步骤)中。

因此,对transform.positiontransform.rotation的操纵应该放入Time.deltaTime中,并且应该在Update()内进行。

物体是在用物理操纵吗?

在这种情况下,应通过在Rigidbody.AddForce()中调用Rigidbody.AddTorque()FixedUpdate()来施加力和扭矩。 FixedUpdate()可以以固定/保证的速率发生,Unity默认为每秒50次(可以在游戏项目的Physics设置中进行调整)。

为了使事情复杂一点,当用AddForce()(默认)或AddTorque()调用ForceMode.ForceForceMode.Acceleration时,为forcetorque参数将被解释为一整秒的数量,因此这些函数将在一个固定的时间步长(即x 0.02s,默认Unity Physics)下调整值(力/扭矩或加速度/角加速度)固定更新率。)

如果您对ForceMode.ImpulseForceMode.VelocityChange感到好奇,它们会将forcetorque解释为该固定时间步长内要应用的金额(即值不会根据时间进行调整。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。