Mathf.Lerp 未达到最终值
Mathf.Lerp misses final value
我正在使用 Mathf.Lerp 制作圆形进度条的动画。
进度条是一个有 属性 名为 "FillAmount" 的图像:
0 means not filled
1 means filled
与填充 属性 "Radial 360" 一起,它的作用有点像时钟。
由于某种原因,执行 Lerp 函数后的最终值丢失了,我不知道如何改进函数以得到预期结果。
我的圆形进度条是一个3/4环,这就是为什么我将uFrom和uTo(介于0和100之间)乘以0.75。
这是我的代码:
public IEnumerator AnimateHealthChange(int uFrom, int uTo)
{
float fFade = 0.25f;
float fOld = ((uFrom * 0.75f) / 100);
float fNew = ((uTo * 0.75f) / 100);
Debug.Log("Changing from " + fOld.ToString() + " to " + fNew.ToString());
for (float t = 0.01f; t < fFade; t += Time.deltaTime)
{
ImageHealthRing.fillAmount = Mathf.Lerp(fOld, fNew, Mathf.Min(1, t / fFade));
yield return null;//
}
Debug.Log("Final filling after for-next-statement: " + ImageHealthRing.fillAmount.ToString());
yield return null;
}
例如,当我调用 AnimateHealthChange(0, 100) 时,我得到以下日志输出:
Changing from 0 to 0.75
Final filling after for-next-statement: 0.6807814
我预计最终结果是 0.75,而不是 0.6807814。
有没有人看出我的错误,或者我是否错误地使用了 Lerp?
你的 for
循环是个问题,因为它不能保证:
for (float t = 0.01f; t < fFade; t += Time.deltaTime)
Time.deltaTime
可以是任何数字(取决于游戏的性能和帧率)并且您使用的是 t < fFade
而不是 t <= fFade
所以即使您这样做,机会,以 t == fFade
结束,(这是它应该结束以正确填充的值)它将跳过循环的迭代。
这里最简单的解决方案是在强制 fillAmount
为正确值的循环之后添加一个额外的语句:
...
yield return null;//
}
ImageHealthRing.fillAmount = fNew;
这样你的循环仍在处理动画,当你的函数结束时,你保证它以正确的值结束。
可能在 for
循环中。看看它是如何执行的:
最初,t
设置为 0.01
。 Healthbar改变了一点。
然后,t
增加 Time.deltaTime
。比如刚好是0.17
。现在 t
等于 0.18
并且循环继续到 运行.
但是当另一个增量 t
变得大于或等于 fFade
时,程序将退出循环 而不会更改健康栏 。在我的示例中,最后处理的数字将是 0.18
.
如何解决这个问题?您应该在循环后立即将 fillAmount
设置为 fNew。
而不是使用 for
循环。使用 while
循环。所以你的代码 运行s 直到达到所需的值。
现在你退出是基于时间而不是基于期望的结果。
您仍然可以 运行 每帧并按时间设置动画,但您不应根据 运行 的时间停止代码。
此外,当您退出循环时,它也可能值 clamping/setting 值。将其设置为您在函数中输入的参数(或 fNew
在您的情况下)。
我正在使用 Mathf.Lerp 制作圆形进度条的动画。
进度条是一个有 属性 名为 "FillAmount" 的图像:
0 means not filled
1 means filled
与填充 属性 "Radial 360" 一起,它的作用有点像时钟。
由于某种原因,执行 Lerp 函数后的最终值丢失了,我不知道如何改进函数以得到预期结果。
我的圆形进度条是一个3/4环,这就是为什么我将uFrom和uTo(介于0和100之间)乘以0.75。
这是我的代码:
public IEnumerator AnimateHealthChange(int uFrom, int uTo)
{
float fFade = 0.25f;
float fOld = ((uFrom * 0.75f) / 100);
float fNew = ((uTo * 0.75f) / 100);
Debug.Log("Changing from " + fOld.ToString() + " to " + fNew.ToString());
for (float t = 0.01f; t < fFade; t += Time.deltaTime)
{
ImageHealthRing.fillAmount = Mathf.Lerp(fOld, fNew, Mathf.Min(1, t / fFade));
yield return null;//
}
Debug.Log("Final filling after for-next-statement: " + ImageHealthRing.fillAmount.ToString());
yield return null;
}
例如,当我调用 AnimateHealthChange(0, 100) 时,我得到以下日志输出:
Changing from 0 to 0.75
Final filling after for-next-statement: 0.6807814
我预计最终结果是 0.75,而不是 0.6807814。
有没有人看出我的错误,或者我是否错误地使用了 Lerp?
你的 for
循环是个问题,因为它不能保证:
for (float t = 0.01f; t < fFade; t += Time.deltaTime)
Time.deltaTime
可以是任何数字(取决于游戏的性能和帧率)并且您使用的是 t < fFade
而不是 t <= fFade
所以即使您这样做,机会,以 t == fFade
结束,(这是它应该结束以正确填充的值)它将跳过循环的迭代。
这里最简单的解决方案是在强制 fillAmount
为正确值的循环之后添加一个额外的语句:
...
yield return null;//
}
ImageHealthRing.fillAmount = fNew;
这样你的循环仍在处理动画,当你的函数结束时,你保证它以正确的值结束。
可能在 for
循环中。看看它是如何执行的:
最初,t
设置为 0.01
。 Healthbar改变了一点。
然后,t
增加 Time.deltaTime
。比如刚好是0.17
。现在 t
等于 0.18
并且循环继续到 运行.
但是当另一个增量 t
变得大于或等于 fFade
时,程序将退出循环 而不会更改健康栏 。在我的示例中,最后处理的数字将是 0.18
.
如何解决这个问题?您应该在循环后立即将 fillAmount
设置为 fNew。
而不是使用 for
循环。使用 while
循环。所以你的代码 运行s 直到达到所需的值。
现在你退出是基于时间而不是基于期望的结果。 您仍然可以 运行 每帧并按时间设置动画,但您不应根据 运行 的时间停止代码。
此外,当您退出循环时,它也可能值 clamping/setting 值。将其设置为您在函数中输入的参数(或 fNew
在您的情况下)。