C# 在x秒内将旋转从0加速到x角(单位为)
这更像是一个数学问题,而不是一个编码问题。例如,当速度以恒定值加速时,我希望在1秒内达到90的旋转角度。我的当前版本需要1.4秒才能达到所需的旋转角度,并且应该在1秒内达到。我相信这是因为它目前在1秒内加速到90的速度,而不是90的旋转角度。由于我的数学不是很好,我不知道我需要如何调整加速度计算。我找不到任何解决办法 注意:我需要手动调整旋转角度,我无法使用任何现有函数,例如transform.Rotate(),因为在我的完整版本中,旋转方向可以随时更改,并且旋转也有减速值 这是一个非常简化的版本(它只将z轴旋转到一个方向,并在开始时运行一次): 提前感谢任何能提供帮助的人 编辑:修改代码以提高效率。我不能使用RotateTowards(),因为在我的完整代码中,我需要钳制targetAngle和负targetAngle之间的旋转。希望这段代码更高效,性能更友好。但我仍然没有找到解决我原来的数学相关问题的方法,这就是这个问题的全部要点C# 在x秒内将旋转从0加速到x角(单位为),c#,unity3d,math,C#,Unity3d,Math,这更像是一个数学问题,而不是一个编码问题。例如,当速度以恒定值加速时,我希望在1秒内达到90的旋转角度。我的当前版本需要1.4秒才能达到所需的旋转角度,并且应该在1秒内达到。我相信这是因为它目前在1秒内加速到90的速度,而不是90的旋转角度。由于我的数学不是很好,我不知道我需要如何调整加速度计算。我找不到任何解决办法 注意:我需要手动调整旋转角度,我无法使用任何现有函数,例如transform.Rotate(),因为在我的完整版本中,旋转方向可以随时更改,并且旋转也有减速值 这是一个非常简化的版
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);