Unity轮旋转算法/公式

问题描述 投票:0回答:1

我目前遇到问题,需要一些帮助来解决。

在我的场景中,我有一个上面放着剧本的轮子。在脚本中,轮子最初以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内部已经定义了“变换”(我在问题描述中提到,这是附着在我的车轮上的脚本)。

c# unity3d
1个回答
0
投票

这里有一种方法可以使它精确地落在所需的旋转上,并使用采样来估计使机芯与起始速度匹配所需的持续时间。

注释说明:

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.