Bevor ich die Bewegung meines Sprites extrapolierte, funktionierte meine Kollision perfekt. Nach der Extrapolation auf die Bewegung meines Sprites (um die Dinge zu glätten) funktioniert die Kollision jedoch nicht mehr.
So funktionierten die Dinge vor der Extrapolation:
Nachdem ich meine Extrapolation implementiert habe, wird die Kollisionsroutine jedoch unterbrochen. Ich gehe davon aus, dass dies darauf zurückzuführen ist, dass es auf die neue Koordinate einwirkt, die von der Extrapolationsroutine (die sich in meinem Renderaufruf befindet) erzeugt wurde.
Nachdem ich meine Extrapolation angewendet habe
Wie kann ich dieses Verhalten korrigieren?
Ich habe versucht, unmittelbar nach der Extrapolation eine zusätzliche Kollisionsprüfung durchzuführen. Dies scheint viele Probleme zu lösen, aber ich habe dies ausgeschlossen, da es nicht in Frage kommt, Logik in mein Rendering zu integrieren.
Ich habe auch versucht, eine Kopie der spritesX-Position zu erstellen, diese zu extrapolieren und mit dieser anstelle des Originals zu zeichnen, sodass das Original intakt bleibt, damit die Logik es aufnehmen kann - dies scheint eine bessere Option zu sein, aber es erzeugt immer noch einige seltsame Effekte bei Kollisionen mit Wänden. Ich bin mir ziemlich sicher, dass dies auch nicht der richtige Weg ist, um damit umzugehen.
Ich habe hier ein paar ähnliche Fragen gefunden, aber die Antworten haben mir nicht geholfen.
Dies ist mein Extrapolationscode:
public void onDrawFrame(GL10 gl) {
//Set/Re-set loop back to 0 to start counting again
loops=0;
while(System.currentTimeMillis() > nextGameTick && loops < maxFrameskip){
SceneManager.getInstance().getCurrentScene().updateLogic();
nextGameTick+=skipTicks;
timeCorrection += (1000d/ticksPerSecond) % 1;
nextGameTick+=timeCorrection;
timeCorrection %=1;
loops++;
tics++;
}
extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks;
render(extrapolation);
}
Extrapolation anwenden
render(float extrapolation){
//This example shows extrapolation for X axis only. Y position (spriteScreenY is assumed to be valid)
extrapolatedPosX = spriteGridX+(SpriteXVelocity*dt)*extrapolation;
spriteScreenPosX = extrapolationPosX * screenWidth;
drawSprite(spriteScreenX, spriteScreenY);
}
Bearbeiten
Wie oben erwähnt, habe ich versucht, eine Kopie der Sprite-Koordinaten speziell zum Zeichnen zu erstellen. Dies hat seine eigenen Probleme.
Erstens, unabhängig vom Kopieren, wenn sich das Sprite bewegt, ist es super glatt, wenn es stoppt, wackelt es leicht nach links / rechts - da es immer noch seine Position basierend auf der Zeit extrapoliert. Ist das normal und können wir es ausschalten, wenn das Sprite stoppt?
Ich habe versucht, Flags für links / rechts zu haben und nur dann zu extrapolieren, wenn eines davon aktiviert ist. Ich habe auch versucht, die letzte und die aktuelle Position zu kopieren, um festzustellen, ob es einen Unterschied gibt. Bei Kollisionen helfen diese jedoch nicht weiter.
Wenn der Benutzer beispielsweise die rechte Taste drückt und sich das Sprite nach rechts bewegt, wenn es gegen eine Wand stößt und der Benutzer die rechte Taste weiterhin gedrückt hält, wird das Sprite weiterhin nach rechts animiert, während es von der Wand gestoppt wird ( daher nicht wirklich bewegend), aber da die richtige Flagge immer noch gesetzt ist und auch weil die Kollisionsroutine das Sprite ständig aus der Wand bewegt, scheint es dem Code (nicht dem Spieler) immer noch, dass sich das Sprite noch bewegt, und daher Die Extrapolation wird fortgesetzt. Was der Spieler also sehen würde, ist das "statische" Sprite (ja, es ist animierend, aber es bewegt sich nicht wirklich über den Bildschirm), und ab und zu zittert es heftig, wenn die Extrapolation versucht, es zu tun ..... .. Ich hoffe das hilft
Antworten:
Ich kann noch keinen Kommentar posten, daher werde ich diesen als Antwort posten.
Wenn ich das Problem richtig verstehe, geht es ungefähr so:
Ich kann mir 3 mögliche Lösungen vorstellen. Ich werde sie in der Reihenfolge auflisten, die meiner Meinung nach am wenigsten wünschenswert ist.
Beispielcode für # 2.
Ich denke, # 2 wäre wahrscheinlich der schnellste und einfachste Weg, um zum Laufen zu kommen, obwohl # 1 eine logisch genauere Lösung zu sein scheint. Abhängig davon, wie Sie mit Ihrer Delta-Zeit-Lösung Nr. 1 umgehen, kann sie durch ein großes Delta auf die gleiche Weise unterbrochen werden. In diesem Fall müssen Sie möglicherweise sowohl Nr. 1 als auch Nr. 2 zusammen verwenden.
EDIT: Ich habe Ihren Code früher falsch verstanden. Die Schleifen sollen so schnell wie möglich gerendert und in einem festgelegten Intervall aktualisiert werden. Aus diesem Grund würden Sie die Sprite-Position interpolieren, um den Fall zu behandeln, in dem Sie mehr zeichnen als aktualisieren. Wenn die Schleife jedoch zurückfällt, fragen Sie beim Aktualisieren ab, bis Sie eingeholt werden oder die maximale Anzahl von Frame-Draws übersprungen haben.
Das einzige Problem ist jedoch, dass sich das Objekt nach einer Kollision bewegt. Bei einer Kollision sollte sich das Objekt nicht mehr in diese Richtung bewegen. Wenn es also zu einer Kollision kommt, setzen Sie die Geschwindigkeit auf 0. Dies sollte verhindern, dass die Renderfunktion das Objekt weiter bewegt.
quelle
Es sieht so aus, als müssten Sie das Rendern und Aktualisieren der Physik vollständig trennen. Normalerweise wird die zugrunde liegende Simulation in diskreten Zeitschritten ausgeführt, und die Frequenz ändert sich nie. Zum Beispiel könnten Sie die Bewegung Ihres Balls alle 1/60 Sekunde simulieren, und das war's.
Um eine variable Bildrate zu ermöglichen, sollte der Rendering-Code mit einer variablen Frequenz arbeiten, aber jede Simulation sollte sich immer noch in einem festen Zeitschritt befinden. Auf diese Weise können die Grafiken den Speicher aus der Simulation als schreibgeschützt lesen und die Interpolation anstelle der Extrapolation einrichten.
Da die Extrapolation versucht, vorherzusagen, wo zukünftige Werte liegen werden, können plötzliche Änderungen der Bewegung zu großen Extrapolationsfehlern führen. Es ist besser, stattdessen Ihre Szene über einen Frame hinter der Simulation zu rendern und zwischen diskreten bekannten Positionen zu interpolieren.
Wenn Sie einige Details zur Implementierung sehen möchten, habe ich hier bereits einen kurzen Abschnitt zu diesem Thema in einem Artikel geschrieben . Bitte lesen Sie den Abschnitt "Timestepping".
Hier ist der wichtige Pseudocode aus dem Artikel:
Die
RenderGame
Funktion ist von größtem Interesse. Die Idee ist, Interpolation zwischen diskreten Simulationspositionen zu verwenden. Der Rendering-Code kann eigene Kopien der schreibgeschützten Simulationsdaten erstellen und zum Rendern einen temporären interpolierten Wert verwenden. Dies gibt Ihnen eine sehr reibungslose Bewegung ohne dumme Probleme wie das, was Sie zu haben scheinen!quelle