我目前遇到问题,需要一些帮助来解决。
在我的场景中,我有一个上面放着剧本的轮子。在脚本中,轮子最初以initialSpeed度/秒旋转,并且最初已经旋转了initialRotation度。
脚本还具有一个AnimationCurve字段,它描述了车轮的减速度。
我如何使用AnimationCurve来降低轮子的速度,以便在duration秒后它完全停止在finalRotation度?
我的代码看起来像这样:
public float finalRotation = 270f;
public AnimationCurve animationCurve = null;
private float initialSpeed = 20f;
private float initialRotation = 20f;
private float elapsedTime = 0f;
private float duration = 5s;
void Start()
{
trasnform.rotation = Quaternion.Euler(new Vector3(0, 0, initialRotation));
}
void Update()
{
if (elapsedTime >= duration)
return;
elapsedTime += Time.deltaTime;
float v = animationCurve.Evaluate(elapsedTime / duration);
//Here is where I don't know how to proceed:
//How do use 'v' to slow down 'speed' so that the wheel fully stops at
//'finalRotation' after 'duration' seconds?
//I have tried this: speed = Mathf.Lerp(initialSpeed, 0, v);
//But this does not guarantees that the wheel will fully stop at "finalRotation". It only
//guarantees that the wheel will fully stop after 'duration'.
transform.Rotate(Vector3.forward, speed);
}
[我已经看过this问题,但是我无法使其正常工作(假设我正确理解了所解释的内容)。
任何帮助将不胜感激。谢谢。
编辑
我定义了“持续时间”。我没有定义“变换”,因为在MonoBehaviour内部已经定义了“变换”(我在问题描述中提到,这是附着在我的车轮上的脚本)。
这里有一种方法可以使它精确地落在所需的旋转上,并使用采样来估计使机芯与起始速度匹配所需的持续时间。
注释说明:
private float finalRotation = 270f;
// define duration, initialize it to 0 for config in Update
private float duration = 0f;
// Have the curve start at 1 and decrease to 0.
// it must immediately decrease starting at t=0 for this technique to work
public AnimationCurve animationCurve = null;
private initialSpeed = 20f;
// Keep track of what the animation curve was at previously
private float previousV = 1f;
private float initialRotation = 20f;
private float elapsedTime = 0f;
// how much will be needed to rotate over the whole duration
private float wholeRotation = 250f;
void Start()
{
// transform, not trasnform
transform.rotation = Quaternion.Euler(new Vector3(0, 0, initialRotation));
}
// create method to set and calculate values
// This should be called by whatever sets finalRotation/duration
void Configure(float finalRotation, float initalSpeed)
{
this.finalRotation = finalRotation;
this.initalSpeed = initialSpeed;
wholeRotation = finalRotation - initialRotation;
// binary sample from the curve to find a
// close to the speed we will see on the first frame
float estimatedRotFirstFrame = Time.fixedDeltaTime * initialSpeed;
float estimatedVFirstFrame = 1f - estimatedRotFirstFrame/wholeRotation;
//sample until the estimated speed is lower than threshold or limit of samples is hit
// larger threshold speeds up sampling but may result on a noticible jitter
// on first frame
float sampleSpeedThreshold = 5f;
// smaller sample count limit speeds u p sampling but may produce the jitter
int maxSampleCount = 10;
float sampledT = 0.5f;
float sampleJump = 0.25f;
for (int i=0 ; i<maxSampleCount ; i++)
{
float sampledV = animationCurve.Evaluate(sampledT);
if (Mathf.Abs(sampledV-estimatedVFirstFrame) < sampleSpeedThreshold)
break;
// if sampledV is too small, try a smaller t, otherwise try a larger t
if (sampledV < estimatedVFirstFrame)
sampledT -= sampleJump;
else
sampledT += sampleJump;
sampleJump *= 0.5f;
}
// calculate duration such that sampledT = estimatedDeltaTime/duration
duration = sampledT * estimatedDeltaTime;
}
// use FixedUpdate to make estimation in Configure more accurate.
void FixedUpdate()
{
if (elapsedTime >= duration)
return;
elapsedTime = Mathf.Min(duration, elapsedTime + Time.deltaTime);
float v = animationCurve.Evaluate(elapsedTime / duration);
// how much closer did the curve get to 0 this frame?
float vDiff = previousV - v;
// how much rotation does that translate to?
float rotThisFrame = vDiff * wholeRotation;
transform.Rotate(Vector3.forward, rotThisFrame);
previousV = v;
}