【问题标题】:Unity3d Rotate around a specific point over timeUnity3d随时间围绕特定点旋转
【发布时间】:2016-09-09 18:42:26
【问题描述】:

我正在编写一个函数,它会在一段时间内缓慢旋转 90 度。到目前为止一切正常,我只需要弄清楚如何让它围绕一个点旋转而不是围绕变换中心旋转。

protected bool _isRotating = false;
public IEnumerator RotateWithEasing(GameHelper.Axis axis, Vector3 isolatedAxisPoint, float inTime)
{
    if(_isRotating)
    {
        yield break;
    }

    _isRotating = true;

    var degrees = this.GetDegreesFromAxis(axis);

    Quaternion fromAngle = transform.rotation;
    Quaternion toAngle = Quaternion.Euler(transform.eulerAngles + degrees);
    for (float t = 0f; t < 1f; t += Time.deltaTime / inTime)
    {
        transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
        yield return null;
    }

    _isRotating = false;
}

谁能帮我指出正确的方向,我该如何修改它以使其围绕指定的isolatedAxisPoint 旋转?

【问题讨论】:

  • 围绕该点画一个圆圈并沿该圆圈移动?
  • 这听起来可行,我是 Unity 新手,我会为此使用 Quaternion.LerpQuaternion.Slerp
  • 你可能会很好地查看rotate around,结合speed * deltatime,你可以增加轻松甚至时间
  • 我看看我今天晚些时候是否有时间提供更详尽的答案;)

标签: c# unity3d interpolation


【解决方案1】:

这是一个实际的 Unity 补间示例,恰好在文本编辑器的另一个窗口中显示!

如果您想旋转某些东西,只需在 IEnumerator 中循环使用 deltaTime,然后调整 eulerAngles 或调用 Rotate 即可。 (永远不要在 Unity 中出于任何原因使用四元数。)在这个例子中,我只调用 Rotate。

这是 Unity 中非常基本的模式

这是 Unity 中补间的基本模式。您将在 Unity 中执行此操作 1000 次!

  1. 计算结束时间
  2. 执行 while 循环,直到达到该时间
  3. 每帧、幻灯片(或其他)按适当的分数。

请注意,你当然

 yield return null;

在循环内部,意思是“等到下一帧”。

(请注意,与任何补间一样,最好在最后强制设置最终值,这样您就知道它是完美的。请注意,在这个示例中,我只是在最后设置了 eulerAngles当循环结束时。)

private IEnumerator _roll( Vector3 delta )
    {
    rollBegins.Invoke();
    
    Vector3 begin = transform.eulerAngles;
    
    float rollSecs = 2f; // speed of the roll
    
    float startTime = Time.time;
    float endTime = startTime+rollSecs;

    while (Time.time < endTime)
        {
        Vector3 d = delta * ( Time.deltaTime / rollSecs );
        transform.Rotate(d, Space.World );
        yield return null;
        }
    
    transform.eulerAngles = .. perfectly correct end values;
    
    busy = false;
    
    rollComplete.Invoke();
    }

{注意,在实际代码示例中,“delta”被理解为仅在一个轴上;这个不用担心,这只是补间使用协程的一个例子。}

注意 - 当然有“两种方式”进入循环。你可以计算出少量你应该将它移动到那一帧。或者,您可以只计算当时的新位置。由你决定。许多程序员认为后者更合乎逻辑,如果是这样,那就这样做吧。还要注意,您可以执行 while 循环,直到某个时间过去,或者,您可以执行 while 循环,直到您到达目的地! (对浮动等式要非常小心。)选择权在您手中。

请注意,您经常使用 Lerp 甚至更好的 SmoothStep 与此类补间。它在 Unity 中无处不在。一旦掌握了基本模式,就可以尝试一下。

请注意,在我的示例中,代码使用 UnityEvent 来标记动画的开始和结束。这是非常常见的。毕竟,通常情况下,一旦某个动作完成,您就必须继续做其他事情。另一个很好的例子是,当某些东西正在制作动画时,用户被阻止说转向或您的游戏中的任何情况。

UnityEvent 的精彩介绍https://stackoverflow.com/a/36249404/294884 请投票 :)


记录在案。

在 Unity 中补间。

在 Unity 中进行补间的真正高级方法是补间:

Basic Tweeng code base appears in this question.

这需要一段时间才能掌握,但它非常强大。令人难以置信的是,tweeng 扩展只有几行代码。

【讨论】:

  • 谢谢,这就是我要找的东西,我回家后会测试一下,只是想知道 rollComplete 是一个内置的委托吗?还是某种事件系统阻止它被多次调用,直到它完成?
  • 谢谢,关于设置最终欧拉角的提示,我注意到在我的角度之前我们稍微偏离了一点,可能是因为舍入浮点小数错误
  • 嗨,Johnny,这正是 Unity 中的正确模式。它就像最基本的东西,有时感觉就像你在 Unity 中编程过的所有东西,呵呵! “rollComplete”是一个“unityEvent”,我已经包含了完整的解释。像这样的协程补间是使用 UnityEvent 的一个很好的例子。
  • 对!很好地发现。必须“强制设定”最终的正确目的地。尤其是角度。
  • 我还没回家,但我要把它标记为已完成,因为我可以在脑海中逻辑地编译代码,这很有意义
【解决方案2】:

使用类似的东西,假设在 1 秒内旋转 90 度:

int rotatedDegrees; 
int desiredRotation = 90;
float startTime = null;
float rotationDuration = 1f;

public void rotate()
{    
  if(startTime == null)
    startTime = time.Now;

  while((time.Now - starttime) / rotationDuration > (((float) rotatedDegrees) / desiredRotation))
  {
    transform.RotateAround (isolatedAxisPoint, Vector3.up, 1);
    rotatedDegrees++;
  }
}

在 startTime + 0 时,它旋转了 0 度。

现在假设 time.Now 类似于 startTime + 0.1 (+100ms)。然后 time.Now - startTime 为 0.1,旋转直到 (rotatedDegrees / desiredRotation) 为 0.1,即 9,即总旋转的 1/10。

【讨论】:

  • hm 很有趣,但是 time.Now 与 rotateDegrees / desiredRotation 有什么关系,time.now 不是一直在增加,还是不应该在协程中这样变量就不会被修改?
  • @johnny5 已编辑,time.Now - startTime = 自轮换开始以来的时间。
  • 谢谢,这看起来很可靠我回家后会测试它。如果有效,我会将其标记为完成
  • 我不知道这段代码是什么。约翰尼,就像你说的那样使用 IEnumerator,但忘了四元数。只需根据您的喜好使用 Rotate 或 eulerAngles。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-01
  • 2016-11-20
相关资源
最近更新 更多