it-swarm.com.de

Beschleunigung in der Einheit

Ich versuche, Beschleunigung und Verzögerung in Unity nachzuahmen.

Ich habe Code geschrieben, um eine Spur in Unity zu generieren und ein Objekt zeitabhängig an einer bestimmten Stelle der Spur zu platzieren. Das Ergebnis sieht ein bisschen so aus.

 Cube mid way through Catmull-Rom Spline

Mein aktuelles Problem ist, dass jeder Abschnitt des Splines eine andere Länge hat und der Würfel sich mit unterschiedlicher, aber gleichmäßiger Geschwindigkeit über jeden Abschnitt bewegt. Dies führt zu plötzlichen Sprüngen in der Geschwindigkeitsänderung des Würfels beim Übergang zwischen Abschnitten.

Um dieses Problem zu beheben, habe ich versucht, Robert Penners Beschleunigungsgleichungen in der GetTime(Vector3 p0, Vector3 p1, float alpha)-Methode zu verwenden. Dies hat zwar etwas geholfen, war aber nicht ausreichend. Es gab immer noch Geschwindigkeitssprünge zwischen den Übergängen.

Hat jemand eine Idee, wie ich die Position des Würfels dynamisch verringern könnte, damit er aussieht, als würde er beschleunigen und verlangsamen, ohne große Geschwindigkeitssprünge zwischen den Abschnitten der Strecke?


Ich habe ein Skript geschrieben, das eine einfache Implementierung meines Codes zeigt. Es kann an jedes Spielobjekt angehängt werden. Um zu sehen, was passiert, wenn der Code ausgeführt wird, können Sie etwas an einen Würfel oder eine Kugel anhängen.

using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class InterpolationExample : MonoBehaviour {
    [Header("Time")]
    [SerializeField]
    private float currentTime;
    private float lastTime = 0;
    [SerializeField]
    private float timeModifier = 1;
    [SerializeField]
    private bool running = true;
    private bool runningBuffer = true;

    [Header("Track Settings")]
    [SerializeField]
    [Range(0, 1)]
    private float catmullRomAlpha = 0.5f;
    [SerializeField]
    private List<SimpleWayPoint> wayPoints = new List<SimpleWayPoint>
    {
        new SimpleWayPoint() {pos = new Vector3(-4.07f, 0, 6.5f), time = 0},
        new SimpleWayPoint() {pos = new Vector3(-2.13f, 3.18f, 6.39f), time = 1},
        new SimpleWayPoint() {pos = new Vector3(-1.14f, 0, 4.55f), time = 6},
        new SimpleWayPoint() {pos = new Vector3(0.07f, -1.45f, 6.5f), time = 7},
        new SimpleWayPoint() {pos = new Vector3(1.55f, 0, 3.86f), time = 7.2f},
        new SimpleWayPoint() {pos = new Vector3(4.94f, 2.03f, 6.5f), time = 10}
    };

    [Header("Debug")]
    [Header("WayPoints")]
    [SerializeField]
    private bool debugWayPoints = true;
    [SerializeField]
    private WayPointDebugType debugWayPointType = WayPointDebugType.SOLID;
    [SerializeField]
    private float debugWayPointSize = 0.2f;
    [SerializeField]
    private Color debugWayPointColour = Color.green;
    [Header("Track")]
    [SerializeField]
    private bool debugTrack = true;
    [SerializeField]
    [Range(0, 1)]
    private float debugTrackResolution = 0.04f;
    [SerializeField]
    private Color debugTrackColour = Color.red;

    [System.Serializable]
    private class SimpleWayPoint
    {
        public Vector3 pos;
        public float time;
    }

    [System.Serializable]
    private enum WayPointDebugType
    {
        SOLID,
        WIRE
    }

    private void Start()
    {
        wayPoints.Sort((x, y) => x.time.CompareTo(y.time));
        wayPoints.Insert(0, wayPoints[0]);
        wayPoints.Add(wayPoints[wayPoints.Count - 1]);
    }

    private void LateUpdate()
    {
        //This means that if currentTime is paused, then resumed, there is not a big jump in time
        if(runningBuffer != running)
        {
            runningBuffer = running;
            lastTime = Time.time;
        }

        if(running)
        {
            currentTime += (Time.time - lastTime) * timeModifier;
            lastTime = Time.time;
            if(currentTime > wayPoints[wayPoints.Count - 1].time)
            {
                currentTime = 0;
            }
        }
        transform.position = GetPosition(currentTime);
    }

    #region Catmull-Rom Math
    public Vector3 GetPosition(float time)
    {
        //Check if before first waypoint
        if(time <= wayPoints[0].time)
        {
            return wayPoints[0].pos;
        }
        //Check if after last waypoint
        else if(time >= wayPoints[wayPoints.Count - 1].time)
        {
            return wayPoints[wayPoints.Count - 1].pos;
        }

        //Check time boundaries - Find the nearest WayPoint your object has passed
        float minTime = -1;
        float maxTime = -1;
        int minIndex = -1;
        for(int i = 1; i < wayPoints.Count; i++)
        {
            if(time > wayPoints[i - 1].time && time <= wayPoints[i].time)
            {
                maxTime = wayPoints[i].time;
                int index = i - 1;
                minTime = wayPoints[index].time;
                minIndex = index;
            }
        }

        float timeDiff = maxTime - minTime;
        float percentageThroughSegment = 1 - ((maxTime - time) / timeDiff);

        //Define the 4 points required to make a Catmull-Rom spline
        Vector3 p0 = wayPoints[ClampListPos(minIndex - 1)].pos;
        Vector3 p1 = wayPoints[minIndex].pos;
        Vector3 p2 = wayPoints[ClampListPos(minIndex + 1)].pos;
        Vector3 p3 = wayPoints[ClampListPos(minIndex + 2)].pos;

        return GetCatmullRomPosition(percentageThroughSegment, p0, p1, p2, p3, catmullRomAlpha);
    }

    //Prevent Index Out of Array Bounds
    private int ClampListPos(int pos)
    {
        if(pos < 0)
        {
            pos = wayPoints.Count - 1;
        }

        if(pos > wayPoints.Count)
        {
            pos = 1;
        }
        else if(pos > wayPoints.Count - 1)
        {
            pos = 0;
        }

        return pos;
    }

    //Math behind the Catmull-Rom curve. See here for a good explanation of how it works. https://stackoverflow.com/a/23980479/4601149
    private Vector3 GetCatmullRomPosition(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float alpha)
    {
        float dt0 = GetTime(p0, p1, alpha);
        float dt1 = GetTime(p1, p2, alpha);
        float dt2 = GetTime(p2, p3, alpha);

        Vector3 t1 = ((p1 - p0) / dt0) - ((p2 - p0) / (dt0 + dt1)) + ((p2 - p1) / dt1);
        Vector3 t2 = ((p2 - p1) / dt1) - ((p3 - p1) / (dt1 + dt2)) + ((p3 - p2) / dt2);

        t1 *= dt1;
        t2 *= dt1;

        Vector3 c0 = p1;
        Vector3 c1 = t1;
        Vector3 c2 = (3 * p2) - (3 * p1) - (2 * t1) - t2;
        Vector3 c3 = (2 * p1) - (2 * p2) + t1 + t2;
        Vector3 pos = CalculatePosition(t, c0, c1, c2, c3);

        return pos;
    }

    private float GetTime(Vector3 p0, Vector3 p1, float alpha)
    {
        if(p0 == p1)
            return 1;
        return Mathf.Pow((p1 - p0).sqrMagnitude, 0.5f * alpha);
    }

    private Vector3 CalculatePosition(float t, Vector3 c0, Vector3 c1, Vector3 c2, Vector3 c3)
    {
        float t2 = t * t;
        float t3 = t2 * t;
        return c0 + c1 * t + c2 * t2 + c3 * t3;
    }

    //Utility method for drawing the track
    private void DisplayCatmullRomSpline(int pos, float resolution)
    {
        Vector3 p0 = wayPoints[ClampListPos(pos - 1)].pos;
        Vector3 p1 = wayPoints[pos].pos;
        Vector3 p2 = wayPoints[ClampListPos(pos + 1)].pos;
        Vector3 p3 = wayPoints[ClampListPos(pos + 2)].pos;

        Vector3 lastPos = p1;
        int maxLoopCount = Mathf.FloorToInt(1f / resolution);

        for(int i = 1; i <= maxLoopCount; i++)
        {
            float t = i * resolution;
            Vector3 newPos = GetCatmullRomPosition(t, p0, p1, p2, p3, catmullRomAlpha);
            Gizmos.DrawLine(lastPos, newPos);
            lastPos = newPos;
        }
    }
    #endregion

    private void OnDrawGizmos()
    {
        #if UNITY_EDITOR
        if(EditorApplication.isPlaying)
        {
            if(debugWayPoints)
            {
                Gizmos.color = debugWayPointColour;
                foreach(SimpleWayPoint s in wayPoints)
                {
                    if(debugWayPointType == WayPointDebugType.SOLID)
                    {
                        Gizmos.DrawSphere(s.pos, debugWayPointSize);
                    }
                    else if(debugWayPointType == WayPointDebugType.WIRE)
                    {
                        Gizmos.DrawWireSphere(s.pos, debugWayPointSize);
                    }
                }
            }

            if(debugTrack)
            {
                Gizmos.color = debugTrackColour;
                if(wayPoints.Count >= 2)
                {
                    for(int i = 0; i < wayPoints.Count; i++)
                    {
                        if(i == 0 || i == wayPoints.Count - 2 || i == wayPoints.Count - 1)
                        {
                            continue;
                        }

                        DisplayCatmullRomSpline(i, debugTrackResolution);
                    }
                }
            }
        }
        #endif
    }
}
10
Dan

Ok, lass uns etwas math hierauf setzen.

Ich war schon immer für die Wichtigkeit und den Nutzen der Mathematik in gamedev und befürworte diese Frage. Ich gehe zu dieser Antwort zu weit, aber ich denke wirklich, dass Ihre Frage nicht etwa das Codieren betrifft, sondern das Modellieren und Lösen eines Algebra-Problems . Lass uns gehen.

Parametrisierung

Wenn Sie einen Hochschulabschluss haben, erinnern Sie sich vielleicht an Funktionen - Operationen, die einen Parameter annehmen und ein Ergebnis liefern - und Diagramme - eine grafische Darstellung (oder ein Diagramm) der Entwicklung von eine Funktion gegenüber ihrem Parameter. f(x) kann Sie an etwas erinnern: Es besagt, dass eine Funktion mit dem Namen f vom Parameter x abhängt. "Zu parametrisieren " bedeutet also grob ausgedrückt, ein System in Form eines oder mehrerer Parameter auszudrücken. 

Sie sind möglicherweise nicht mit den Begriffen vertraut, tun dies jedoch ständig. Ihre Track ist beispielsweise ein System mit 3 Parametern: f(x,y,z).

Eine interessante Sache bei der Parametrierung ist, dass Sie ein System packen und anhand anderer Parameter beschreiben können. Wieder machst du es schon. Wenn Sie die Entwicklung Ihres Tracks mit der Zeit beschreiben, sagen Sie, dass jede Koordinate eine Funktion der Zeit ist, f(x,y,z) = f(x(t),y(t),z(t)) = f(t). Mit anderen Worten, Sie können Zeit verwenden, um jede Koordinate zu berechnen, und die Koordinaten verwenden, um Ihr Objekt für die angegebene Zeit im Raum zu positionieren.

Modellieren eines Schienensystems

Schließlich werde ich anfangen, deine Frage zu beantworten. Um das gewünschte Track-System vollständig zu beschreiben, benötigen Sie zwei Dinge:

  1. Ein Weg;

Sie haben diesen Teil bereits praktisch gelöst. Sie richten einige Punkte im Szenenraum ein und verwenden einen Catmull-Rom-Spline, um die Punkte zu interpolieren und einen Pfad zu generieren. Das ist klug und es bleibt nicht mehr viel zu tun.

Außerdem haben Sie an jedem Punkt ein Feld time hinzugefügt, um sicherzustellen, dass das sich bewegende Objekt genau zu diesem Zeitpunkt diese Prüfung durchläuft. Ich werde später darauf zurückkommen.

  1. Ein sich bewegendes Objekt.

Interessant an Ihrer Path-Lösung ist, dass Sie die Pfadberechnung mit einem percentageThroughSegment-Parameter parametrisiert haben - einem Wert zwischen 0 und 1, der die relative Position innerhalb des Segments darstellt. In Ihrem Code iterieren Sie zu festen Zeitschritten, und Ihre percentageThroughSegment ist der Anteil zwischen der aufgewendeten Zeit und der gesamten Zeitspanne des Segments. Da jedes Segment eine bestimmte Zeitspanne hat, emulieren Sie viele konstante Geschwindigkeiten. 

Das ist ziemlich normal, aber es gibt eine Subtilität. Sie ignorieren einen äußerst wichtigen Teil bei der Beschreibung einer Bewegung: die zurückgelegte Strecke .

Ich schlage Ihnen einen anderen Ansatz vor. Verwenden Sie die zurückgelegte Entfernung, um Ihren Weg zu parametrieren. Dann ist die Bewegung des Objekts die zurückgelegte Entfernung in Bezug auf die Zeit. Auf diese Weise haben Sie zwei unabhängige und konsistente Systeme. Hände zur Arbeit!

Beispiel:

Von jetzt an werde ich alles der Einfachheit halber 2D machen, aber später auf 3D umzustellen, wird trivial sein.

Betrachten Sie den folgenden Pfad:

 Example path

Wenn i der Index des Segments ist, ist d die zurückgelegte Entfernung und x, y die Koordinaten in der Ebene. Dies kann ein Pfad sein, der von einem Spline wie Ihrem erstellt wurde, oder mit Bézier-Kurven oder was auch immer.

Die Bewegung, die ein Objekt mit Ihrer aktuellen Lösung entwickelt hat, könnte als ein Diagramm von distance traveled on the path vs time wie folgt beschrieben werden:

 Movement 1 graph

Wobei t in der Tabelle die Zeit ist, zu der das Objekt die Prüfung erreichen muss, d wieder die bis zu dieser Position zurückgelegte Entfernung ist, v die Geschwindigkeit und a die Beschleunigung ist. 

Der obere Teil zeigt, wie das Objekt mit der Zeit vorrückt. Die horizontale Achse ist die Zeit und die Vertikale ist die zurückgelegte Entfernung. Wir können uns vorstellen, dass die vertikale Achse der Pfad ist, der in einer flachen Linie "abgerollt" ist. Der untere Graph zeigt die Entwicklung der Geschwindigkeit über die Zeit.

Wir müssen uns an dieser Stelle an etwas Physik erinnern und beachten, dass die Kurve der Entfernung in jedem Segment eine gerade Linie ist, die einer Bewegung mit konstanter Geschwindigkeit ohne Beschleunigung entspricht. Ein solches System wird durch diese Gleichung beschrieben: d = do + v*t

 Movement 1 animation

Wenn das Objekt die Kontrollpunkte erreicht, ändert sich plötzlich der Geschwindigkeitswert (da der Graph keine Kontinuität aufweist), und dies hat einen ungewöhnlichen Effekt in der Szene. Ja, das wissen Sie bereits und deshalb haben Sie die Frage gestellt.

Ok, wie können wir das besser machen? Hmm ... Wenn der Geschwindigkeitsdiagramm kontinuierlich wäre, wäre das nicht der nervige Geschwindigkeitssprung. Die einfachste Beschreibung einer solchen Bewegung könnte eine einheitliche Beschleunigung sein. Ein solches System wird durch diese Gleichung beschrieben: d = do + vo*t + a*t^2/2. Wir müssen auch eine Anfangsgeschwindigkeit annehmen, ich wähle hier Null (Abschied von Ruhe).

 enter image description here

Wie erwartet, ist der Geschwindigkeitsdiagramm kontinuierlich, die Bewegung wird über den Weg beschleunigt. Dies könnte in Unity kodiert werden, indem die Methids Start und GetPosition folgendermaßen geändert werden:

private List<float> lengths = new List<float>();
private List<float> speeds = new List<float>();
private List<float> accels = new List<float>();
public float spdInit = 0;

private void Start()
{
  wayPoints.Sort((x, y) => x.time.CompareTo(y.time));
  wayPoints.Insert(0, wayPoints[0]);
  wayPoints.Add(wayPoints[wayPoints.Count - 1]);
       for (int seg = 1; seg < wayPoints.Count - 2; seg++)
  {
    Vector3 p0 = wayPoints[seg - 1].pos;
    Vector3 p1 = wayPoints[seg].pos;
    Vector3 p2 = wayPoints[seg + 1].pos;
    Vector3 p3 = wayPoints[seg + 2].pos;
    float len = 0.0f;
    Vector3 prevPos = GetCatmullRomPosition(0.0f, p0, p1, p2, p3, catmullRomAlpha);
    for (int i = 1; i <= Mathf.FloorToInt(1f / debugTrackResolution); i++)
    {
      Vector3 pos = GetCatmullRomPosition(i * debugTrackResolution, p0, p1, p2, p3, catmullRomAlpha);
      len += Vector3.Distance(pos, prevPos);
      prevPos = pos;
    }
    float spd0 = seg == 1 ? spdInit : speeds[seg - 2];
    float lapse = wayPoints[seg + 1].time - wayPoints[seg].time;
    float acc = (len - spd0 * lapse) * 2 / lapse / lapse;
    float speed = spd0 + acc * lapse;
    lengths.Add(len);
    speeds.Add(speed);
    accels.Add(acc);
  }
}

public Vector3 GetPosition(float time)
{
  //Check if before first waypoint
  if (time <= wayPoints[0].time)
  {
    return wayPoints[0].pos;
  }
  //Check if after last waypoint
  else if (time >= wayPoints[wayPoints.Count - 1].time)
  {
    return wayPoints[wayPoints.Count - 1].pos;
  }

  //Check time boundaries - Find the nearest WayPoint your object has passed
  float minTime = -1;
  // float maxTime = -1;
  int minIndex = -1;
  for (int i = 1; i < wayPoints.Count; i++)
  {
    if (time > wayPoints[i - 1].time && time <= wayPoints[i].time)
    {
      // maxTime = wayPoints[i].time;
      int index = i - 1;
      minTime = wayPoints[index].time;
      minIndex = index;
    }
  }

  float spd0 = minIndex == 1 ? spdInit : speeds[minIndex - 2];
  float len = lengths[minIndex - 1];
  float acc = accels[minIndex - 1];
  float t = time - minTime;
  float posThroughSegment = spd0 * t + acc * t * t / 2;
  float percentageThroughSegment = posThroughSegment / len;

  //Define the 4 points required to make a Catmull-Rom spline
  Vector3 p0 = wayPoints[ClampListPos(minIndex - 1)].pos;
  Vector3 p1 = wayPoints[minIndex].pos;
  Vector3 p2 = wayPoints[ClampListPos(minIndex + 1)].pos;
  Vector3 p3 = wayPoints[ClampListPos(minIndex + 2)].pos;

  return GetCatmullRomPosition(percentageThroughSegment, p0, p1, p2, p3, catmullRomAlpha);
}

Ok, mal sehen wie es geht ...

 enter image description here

Ähhhhhhhhhhhhhhhh.jpg Es sah fast gut aus, außer dass es sich irgendwann rückwärts bewegt und dann wieder vorrückt. Wenn wir unsere Diagramme überprüfen, werden sie dort beschrieben. Zwischen 12 und 16 Sekunden ist die Geschwindigkeit negativ. Warum passiert das? Da diese Bewegungsfunktion (konstante Beschleunigungen) zwar einfach ist, gibt es einige Einschränkungen. Bei einigen abrupten Geschwindigkeitsschwankungen gibt es möglicherweise keinen konstanten Beschleunigungswert, der unsere Prämisse (das Weitergeben von Kontrollpunkten zum richtigen Zeitpunkt) ohne Nebeneffekte wie diese gewährleisten kann.

Was tun wir jetzt?

Sie haben viele Möglichkeiten:

  • Beschreiben Sie ein System mit linearen Beschleunigungsänderungen und wenden Sie Randbedingungen an (Warnung: Lose der zu lösenden Gleichungen);
  • Beschreiben Sie ein System mit konstanter Beschleunigung über einen bestimmten Zeitraum, z. B. Beschleunigen oder Abbremsen kurz vor/nach der Kurve, und halten Sie die Geschwindigkeit für den Rest des Segments konstant (Warnung: noch mehr Gleichungen zu lösen, schwer zu garantieren Voraussetzung für das Passieren von Kontrollpunkten in der richtigen Zeit);
  • Verwenden Sie eine Interpolationsmethode, um ein Diagramm der Position durch die Zeit zu generieren. Ich habe Catmull-Rom selbst ausprobiert, aber das Ergebnis hat mir nicht gefallen, weil die Geschwindigkeit nicht sehr glatt aussah. Bezier-Kurven scheinen ein bevorzugter Ansatz zu sein, da Sie die Steigungen (auch als Geschwindigkeiten bezeichnet) an den Kontrollpunkten direkt beeinflussen und Rückwärtsbewegungen vermeiden können.
  • Und mein Favorit: Fügen Sie ein öffentliches AnimationCurve-Feld in der Klasse hinzu und passen Sie Ihre Bewegungsgrafik im Editor mit der ts fantastischen integrierten Schublade an! Mit der Methode AddKey können Sie Kontrollpunkte problemlos hinzufügen und mit der Methode Evaluate eine Zeit lang eine Position abrufen. Sie können sogar die Methode OnValidate für Ihre Komponentenklasse verwenden, um die Punkte in der Szene automatisch zu aktualisieren, wenn Sie sie in der Szene bearbeiten Kurve und umgekehrt.

Hör nicht auf! Fügen Sie einen Verlauf in der Pfadlinie Gizmo hinzu, um schnell zu erkennen, wo es schneller oder langsamer geht. Fügen Sie Griffe hinzu, um den Pfad im Editor-Modus zu bearbeiten ... werden Sie kreativ!

1

Soweit ich das beurteilen kann, haben Sie den größten Teil der Lösung bereits installiert, nur falsch initialisiert. 

Die lokale Geschwindigkeit hängt von der Länge des Splines ab. Daher sollten Sie die Geschwindigkeit um Inverse der Länge des Segments modulieren (was sich leicht mit wenigen Schritten approximieren lässt). 

In Ihrem Fall haben Sie zwar keine Kontrolle über die Geschwindigkeit, nur die Eingabezeit, also müssen Sie die Werte von SimpleWayPoint.timeentsprechend der Reihenfolge und Länge der vorherigen Splinesegmente) richtig verteilen, anstatt sie zu initialisieren manuell in der Felddeklaration. Auf diese Weise sollte percentageThroughSegment gleichmäßig verteilt werden.

Wie in den Kommentaren erwähnt, könnte ein Teil dieser Mathematik mit Lerp() :) einfacher aussehen.

0
Brice V.

Sie können versuchen, mit dem Wheelcollider-Tutorial zu arbeiten, das sie für ihr Radsystem haben.

Es gibt einige Variablen, die Sie zusammen mit den Rigidbody-Variablen anpassen können, um ein simuliertes Fahren zu erreichen.

Wie sie schreiben

Sie können bis zu 20 Räder in einer einzigen Fahrzeuginstanz haben, von denen jedes Lenk-, Motor- oder Bremsmoment aufbringt.

Haftungsausschluss: Ich habe nur minimale Erfahrung mit WheelColliders. Aber sie scheinen mir das zu sein, wonach Sie suchen.

https://docs.unity3d.com/Manual/WheelColliderTutorial.html

 enter image description here

0
Doh09

Lassen Sie uns zuerst einige Begriffe definieren:

  1. t: Interpolationsvariable für jeden Spline von 0 bis 1.
  2. s: die Länge jedes Splines. Je nachdem, welchen Spline-Typ Sie verwenden (Catmull-Rom, Bezier usw.), gibt es Formeln, um die geschätzte Gesamtlänge zu berechnen.
  3. dt: Die Änderung in t pro Frame. Wenn dies für alle Splines konstant ist, werden Sie an den Spline-Endpunkten eine plötzliche Geschwindigkeitsänderung feststellen, da jeder Spline eine unterschiedliche Länge s hat.

Die einfachste Möglichkeit, die Geschwindigkeitsänderung an jedem Gelenk zu erleichtern, ist:

void Update() {
    float dt = 0.05f; //this is currently your "global" interpolation speed, for all splines
    float v0 = s0/dt; //estimated linear speed in the first spline.
    float v1 = s1/dt; //estimated linear speed in the second spline.
    float dt0 = interpSpeed(t0, v0, v1) / s0; //t0 is the current interpolation variable where the object is at, in the first spline
    transform.position = GetCatmullRomPosition(t0 + dt0*Time.deltaTime, ...); //update your new position in first spline
}

woher:

float interpSpeed(float t, float v0, float v1, float tEaseStart=0.5f) {
    float u = (t - tEaseStart)/(1f - tEaseStart);
    return Mathf.Lerp(v0, v1, u);
}

Die Intuition oben besagt, dass ich beim Erreichen des Endes meines ersten Splines die erwartete Geschwindigkeit für den nächsten Spline vorhersage und meine aktuelle Geschwindigkeit dorthin beschleunige.

Schließlich, um die Lockerung noch besser aussehen zu lassen:

  • Erwägen Sie die Verwendung einer nichtlinearen Interpolationsfunktion in interpSpeed().
  • Erwägen Sie die Implementierung eines "Einstiegs" auch zu Beginn des zweiten Splines
0
Lincoln C