C# 在x秒内将旋转从0加速到x角(单位为)

C# 在x秒内将旋转从0加速到x角(单位为),c#,unity3d,math,C#,Unity3d,Math,这更像是一个数学问题,而不是一个编码问题。例如,当速度以恒定值加速时,我希望在1秒内达到90的旋转角度。我的当前版本需要1.4秒才能达到所需的旋转角度,并且应该在1秒内达到。我相信这是因为它目前在1秒内加速到90的速度,而不是90的旋转角度。由于我的数学不是很好,我不知道我需要如何调整加速度计算。我找不到任何解决办法 注意:我需要手动调整旋转角度,我无法使用任何现有函数,例如transform.Rotate(),因为在我的完整版本中,旋转方向可以随时更改,并且旋转也有减速值 这是一个非常简化的版

这更像是一个数学问题,而不是一个编码问题。例如,当速度以恒定值加速时,我希望在1秒内达到90的旋转角度。我的当前版本需要1.4秒才能达到所需的旋转角度,并且应该在1秒内达到。我相信这是因为它目前在1秒内加速到90的速度,而不是90的旋转角度。由于我的数学不是很好,我不知道我需要如何调整加速度计算。我找不到任何解决办法

注意:我需要手动调整旋转角度,我无法使用任何现有函数,例如transform.Rotate(),因为在我的完整版本中,旋转方向可以随时更改,并且旋转也有减速值

这是一个非常简化的版本(它只将z轴旋转到一个方向,并在开始时运行一次):

提前感谢任何能提供帮助的人

编辑:修改代码以提高效率。我不能使用RotateTowards(),因为在我的完整代码中,我需要钳制targetAngle和负targetAngle之间的旋转。希望这段代码更高效,性能更友好。但我仍然没有找到解决我原来的数学相关问题的方法,这就是这个问题的全部要点

private float accelerationInSeconds = 1;
private float targetAngle = 90f;

private float speed = 0;
private float angle = 0;
private float axis = 1;
private bool rotate = true;
private float acceleration;

void Start() {
    // Calculate acceleration (this calculation should be changed)
    acceleration = targetAngle / accelerationInSeconds;
}

void Update() {
    if (rotate) {
        // Accelerate
        speed += axis * (acceleration * Time.deltaTime);

        // Calculate next rotation position
        angle += speed * Time.deltaTime;

        // Check if rotation has gone over the target angle
        if (angle >= targetAngle) {
            angle = targetAngle;
            speed = 0;
            rotate = false;
        }

        // Rotate object
        transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    }
}

多亏了StackExchange中的数学部分,我终于找到了答案

因此,简单的答案是:


加速度=2*目标角度/数学功率(加速度秒,2)

正如我在使用。协同程序类似于临时的
Update
方法,通常比直接在
Update
中进行操作更容易控制和维护

// Flag to avoid concurrent routines
private bool isRotating;

public void Rotate(float targetAngle, float duration)
{
    if(! isRotating) StartCoroutine (RotateRoutine(targetAngle, duration));
}

private IEnumerator RotateRoutine (float targetAngle, float duration)
{
    // Just to be sure
    if(isRotating) yield break;

    // block concurrent routines
    isRotating = true;

    // Pre-calculate the start and end rotation
    var start = transform.rotation;
    var end = Quaternion.Euler(0, 0, targetAngle);

    var timePassed = 0f;
    while(timePassed < duration)
    {
        // This value will grow linear from 0 to 1 in exactly "duration" seconds
        var x = timePassed / duration;

        // TODO!
        var y = MAGIC;

        // Interpolate between the start and end rotation using given factor "y"
        transform.rotation = Quaternion.Lerp(start, end, y);


        // "pause" the routine here, render this frame
        // and continue from here in the next frame
        yield return null;

        // Increase by the time passed since last frame
        timePassed += Time.deltaTime;
    }

    // To be sure to end with clean values
    transform.rotation = end;

    // Allow next routine
    isRotating = false;
}
我们从您的代码中进一步了解到,
速度
始终从
0
->
b=0
开始。最后一步非常简单:

我们必须填写什么值才能使
y
0
变为
1
,同时
x
0
变为
1

 1 = a * 1 * 1 + 0;
=>
a=1

因此,在你的情况下,它是简单的

 var y = x * x;
  • 如果你也想要放松,你也可以简单地使用它,它会自动添加放松和放松

     var y = Mathf.SmoothStep(0, 1, x);
    
  • 为了更容易控制,您可以使用一个控制面板,并根据您的需要精确调整运动曲线

    曲线编辑器已经提供了一些预设曲线,例如线性曲线、对数曲线、指数曲线和缓进/缓出曲线,从0增长到1

    然后使用获取例程中给定输入时间(
    x
    )的值(
    y


  • 我建议将旋转保持为四元数。也就是说,找到你的目标旋转(以某种方式),并使用quaternion.lerp对该旋转进行插值。通常,不要在Euler中使用连续计算(有关详细信息,请参阅)!相反,我宁愿计算一次目标旋转:
    var targetRotation=Quaternion.Euler(0,0,targetAngle)然后使用获取旋转步骤,例如
    var newRotation=Quaternion.rotatetowwards(transform.rotation,targetotation,speed*Time.deltaTime)
    @derHugo谢谢你的建议,如果我能让它像我希望的那样工作,我会修改我的代码,改为使用RotateTowards()。但这并没有解决我最初的问题,这是一个与数学有关的问题,用于根据目标旋转角度计算加速度值。@derHugo我似乎不能使用rotateTowwards(),因为如果我的目标角度是160,然后我想移动到另一个方向,角度是-160,它不是从160到0,也不是从0到-160。它一直朝着同一方向移动(161162…)。我需要将角度锁定在160到-160之间。我想我需要检查它是否可以用四元数实现。就像乔纳斯建议的那样,Lerp。你仍然可以使用
    旋转方向
    ,听起来好像你的数学算错了……对于二次值,直接使用
    AccelerationSeconds*AccelerationSeconds
    而不是
    Mathf.Pow
    ;)会稍微有效一些嗯,我一定要试试这个,看看我是否也能让它减速。在我的完整版本中,我实际上使用了一个协程,我只是认为在这个示例中使用更新方法会更具可读性。如果您的实际代码是一个协程,请给我们一个协程;)我们知道怎么读^^
     var y = x * x;
    
     var y = Mathf.SmoothStep(0, 1, x);
    
     [SerializeField] private AnimationCurve curve;
    
     var y = curve.Evaluate(x);