C# 恒加速度负加速度运动

C# 恒加速度负加速度运动,c#,unity3d,math,game-physics,C#,Unity3d,Math,Game Physics,我认为运动过程是统一的 我想做一个将对象移动到指定位置的过程,但正如标题所示,我不仅希望对象移动,而且希望对象在速度衰减的情况下达到预定距离 如果加速度为负,我无法很好地处理它。 具体来说,当初始速度为10时,我想达到一个不回头的位置,如gif所示 我用恒定加速度运动公式中的“s=v0t+1/2at^2”来求加速度“a”,但这似乎不够 如果你能帮助我,我将不胜感激 public class Test : MonoBehaviour { public float t; public

我认为运动过程是统一的

我想做一个将对象移动到指定位置的过程,但正如标题所示,我不仅希望对象移动,而且希望对象在速度衰减的情况下达到预定距离

如果加速度为负,我无法很好地处理它。 具体来说,当初始速度为10时,我想达到一个不回头的位置,如gif所示

我用恒定加速度运动公式中的“s=v0t+1/2at^2”来求加速度“a”,但这似乎不够

如果你能帮助我,我将不胜感激

public class Test : MonoBehaviour
{
    public float t;
    public float initSpd;
    public Transform t1, t2;

    IEnumerator Start()
    {
        var p = t1.position;
        while (true) {
            t1.position = p;
            var v0t = initSpd * t;
            var distance = Vector2.Distance(t1.position, t2.position);
            var direction = (t2.position - t1.position).normalized;
            var a = (2 * (distance - v0t)) / (t * t);
            var v = initSpd;
            // update
            yield return Utils.Coroutine.WhileForSeconds(t, () =>
            {
                t1.Translate(direction * v * Time.deltaTime);
                v += a * Time.deltaTime;
            });
        }
    }
}
跨度=3,初始速度=0 跨度=3,初始速度=3 跨度=3,初始速度=10


您计算
a
的数学是正确的,但您提出的问题无法让您满意地解决

正如你所说的,在恒定加速度下,位置是时间的二次函数,所以用

s = b t^2 + c t + d
对于某些常数
b、c、d
d
的值已由初始位置固定。
c
的值已经由初始速度固定。剩下的自由参数只有一个,当您求解
s(finalTime)=goalPosition
时,您无法控制生成的抛物线是否超出目标

您可以增加多项式次数,但总会有一些初始速度过大并导致超调

本质上,你有一个最优控制/轨迹优化问题,比如

  minimize: integral(acceleration(t)^2) from t = 0 to T
subject to: x(0) given
            v(0) given
            x(T) given
            x(t) <= x(T) for all t in [0, T] (assuming x(0) < x(T))
其中,
kp
kd
是手动调整的正常数,并且在每一帧中重新计算该表达式。您可以调整
kp
kd
以最小化典型场景中的超调


或者,你也可以像大多数游戏一样,让速度瞬间改变:)

我发现通过两步改变速度可以达到理想的效果

    IEnumerator Start()
    {
        var p = t1.position;
        while (true)
        {
            t1.position = p;
            var direction = (t2.position - t1.position).normalized;
            var distance = Vector2.Distance(t1.position, t2.position);

            var v0 = initSpd;
            var M = distance;
            var T = duration;
            var tm = M / v0;
            var vm = v0 / T * tm;
            var accel1 = (vm - v0) / (tm - 0);
            var accel2 = (0 - vm) / (T - tm);
            Debug.Log($"vo={v0}, M={M}, T={T}, tm={tm}, vm={vm}, accel1={accel1}, accel2={accel2}");
            var v = initSpd;
            var stime = Time.time;
            var hist = 0f;
            // update
            yield return Utils.Coroutine.WhileForSeconds(T, () =>
            {
                t1.Translate(direction * v * Time.deltaTime);
                hist += v * Time.deltaTime;
                if (Time.time - stime <= tm)
                    v += accel1 * Time.deltaTime;
                else
                    v += accel2 * Time.deltaTime;
            });
            Debug.Log($"elapsed={Time.time - stime}, moved distance={hist}, v={v}");
        }
    }
IEnumerator Start()
{
var p=t1.1位置;
while(true)
{
t1.位置=p;
var方向=(t2.position-t1.position)。归一化;
变量距离=矢量2.距离(t1.位置,t2.位置);
var v0=初始SPD;
var M=距离;
var T=持续时间;
var tm=M/v0;
var vm=v0/T*tm;
var accel1=(vm-v0)/(tm-0);
var-accel2=(0-vm)/(T-tm);
Log($“vo={v0},M={M},T={T},tm={tm},vm={vm},accel1={accel1},accel2={accel2}”);
var v=初始SPD;
var stime=Time.Time;
var hist=0f;
//更新
收益率收益率效用协程时间(T,()=>
{
t1.平移(方向*v*时间增量);
hist+=v*Time.deltaTime;

如果(Time.Time-谢谢你的详细回答。我认为这对到达的时间很重要,两点之间的距离也很重要。当球向前移动并从前进方向获得垂直力时,它会使球弯曲。然后,我希望弯曲的球停在移动量为我最初计算的f距离。我没有考虑使用像贝塞尔曲线这样的线性插值,因为不管距离有多远,它最终都会到达终点。我更新了图像,红线就是距离值。我想如果我能得到“a”我想,只是需要在每一帧改变方向。我仍然不完全理解你的答案。我必须进一步研究。我不确定我是否理解你的问题陈述。什么是“来自前进方向的垂直力”?“我希望弯曲的球停在我最初计算的移动距离的位置"听起来你想计算一条从a点到b点的路径,弧长正好是L。如果是这样,为什么不使用圆弧呢?试着用数学而不是文字来表述你的问题。这会帮助这里的人们,但更重要的是,这将是一个有用的步骤,帮助你自己找到解决方案。它是垂直的而不是垂直的吗l?举例来说,它是相对于上的右或左。我只是想找到适当的负加速度。这可能会混淆我提到的曲线的信息,对不起。球可能会有螺旋运动,而不是盘旋,这很难预先计算轨迹,所以我想知道每帧的前进量。a有人教我一个答案,用两个恒定的加速度运动,效果很好。
    IEnumerator Start()
    {
        var p = t1.position;
        while (true)
        {
            t1.position = p;
            var direction = (t2.position - t1.position).normalized;
            var distance = Vector2.Distance(t1.position, t2.position);

            var v0 = initSpd;
            var M = distance;
            var T = duration;
            var tm = M / v0;
            var vm = v0 / T * tm;
            var accel1 = (vm - v0) / (tm - 0);
            var accel2 = (0 - vm) / (T - tm);
            Debug.Log($"vo={v0}, M={M}, T={T}, tm={tm}, vm={vm}, accel1={accel1}, accel2={accel2}");
            var v = initSpd;
            var stime = Time.time;
            var hist = 0f;
            // update
            yield return Utils.Coroutine.WhileForSeconds(T, () =>
            {
                t1.Translate(direction * v * Time.deltaTime);
                hist += v * Time.deltaTime;
                if (Time.time - stime <= tm)
                    v += accel1 * Time.deltaTime;
                else
                    v += accel2 * Time.deltaTime;
            });
            Debug.Log($"elapsed={Time.time - stime}, moved distance={hist}, v={v}");
        }
    }