Bewegen von einem Vector3 Punkt zu einem anderen Vector3 Punkt über Zeit

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von DTF.

    Bewegen von einem Vector3 Punkt zu einem anderen Vector3 Punkt über Zeit

    Hallo liebe Community!

    Ich bin mit meinen Versuchen am Ende einen Vector3 Punkt zu einem anderen Vector3 Punkt in einer bestimmten Zeit zu erreichen.. Und darum frage ich euch nun um Hilfe.

    Mein Vorhaben ist ganz simpel, hier habe ich für euch nochmal eine kleine Visuelle Darstellung von diesen Vorhaben:


    Ich habe verschiedene Methoden versucht, doch ich habe es leider nicht hinbekommen :/
    Hier sind einige Versuche:

    C#-Quellcode

    1. lastNode.NewPosition = lastNode.NewPosition.MoveTowards(lastNextNode.NewPosition, ((lastNode.NewPosition - lastNextNode.NewPosition).Length() * lastNextNode.AtPosition * IVTimer.TimeStep) * Vector3.Distance(lastNode.NewPosition, lastNextNode.NewPosition));
    2. lastNode.NewPosition = lastNode.NewPosition.MoveTowards(lastNextNode.NewPosition, (currentSecond * (lastNode.NewPosition - lastNextNode.NewPosition).Length()) / lastNextNode.AtPosition * IVTimer.TimeStep);
    3. lastNode.NewPosition = lastNode.NewPosition.MoveTowards(lastNextNode.NewPosition, (lastNextNode.AtPosition / (lastNode.NewPosition - lastNextNode.NewPosition).Length()) * IVTimer.TimeStep);
    4. lastNode.NewPosition = lastNode.NewPosition.MoveTowards(lastNextNode.NewPosition, currentSecond / (lastNextNode.AtPosition / 10f) * IVTimer.TimeStep);
    5. lastNode.NewPosition = Vector3.Lerp(lastNode.NewPosition, lastNextNode.NewPosition, (lastNextNode.AtPosition / 10f) * NativeGame.FrameTime);
    6. lastNode.NewPosition = Vector3.Lerp(lastNode.NewPosition, lastNextNode.NewPosition, ((currentSecond / 10f) / (lastNextNode.AtPosition / 10f)) * NativeGame.FrameTime);
    7. // Sets the position of the camera
    8. freeCam.Position = lastNode.NewPosition;


    Ich schätze dies war bisher mein bester Versuch:

    C#-Quellcode

    1. lastNode.NewPosition = Vector3.Lerp(lastNode.NewPosition, lastNextNode.NewPosition, ((currentSecond / 10f) / (lastNextNode.AtPosition / 10f)) * NativeGame.FrameTime);


    Das sah dann so aus:


    Das ganze soll so eine Art keyframe editor werden basierend anhand der momentanen Musik

    Wie man im Video sah, habe ich auf Position 0 ein Keyframe gesetzt, und auf Position 15.
    Die Kamera soll dann in 15 Sekunden das Ziel erreichen.
    Jedoch wie man sah, war die Kamera zu schnell am Ziel.

    currentSecond ist die momentane position der musik
    lastNextNode.AtPosition ist die zeit in der die interpolation erreicht werden soll
    NativeGame.FrameTime und IVTimer.TimeStep ist beides das selbe, ich dachte anfangs das vielleicht unterschiede bestände

    Ich bin nicht der beste im erklären, also falls ihr noch Fragen habt, gerne fragen!
    Danke im Vorraus!
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    @ClonkAndre Schreib das doch mal ganz einfach in Vektorschreibweise auf:

    Quellcode

    1. int count = 42; // Anzahl der Schritte
    2. double length = (VectZiel - VectStart).Betrag / count;
    3. VectStep = (VectZiel - VectStart).Norm / length; // Schrittweite
    4. VectMotion = VectStart;
    5. for(int steps = 0; steps < count; steps++)
    6. {
    7. VectMotion += VectStep;
    8. }
    Feddich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Was genau ist denn die "Vektorschreibweise"?
    Sorry, ich bin wirklich kein Mathe Profi.
    Wie genau wende ich denn den Code von dir an?

    Die "MoveTowards" Funktion die man in meinen Tests oben sehen kann, ist übrigens eine extension des System.Numerics.Vector3 structs und sieht folgendermaßen aus:

    C#-Quellcode

    1. public static Vector3 MoveTowards(this Vector3 vec, Vector3 target, float maxDistanceDelta)
    2. {
    3. Vector3 vector3 = target - vec;
    4. float magnitude = vector3.Length();
    5. return magnitude <= maxDistanceDelta || magnitude == 0.0 ? target : vec + vector3 / magnitude * maxDistanceDelta;
    6. }
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Wenn du das mit Linearinterpolation machst und mit der Zeit und Dauer einen Alphawert für die VectorLerp funktion berechnest, geht das recht einfach. Das funktioniert so auch Frameraten unabhängig.

    Ein wenig PseudoCode, sollte so funktionieren.

    Quellcode

    1. vector3 startVector = ...
    2. vector3 targetVector = ...
    3. float startTime = GetCurrentGameTime()
    4. float duration = 15
    5. float alpha = (GetCurrentGameTime() - startTime) / duration
    6. if(alpha > 1.0)
    7. {
    8. alpha = 1
    9. //target position reached
    10. }
    11. vector3 actorNewPos = LinearInterpolateVector3(startVector, targetVector, alpha)}


    PS:
    Jupp, funktioniert. Habs eben flott in der UE getestet mit 3 Sekunden Dauer.

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „DTF“ ()

    @ClonkAndre Du hattest ja auch in Deinem Snippet Vektoren verwendet.
    Das sind Grundlagen, wo Du erst mal reinschauen solltest:
    de.wikipedia.org/wiki/Vektor
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hey @DTF, was genau spuckt die "GetCurrentGameTime()" Funktion für einen Wert aus?

    Ich hatte mit deinem PseudoCode auch leider kein Erfolg (Kamera hat das Ziel nicht in der angegebenen Zeit erreicht), und ich gehe davon aus, das ich einen falschen Werte nehme für die startTime und alpha Variable.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    ClonkAndre schrieb:

    Kamera hat das Ziel nicht in der angegebenen Zeit erreicht
    Dann musst Du mal mit den Parametern spielen.
    Sieh Dir den Inhalt der Variablen an, gib ihn in der Console aus, mached Sinnigkeitstest.
    Lerne zu debuggen.
    Debuggen, Fehler finden und beseitigen
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ClonkAndre schrieb:

    Hey @DTF, was genau spuckt die "GetCurrentGameTime()" Funktion für einen Wert aus?


    GetCurrentGameTime war nur also Pseudo gedacht. Du kannst genauso gut die aktuelle Zeit vom System nutzen. Schau mal in dem Video von mir, die Blueprint-Nodes sollten leicht zu verstehen sein. Wenn du das nicht lesen kannst, weil die Auflösung probleme macht, kenne das selber als ich noch FHD nutze und 4K Videos geschaut hab. Dann sag Bescheid, kann dann einen Scrennshot anhängen in kleinerer Auflösung anhängen.

    Die Signatur von Lerp:
    public static System.Numerics.Vector3 Lerp (System.Numerics.Vector3 value1, System.Numerics.Vector3 value2, float amount);

    Zum Alpha-Wert(oben amount genannt), wenn Alpha 0 ist, kommt der Wert aus der Funktion der bei value1 reingeht(der vector wo wir starten), wenn Alpha 1 ist, kommt der Wert von value2 heraus. Bei 0.5 genau die Mitte zwischen beiden. Probier selbst auch mal -1 und 2 für alpha aus und schau an wie das Einfluss auf die Werte nimmt ;)

    Also du kennst die StartZeit der Animation und auch die gewollte Dauer:

    StartZeit = BeginDerAnimation
    EndZeit = StartZeit + 15 = EndDerAnimation. // 15 ist deine gewollte Dauer

    Ist wie bei Prozentrechnen: "Wert / Maximum * 100 = %"
    Also:
    (Aktuelle Zeit - StartZeit) / Dauer

    Da ein Wert zwischen 0 und 1 gebraucht wird, sparen wir die Multiplikation mit 100.

    Im PseudeCode deshalb die abfrage ob Alpha > 1 ist, so lässt sich sofort feststellen, das die Animation ist durch ist. Würde man dann den Wert für Alpha nicht auf 1 setzen, würde man ein klein wenig übers Ziel hinausschiessen.

    Ob du also nun eine Zeit als float oder einen der Integer-Typen(Ganzzahlen) nutzt ist egal, hauptsache du kommst von 0 bis 1 wie ich zeigte.

    Setze die Postion des Actors anstatt MoveTowards. Dann sollte das Movement schon mal klappen. @ClonkAndre hab jetzt einfach noch den Screenshot vom meinem Blueprint aus der UE gemacht, sieh ihn dir an, ist wirklich nicht schwer zu verstehen. Ist wie mit der Maus zusammengeklickter Code.
    Bilder
    • Unbenannt.jpg

      513,7 kB, 2.028×922, 36 mal angesehen
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „DTF“ ()

    Letzter Post ist so lang, bin mal frech und mach einen Doppelpost.

    @ClonkAndre
    Hab das mal in 2D mit einer bewegten PictureBox gemacht. Einfach Z vom Vector ignoriert, die PictureBox "wandert" in der angegebenen Dauer von A nach B. So ein 2D Beispiel hätte mir früher einfallen sollen, so einfach kann es sein.

    C#-Quellcode

    1. using System.Numerics;
    2. namespace Movement
    3. {
    4. public partial class Form1 : Form
    5. {
    6. Vector3 startPos = new Vector3(0, 0, 0);
    7. Vector3 endPos = new Vector3(500, 150, 0);
    8. PictureBox box = new PictureBox();
    9. DateTime startTime;
    10. public Form1()
    11. {
    12. InitializeComponent();
    13. }
    14. private void Form1_Load(object sender, EventArgs e)
    15. {
    16. box.Size = new Size(10, 10);
    17. box.Location = new Point((int)startPos.X, (int)startPos.Y);
    18. box.BackColor = Color.Blue;
    19. Controls.Add(box);
    20. }
    21. private void timer1_Tick(object sender, EventArgs e)
    22. {
    23. float alpha = 0;
    24. float duration = 15;
    25. alpha = (float)((DateTime.Now - startTime).TotalSeconds / duration);
    26. if (alpha > 1)
    27. {
    28. alpha = 1;
    29. timer1.Stop();
    30. }
    31. Vector3 pos = Vector3.Lerp(startPos, endPos, alpha);
    32. box.Location = new Point((int)pos.X, (int)pos.Y);
    33. }
    34. private void button1_Click(object sender, EventArgs e)
    35. {
    36. box.Location = new Point((int)startPos.X, (int)startPos.Y);
    37. startTime = DateTime.Now;
    38. timer1.Start();
    39. }
    40. }
    41. }

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DTF“ ()

    @DTF Habe es nun auch soweit zum laufen bekommen! Ich hatte einen entscheidenen Fehler gemacht: Ich hatte die Position der Kamera als value1 Parameter im Vector3.Lerp eingefügt welche sich durch den Lerp die ganze Zeit geändert hat :S Also die start position ist die ganze Zeit mit der Kamera mitgewandert und hat das Ergebnis verfälscht :whistling:

    Ich habe die Rotation der Kamera noch nicht getestet, aber da ich jetzt den Code habe sollte dies auch kein Problem mehr sein!

    Vielen dank für die ausführliche Erklärung und deiner Hilfsbereitschaft!
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Ja wunderbar. Dann hast du direkt wie in deinem Video auch schon EaseIn EaseOut drin? Also langsam anfahren und am Ende langsamer werden?

    Das mach ich gerade eine "Kurve" selbst für. Beeinflusst den Alpha Wert für die vector3.Lerp, macht dann genau das. Also EaseIn und auch Out. Editiere ich hier noch rein, das kann sicherlich irgendwann noch jemand brauchen. Ich zwar nicht, gibts alles in der UE für sowas, aber können möchte ich das denn doch noch auf die Harte(Bin viel zu verwöhnt von fertigem Zeug). Nette übung um den Kopf fit zu halten.

    PS:
    Hat geklappt. Hab Spass dran gefunden, werde ich evtl. noch erweitern um die startbeschleunigung und end-entschleunigung variabel zu machen. :D

    C#-Quellcode

    1. using System.Numerics;
    2. namespace Movement
    3. {
    4. public partial class Form1 : Form
    5. {
    6. Vector3 startPos = new Vector3(0, 0, 0);
    7. Vector3 endPos = new Vector3(1000, 150, 0);
    8. PictureBox box = new PictureBox();
    9. DateTime startTime;
    10. public Form1()
    11. {
    12. InitializeComponent();
    13. }
    14. private float AlphaEaseInEaseOut(float alpha)
    15. {
    16. return alpha * alpha + (1 - ((1 - alpha) * (1 - alpha)) - (alpha * alpha)) * alpha;
    17. }
    18. private void Form1_Load(object sender, EventArgs e)
    19. {
    20. box.Size = new Size(10, 10);
    21. box.Location = new Point((int)startPos.X, (int)startPos.Y);
    22. box.BackColor = Color.Blue;
    23. Controls.Add(box);
    24. }
    25. private void timer1_Tick(object sender, EventArgs e)
    26. {
    27. float alpha = 0;
    28. float duration = 5;
    29. alpha = (float)((DateTime.Now - startTime).TotalSeconds / duration);
    30. if (alpha > 1)
    31. {
    32. alpha = 1;
    33. timer1.Stop();
    34. }
    35. Vector3 pos = Vector3.Lerp(startPos, endPos, AlphaEaseInEaseOut(alpha));
    36. box.Location = new Point((int)pos.X, (int)pos.Y);
    37. }
    38. private void button1_Click(object sender, EventArgs e)
    39. {
    40. box.Location = new Point((int)startPos.X, (int)startPos.Y);
    41. startTime = DateTime.Now;
    42. timer1.Start();
    43. }
    44. }
    45. }

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DTF“ ()

    DTF schrieb:

    Dann hast du direkt wie in deinem Video auch schon EaseIn EaseOut drin? Also langsam anfahren und am Ende langsamer werden?


    Hatte ich leider noch nicht, hätte mich damit abfinden können, doch dann sah ich das du uns ein Beispiel Code hinterlassen hast um dies zu ermöglichen, unddd... nun gibt es auch bei mir eine EaseIn/EasyOut Funktion <3
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    DTF schrieb:

    C#-Quellcode

    1. private float AlphaEaseInEaseOut(float alpha)
    2. {
    3. return alpha * alpha + (1 - ((1 - alpha) * (1 - alpha)) - (alpha * alpha)) * alpha;
    4. }
    Meinst Du

    C#-Quellcode

    1. private float AlphaEaseInEaseOut2(float alpha)
    2. {
    3. return 3 * (alpha * alpha) - 2 * (alpha * alpha * alpha);
    4. }
    :?:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ja so ist das deutlich besser lesbar. Hatte gestern nur noch 3 Formeln für qadrieren, umdrehen und linearinterpolieren im kopf und draus diese hieroglyphenartige Formel gemacht. Hab beide Kurven verglichen, sind nahezu identisch, hinter der 6. oder 7. Nachkommastelle gabs erst minimale Abweichungen. Hab deine AlphaEaseInEaseOut2 mit in mein Projekt kopiert, damit ich das nicht vergesse. :thumbup:

    Ich glaub ich muss noch mal mehr Mathe pauken, speziell solche kurven.

    ClonkAndre schrieb:

    doch dann sah ich das du uns ein Beispiel Code hinterlassen hast um dies zu ermöglichen, unddd... nun gibt es auch bei mir eine EaseIn/EasyOut Funktion


    Freut mich. Aber die Formel von RFG ist besser, weil kürzer und weniger CPU instruktionen nötig, was gerade bei Spielen immer bedacht werden sollte. Beide daraus resultierenden Kurven sind nahezu identisch, von daher wie gesagt, RFGs Formel ist besser.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „DTF“ ()