Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

daG

Treue Seele

Beiträge: 130

Wohnort: Hamburg

  • Private Nachricht senden

71

18.02.2011, 21:49

Das Problem ist doch folgendes:

Wenn du jetzt z.B. eine Beschleunigung hast könnte es evtl so aussehen:

speed = 10;
acceleration = 1;

positionX = speed * time * acceleration;
acceleration = acceleration * time * 100;

jetzt stellen wir uns 2 Szenarien vor.

Szenario 1:

wir haben 20 Frames mit jeweils 10ms.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
Frame 1 (nach 10ms):
positionX = 10 * 0.01 * 1 => 0.1
acceleration = 1 + 0.01 * 100 => 2

Frame 2 (nach 20ms):
positionX = 10 * 0.01 * 2 => 0.2
acceleration = 2 + 0.01 * 100 => 3
...
Frame 20: (nach 200ms):
positionX = 10 * 0.01 * 20 => 2.0
acceleration = 20 + 0.01 * 100 => 21


Szenario 2:

wir haben 2 Frames mit jeweils 100ms.

Quellcode

1
2
3
4
5
6
7
Frame 1: (nach 100ms):
positionX = 10 * 0.1 * 1 => 1.0
acceleration = 1 + 0.1 * 100 => 11

Frame 2: (nach 200ms):
positionX = 10 * 0.1 * 11 => 11.0
acceleration = 11 + 0.1 * 100 => 21


Es ist die selbe Zeit vergangen aber wir haben bei Szenario 1 positionX == 2.0 und bei Szenario 2 positionX == 11.0

Das Problem ist halt, das die Beschleunigung bei 2 nicht langsam angestiegen ist wie bei 1.

Ich glaub es rallt wieder keiner, aber ich habs wenigstens versucht :D

72

18.02.2011, 23:20

Ja, musste halt n Integral benutzen.
Die Rechnung ist übrigens komisch. Du müsstest Speed mit der Zeit verändern und Acceleration nur, wenn diese nicht konstant ist (sonst wirds noch ne Stufe komplizierter)

Also mal sehen. Ist die Geschwindigkeit konstant ist die Strecke einfach die Zeit mal die Geschwindigkeit. Eigentlich ist sie aber das Integral über die Geschwindigkeit/Zeit Funktion, ist hier aber netterweise das selbe.
Jetzt steigt die Geschwindigkeit aber an, sagen wir mal als Gerade. Der Graph Strecke/Zeit ist jetzt eine Parable, der Graph Geschwindigkeit/Zeit einer Gerade. Du musst die Gerade aber integrieren.
Was du stattdessen machst, ist die Geschwindigkeit/Zeit Funktion in diskreten Abständen abzutasten, du hast also in Wirklichkeit keine Gerade mehr, sondern eine Treppenfunktion. Je niedriger die Frequenz, desto länger die Treppenstufen und desto mehr Fläche geht zwischen Treppe und tatsächlichem Graph verloren. Je länger also die Zeitabstände, desto langsamer bist du.
Wenn du das Integral benutzt, bist du schneller als sonst imemr, da sich die Abtastung bei imemr kürzeren Abständen an das Integral rantastet.
Da du dich jetzt iterativ bewegst, nimmst du also das Integral vom letzten Zeitpunkt bis zum aktuellen über die Geschwindigkeit/Zeit Funktion und schon stimmt es (das gilt IMMER, egal ob die Geschwindigkeit konstant ist, linear wächst, ne Parabel ist, oder was total verrücktes, nur bei letzterem könntest du Probleme haben, das Integral zu bestimmen)


Achja, das Selbe Problem hast du auch bei konstanter Framerate, nur da isses dann halt konstant falsch.
Lieber dumm fragen, als dumm bleiben!

daG

Treue Seele

Beiträge: 130

Wohnort: Hamburg

  • Private Nachricht senden

73

19.02.2011, 01:26

Ja, es ist ein doofes Beispiel, aber es war jetzt das einzige was mir einfiel um es zu erklären. Ich hab bis jetzt das Problem auch noch nicht gehabt, bin ja noch bei meinem ersten Spiel :)

Die Frage ist halt ob man alle Probleme theoretisch mit einer Formel lösen kann, ohne das die Zeit konstant ist. Beil der iterativen Lösung ist es wenigstens gleichmäßig, wenn in diesem Beispiel auch falsch ^^

Und wie machen die anderen das? Ich denke spätestens wenn man das Spiel als Replay speichern möchte braucht man eine virtuelle Zeit, aber ich lasse mich da auch gerne eines besseren belehren :)

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

74

19.02.2011, 02:41

Eine sehr einfache Variante wäre:
current_step_count = (currenttime - starttime) / step_width;

while(obj.step_count < current_step_count)
obj.update(step_width)
obj.step_count++
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

75

19.02.2011, 09:40

Ja, musste halt n Integral benutzen.

Was bei konstanter Beschleunigung eines physikalischen Systems eben wieder auf
d = t * ( v0 + 0.5 * t * a )
hinausläuft.
Die Intervalle sind dann Wurscht, das Ergebnis stimmt, weil es nicht iterativ ist. Und ja, das geht nicht bei jeder Simulation. Sehr viele lassen sich aber auf eine ähnliche Weise ausdrücken (auch inklusive Reibungsverluste/Dämpfungen, Rotationen, etc). Egal welche Anzahl Zwischen-Steps man nimmt, das Ergebnis stimmt bei jeder Wahl. Auch eine super langsame Zeitlupen-Darstellung bei 150 FPS wird da wirds aus dem Ruder laufen lassen.

Instabil wird es nur durch die Vorgabe eines Systems mit sehr hoher Interaktionsrate (beispielsweise eine Krabbel-Kiste voller Plastik-Bälle). Diese Problemstellung ist aber generell problematisch, egal mit welchem Ansatz. Ein Fußball-Game, Strategiespiel oder Billard beispielsweise ließe sich aber sehr gut und stabil mit dem obigen Ansatz zur Bestimmung von Objekt-Positionen in Abhängigkeit der verstrichenen Gesamtzeit berechnen. Er muss wie gesagt nur um die nötigen Variablen erweitert werden.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

76

19.02.2011, 11:43

Die Intervalle sind dann Wurscht, das Ergebnis stimmt, weil es nicht iterativ ist.

Moment, die Position kann ja auch mit der korrekten Formel iterativ berechnet werden. Also wenn man in jedem Frame nur die letzte Position und die letzte Geschwindigkeit hat kann man anhand der vergangenen Zeit die neue Geschwindigkeit bzw. die zurückgelegte Strecke seit dem letzten Frame ausrechnen (man kann ja das Integral von [0; t] ausrechnen und das nehmen oder von [t-1; t] und das dann auf die alte Position addieren). Wenn man nicht das Integral benutzt, sind die Ergebnisse nicht falsch, weil numerisch instabil, sondern weil einfach die Formel falsch ist.
Lieber dumm fragen, als dumm bleiben!

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

77

19.02.2011, 15:56

@Jonathan_Klein
eben nicht! Es ist instabil, weil kleine Fehler sich pro Durchlauf weiter aufschaukeln! Eigentlich alles was iterativ arbeitet ist irgendwann instabil. Der Trick bei den fixedtimesteps ist einfach, dass es immer in die gleiche Richtung "abhaut", während es bei flexiblen Schritten beliebig variieren kann.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

78

19.02.2011, 20:45

Fixed Timestep ist doch nicht das Gegenteil von Iterativ. Oder wir haben gänzlich andere Vorstellungen, was die Wörter bedeuten.

Ums mal deutlich aufzuschreiben:

Iterativ: NeuePosition=LetztePosition+ZeitSeitLetztemFrame*Geschwindigkeit
Direkt (oder wie auch imemr mans nennen will): NeuePosition=StartPosition+(StartZeit-AktuelleZeit)*Geschwindigkeit

Variable Framerate: Zeit messen
KonstanteFramerate (fixed TimeStep): nach jedem Frame warten, so dass alle gleich lang brauchen.

Man kann das jetzt beliebig kombinieren.
Bei Iterativ addieren sich Fehler natürlich auf. Bei der direkten Berechnung muss man dafür immer die Startposition und die Startzeit speichern und natürlich ändern, wenn sich z.B: die Bewegungsrichtung ändert.

So, nehmen wir an, der Spieler steuert eine Figur. Ob er jetzt die Rechttaste bei 50FPS eine Frame früher oder später drückt, ist ziemlich egal. Da er eh oft die Richtung ändern wird, können die Fehler sich gar nicht so schnell addieren, dass das nicht vollkommen irrelevant gegenüber den ungleichmäßigen Spielereingaben sein würde (Eine Vernünftige Framerate vorausgesetzt). Außerdem muss man bei der Direkten Bewegung bei jeder Eingabe vom Spieler die Startwerte ändern, also alle paar Sekunden.
Bei Gegnern ist es ähnlich. Wenn die zum Spieler hinlaufen wollen, ändert sich deren Startbedingungen auch ständig.

Meiner Meinung nach ist die Direkte Berechnung aufwändiger, aber genauer; und daher für wirklcih extreme Fälle eine Überlegung wert, aber in den meisten Fällen wird es einfach keinen Unterschied machen.
Lieber dumm fragen, als dumm bleiben!

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

79

19.02.2011, 20:51

Aufwendiger ist die Berechnung über absolute Zeit keines Falls. Beide Ansätze brauchen schließlich die gleiche Anzahl eingehender Parameter. Wenn irgendwelche Parameter nicht gebraucht würden, könnte man sie schließlich weglassen:
x += frameTime*speed;
x = totalTime*speed;
x += frameTime*(speed + 0.5*accel);
x = totalTime*(speed + 0.5*accel);
Die einzig kürzere Variante wäre:
x += const;

Iterativ ist aber natürlich alles, was bei der Berechnung für Frame x auf die Ergebnisse aus Frame x-1 zugreift und wie Nox schon sagte addieren sich dabei ständig die numerischen Fehler immer weiter auf. Und die können auch schon bei 50-150 Frames imense Ausmaße annehmen, die nicht in jedem Fall tolerierbar sein müssen. Klar, als Steuerung einer Spiel-Figur wie bei einem Shooter macht es nichts. Aber bei einer abgefeuerten Kugel ist es schon relevant, ob sie verfehlt, obwohl sie treffen sollte oder ob sie tatsächlich trifft!

"Ständig" ändert sich da weder die Startbedingung für Spieler, noch für KI-Gegner. Eine Änderung alle 50-150 Frames bedeutet immerhin, dass man sich die Fehler von 50 bis 150 (irgendwas zwischen 0.5 und 5 Sekunden) Frames komplett geschenkt hat.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »BlueCobold« (19.02.2011, 20:58)


Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

80

20.02.2011, 01:24

Fixed Timestep ist doch nicht das Gegenteil von Iterativ

Habe ich jemals was anderes behauptet? ;)
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Werbeanzeige