Wie kann ich ein sich bewegendes Objekt am Ende eines Pfades reibungslos anhalten lassen?


8

Es gibt ein Dutzend Möglichkeiten, wie ich diese Frage formulieren könnte, aber um meine Gedanken in Einklang zu bringen, formuliere ich sie in Übereinstimmung mit meinem vorliegenden Problem.

Also erstelle ich eine schwimmende Plattform, auf der ich einfach von einem bestimmten Punkt zum anderen fahren und dann zum ersten zurückkehren und einfach in einer geraden Linie zwischen den beiden hin- und hergehen möchte. Um es jedoch ein wenig interessanter zu machen, möchte ich der Plattform einige Regeln hinzufügen.

  1. Ich codiere es, um ein Vielfaches ganzer Kachelwerte von Weltdaten zu übertragen. Wenn die Plattform also nicht stationär ist, bewegt sie sich mindestens eine ganze Fliesenbreite oder Fliesenhöhe.
  2. Innerhalb einer Fliesenlänge möchte ich, dass es von einem Stopp auf eine bestimmte Höchstgeschwindigkeit beschleunigt.
  3. Nach Erreichen der Entfernung einer Kachellänge möchte ich, dass diese bei einer bestimmten Kachelkoordinate zum Stillstand kommt und den Vorgang dann in umgekehrter Reihenfolge wiederholt.

Geben Sie hier die Bildbeschreibung ein

Die ersten beiden Teile sind nicht allzu schwierig, im Wesentlichen habe ich Probleme mit dem dritten Teil. Ich möchte, dass die Plattform genau an einer Kachelkoordinate anhält, aber da ich mit Beschleunigung arbeite, scheint es einfach zu sein, die Beschleunigung in die entgegengesetzte Richtung auf einen Wert anzuwenden, der die aktuelle Geschwindigkeit der Plattform speichert, sobald sie die Länge einer Kachel erreicht der Entfernung (unter der Annahme, dass die Kachel mehr als eine Kachellänge zurücklegt, aber um die Dinge einfach zu halten, nehmen wir einfach an, dass dies der Fall ist) - aber dann ist die Frage, wie hoch der richtige Wert für die Beschleunigung wäre, um diesen Effekt zu erzielen? Wie würde ich diesen Wert finden?


1
Ich habe momentan keine Zeit für eine vollständige Antwort, aber sehen Sie sich das an: red3d.com/cwr/steer/gdc99 , speziell den Abschnitt "Ankunft". Imitieren Sie dieses Verhalten, um zu einem Stopp zu verlangsamen, und kehren Sie es um, um von einem Stopp zu beschleunigen.
MichaelHouse

Lesezeichen. Das ist eine Fülle wertvoller Informationen, die Sie mir gerade aufgeklärt haben, Sir.
TheBroodian

Diese Art "gewünschte_Geschwindigkeit = (abgeschnittene Geschwindigkeit / Entfernung) * Zielversatz" ist sinnvoll, aber nicht genau. Sobald ich die gewünschte Geschwindigkeit gefunden habe, subtrahiere ich sie von der aktuellen Geschwindigkeit des Objekts?
TheBroodian

Ich verwende es, um den Beschleunigungswert zu aktualisieren: acceleration = desired_velocity - currentVelocityWenden Sie diese Beschleunigung dann wie gewohnt an. Ich werde in Kürze eine Antwort erstellen, die zeigt, was ich tue.
MichaelHouse

Antworten:


5

Verwenden Sie diese Lenkverhalten als Richtlinie. Betrachten Sie das Ankunftsverhalten:

Geben Sie hier die Bildbeschreibung ein

Das Ankunftsverhalten ist identisch mit der Suche, während der Charakter weit von seinem Ziel entfernt ist. Anstatt sich mit voller Geschwindigkeit durch das Ziel zu bewegen, wird der Charakter durch dieses Verhalten langsamer, wenn er sich dem Ziel nähert, und verlangsamt sich schließlich bis zu einem Stopp, der mit dem Ziel zusammenfällt.

Wir können eine "Ankunft" -Funktion wie diese erstellen:

arriveAtPoint(Vector2f position, Vector2f target) {
    float slowing_distance = 1;
    Vector2f target_offset = target - position;
    float distance = target_offset.length();
    float ramped_speed = currentVelocity * (distance / slowing_distance);
    float clipped_speed = Math.min(ramped_speed, currentVelocity);
    targetLinearVelocity = target_offset.scale(clipped_speed / distance);
    acceleration = targetLinearVelocity -linearVelocity;
}

Dadurch wird die Beschleunigung aktualisiert, die zum Anwenden auf das bewegte Objekt erforderlich ist.


Und nur zur Verdeutlichung wäre linearVelocity die Geschwindigkeit, mit der sich unser Objekt nach dem vorherigen Update gerade bewegt hätte?
TheBroodian

Deine Formulierung ist ziemlich seltsam. Aber linearVelocity == currentVelocity.
MichaelHouse

3
Ich bin mit diesem Ansatz nicht einverstanden, da er zu kompliziert ist. Dies ist mit einem einfachen Tween unter Verwendung von Bewegungsgleichungen ( den SUVAT-Formeln ) möglich. Ein wenig Algebra und Sie können die Eingaben berechnen, die erforderlich sind, um ein gewünschtes Ziel genau zu treffen.
Andrew Russell

1
Es wäre hilfreich, wenn Sie das mit einer Antwort ausarbeiten könnten?
TheBroodian

@ AndrewRussell Ich würde diese Antwort auch gerne sehen.
MichaelHouse

5

Schauen Sie sich diese Seite an: http://sol.gfxile.net/interpolation/index.html

Es scheint, dass Sie einen Effekt wie den glatten Schritt wollen:

Smoothstep-Grafik

Wenn Sie den Punkt ganz links haben, den Punkt ganz rechts, den die Plattform erreichen sollte, und die Zeit, die sie für die Erstellung einer vollständigen Sequenz benötigen sollte, kann Folgendes in Ordnung sein:

foreach frame:

float smoothstep(float t, int level = 1)
{
    float ret = t;
    for(int i = 0; i < level; ++i)
    {
        ret = pow(ret, 2) * (3 - 2 * ret);
    }
    return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);

Wenn Sie eine Physik-Engine verwenden, können Sie sie mit Impulsen erstellen, sollte nicht so schwer zu übersetzen sein. Wenn Sie einen noch reibungsloseren Prozess wünschen, können Sie den Smoothstep-Level erhöhen. Mehrfacher Glattschritt


3

Sie können XnaTweener verwenden , das Beschleunigungsfunktionen bietet, mit denen Werte auf einfache Weise von einem Punkt zum anderen interpoliert werden können ...

Hier ist eine Antwort mit Code aus dem Xna Tweener-Projekt und einem Video, das zeigt, wie es funktioniert ...

https://gamedev.stackexchange.com/a/26872/8390

[BEARBEITEN]

Sie sollten eine Tastenfolge haben, die die Plattformbewegung wie folgt definiert:

public class MovementKey
{
    public float Time = 0;
    public float Duration;
    public Vector2 Traslation;            // Traslation is relative to previous key
    public TweeningFunction Function;

    internal float GetRatio( float Elapsed )   
    {
        // Always return a value in [0..1] range
        //    0 .. Start position relative to accumulated traslations of previous keys
        //    1 .. Target relative position reached.. then should go to next key if avalaible
        return Function( Elapsed, 0, 1, Duration ); 
    }
}

Und dann können Sie die Bewegung folgendermaßen handhaben:

public class Movement {

    List<MovementKey> Keys;

    public void Update( float Seconds)
    {

        float ratio;
        if (Playing) Elapsed += Seconds;

        while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
        {
            Traslation += Keys[iKey].Traslation;  // Relative
            index++;
        }

       if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
       {
          ratio = 1;
          if ( DoLoop )
          {
              Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
              Index = 0;
              Traslation = Vector2.zero;
          }
       }
       else {                    
           ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
       }

       Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;        
   }

"DefaultPosition" ist die Startposition, "Traslation" akkumuliert die Bewegung mehrerer Tasten, und jede Tastenübersetzung ist relativ zur vorherigen Taste. Wenn Sie sie also mit einem Verhältnisfaktor [0..1] multiplizieren, wird die interpolierte relative Übersetzung zurückgegeben um diesen Schlüssel vom vorherigen Schlüssel zu erreichen ...

Hier haben Sie ein weiteres Video, das eine Plattformbewegung zeigt, die wie hier beschrieben definiert ist ...

http://www.youtube.com/watch?v=ZPHjpB-ErnM&feature=player_detailpage#t=104s

Ich habe diesen Code überarbeitet, um ihn verständlich zu machen ... vielleicht hat er einen Fehler ... der ursprüngliche Code behandelt mehrere Instanzen derselben Bewegung, aber mit einigen Verzögerungen zwischen den einzelnen Instanzen ... Ich bin sicher, dass dieser Code dies kann neu gestaltet werden, um einfacher zu sein ...


Vielen Dank, dies ist hilfreich, obwohl es im scheinbaren Kontext einer Animation verwendet wird. Ich versuche, es in meinem Kopf in etwas zu übersetzen, das für meine aktuelle Situation kontextbezogener wäre.
TheBroodian

Ich bin verloren. Ich kann nicht herausfinden, wie ich das überhaupt mit meiner aktuellen Situation in Verbindung bringen soll. oo ;;
TheBroodian

Sie haben eine Animation ... Sie versuchen, in Bezug auf die Position zu animieren ...
Blau

Verzeihen Sie mir, der Grund, warum ich Schwierigkeiten habe, ist, dass ich versuche, diese Idee zu booten und sie in ein System zu übersetzen, das auf einem Zeitsystem mit Geschwindigkeit = Geschwindigkeit * arbeitet, während dieses System die Position des Objekts einfach prozedural anstößt (Daran ist nichts auszusetzen, nur schwer zu finden, wie man die beiden in Beziehung setzt).
TheBroodian
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.