Timebased Movement: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
K (Konstant Beschleunigte Bewegung)
(Bild 1? :D, ansonsten Korrektur gelesen)
Zeile 6: Zeile 6:
 
Nehmen wir an wir möchten einen Ball darstellen der sich mit konstanter Geschwindigkeit vom linken Bildschirmrand zum rechten Bildschirmrand bewegt.
 
Nehmen wir an wir möchten einen Ball darstellen der sich mit konstanter Geschwindigkeit vom linken Bildschirmrand zum rechten Bildschirmrand bewegt.
  
Das erste Bild wird den Ball ganz links zeigen. Auf dem nächsten Bild wird der Ball ein stück weiter sein, die Frage ist nur wie weit? Die Länge der Strecke die der Ball zurücklegen muss legen wir nun mal willkürlich auf 1 Längeneinheit (kurz: LE) fest. Die Strecke soll er in 5 Sekunden zurück legen.
+
Das erste Bild wird den Ball ganz links zeigen. Auf dem nächsten Bild wird der Ball ein Stück weiter sein, die Frage ist nur wie weit? Die Länge der Strecke die der Ball zurücklegen muss legen wir nun mal willkürlich auf 1 Längeneinheit (kurz: LE) fest. Die Strecke soll er in 5 Sekunden zurück legen.
  
 
Ein Rechner A braucht 1 Sekunde um 1 Bild zu Berechnen. Um das gewünschte Ergebnis zu erreichen müssten wir den Ball nach jedem Bild 0.2 Felder weiterbewegen.
 
Ein Rechner A braucht 1 Sekunde um 1 Bild zu Berechnen. Um das gewünschte Ergebnis zu erreichen müssten wir den Ball nach jedem Bild 0.2 Felder weiterbewegen.
Zeile 33: Zeile 33:
 
* Bild 10: Ball Position: 1.0 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
 
* Bild 10: Ball Position: 1.0 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  
Bei dem einen Rechner muss der Ball bei jedem Bild um 0.2 LE bewegt werden, beim andern Rechner nur 0.1 LE pro Bild.     Tut man dies nicht, bewegt sich der Ball zu schnell oder zu langsam.  
+
Bei dem einen Rechner muss der Ball bei jedem Bild um 0.2 LE bewegt werden, beim andern Rechner nur 0.1 LE pro Bild. Tut man dies nicht, bewegt sich der Ball zu schnell oder zu langsam.  
  
 
Doch woher weiß man nun wie weit man seinen Ball auf den jeweiligen Rechner pro Bild bewegen muss?
 
Doch woher weiß man nun wie weit man seinen Ball auf den jeweiligen Rechner pro Bild bewegen muss?
  
In unserem Beispiel bewegt sich der ball mit der konstanten Geschwindigkeit von 0.2 LE pro Sekunde. Mit folgender Formel können wir bei konstanter Geschwindigkeit die neue Position berechnen:
+
In unserem Beispiel bewegt sich der Ball mit der konstanten Geschwindigkeit von 0.2 LE pro Sekunde. Mit folgender Formel können wir bei konstanter Geschwindigkeit die neue Position berechnen:
  
  neue_Position = Geschwindigkeit*vergangene_Zeit + alte_Position
+
  neue_Position = Geschwindigkeit * vergangene_Zeit + alte_Position
  
 
Wir brauchen also nur eine Geschwindigkeit festlegen und messen wieviel Zeit vergangen ist um die neue Position zu berechnen zu können.
 
Wir brauchen also nur eine Geschwindigkeit festlegen und messen wieviel Zeit vergangen ist um die neue Position zu berechnen zu können.
Zeile 48: Zeile 48:
  
 
Allgemein:
 
Allgemein:
  VergangeneZeit:= (Zeit1-Zeit0)/Frequenz;
+
  VergangeneZeit := ( Zeit1 - Zeit0 ) / Frequenz;
  
 
=== Millisekunden genau unter Windows===
 
=== Millisekunden genau unter Windows===
Zeile 56: Zeile 56:
 
//Benötigte Variablen
 
//Benötigte Variablen
 
var
 
var
   BerechnungsZeit:LongWord;
+
   BerechnungsZeit : LongWord;
   Position:Double;
+
   Position       : Double;
  
procedure BeimStart;//Was hier drinnen steht sollte zum Start ausgeführt werden
+
procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden
 
begin
 
begin
 
   BerechnungsZeit := GetTickCount();
 
   BerechnungsZeit := GetTickCount();
 
end;
 
end;
  
procedure BerechnungsCheck;//Alle nötigen Berechnungen durchführen
+
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen
 
const
 
const
   Frequenz=1000;//Durch Windows festgelegt
+
   Frequenz = 1000; // Durch Windows festgelegt
 
var
 
var
   AktuelleZeit:LongWord;
+
   AktuelleZeit : LongWord;
 
begin
 
begin
 
   AktuelleZeit := GetTickCount();
 
   AktuelleZeit := GetTickCount();
   Berechne((AktuelleZeit - BerechnungsZeit) /Frequenz);
+
   Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);
 
   BerechnungsZeit := AktuelleZeit;
 
   BerechnungsZeit := AktuelleZeit;
 
end;
 
end;
  
procedure Berechne(vergangene_Zeit:Double);
+
procedure Berechne(vergangene_Zeit : Double);
 
const
 
const
 
   Geschwindigkeit = 0.5;
 
   Geschwindigkeit = 0.5;
Zeile 81: Zeile 81:
 
   {Alle Berechnungen stehen hier }
 
   {Alle Berechnungen stehen hier }
 
   // z.B.
 
   // z.B.
   Position := Geschwindigkeit*vergangene_Zeit + Position;
+
   Position := Geschwindigkeit * vergangene_Zeit + Position;
 
end;
 
end;
 
</pascal>
 
</pascal>
  
 
=== Absolute Genauigkeit per Hardware ===
 
=== Absolute Genauigkeit per Hardware ===
Man kann auch die Hardware zur Zeitmessung nutzen um so noch genauere Ergebnisse zu erziehlen. Es kann jedoch theoretisch sein(auch jetzt noch?), dass diese nicht zur verfügung steht.
+
Man kann auch die Hardware zur Zeitmessung nutzen um so noch genauere Ergebnisse zu erziehlen. Es kann jedoch theoretisch sein, dass diese nicht zur Verfügung steht.
 
<pascal>
 
<pascal>
 
//Benötigte Variablen
 
//Benötigte Variablen
 
var
 
var
   BerechnungsZeit:Int64;
+
   BerechnungsZeit : Int64;
   Frequenz:Int64;
+
   Frequenz       : Int64;
   Position:Double;
+
   Position       : Double;
  
procedure BeimStart;//Was hier drinnen steht sollte zum Start ausgeführt werden
+
procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden
 
begin
 
begin
   if not QueryPerformanceFrequency(Frequenz) then//Frequenz ermitteln
+
   if not QueryPerformanceFrequency(Frequenz) then // Frequenz ermitteln
 
   raise Exception.create('Kein Hardware Timer vorhanden');
 
   raise Exception.create('Kein Hardware Timer vorhanden');
   QueryPerformanceCounter(BerechnungsZeit);//Aktuelle Zeit ermitteln
+
   QueryPerformanceCounter(BerechnungsZeit); // Aktuelle Zeit ermitteln
 
end;
 
end;
procedure BerechnungsCheck;//Alle nötigen Berechnungen durchführen
+
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen
 
var
 
var
   AktuelleZeit:Int64;
+
   AktuelleZeit : Int64;
 
begin
 
begin
 
   QueryPerformanceCounter(AktuelleZeit);
 
   QueryPerformanceCounter(AktuelleZeit);
   Berechne((AktuelleZeit - BerechnungsZeit) /Frequenz);
+
   Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);
 
   BerechnungsZeit := AktuelleZeit;
 
   BerechnungsZeit := AktuelleZeit;
 
end;
 
end;
procedure Berechne(vergangene_Zeit:Double);
+
procedure Berechne(vergangene_Zeit : Double);
 
const
 
const
 
   Geschwindigkeit = 0.5;
 
   Geschwindigkeit = 0.5;
Zeile 114: Zeile 114:
 
   {Alle Berechnungen stehen hier }
 
   {Alle Berechnungen stehen hier }
 
   // z.B.
 
   // z.B.
   Position := Geschwindigkeit*vergangene_Zeit + Position;
+
   Position := Geschwindigkeit * vergangene_Zeit + Position;
 
end;
 
end;
 
</pascal>
 
</pascal>
Zeile 120: Zeile 120:
 
== Konstant Beschleunigte Bewegung ==
 
== Konstant Beschleunigte Bewegung ==
  
Nehmen wir an wir möchten darstellen wie ein Ball zu Boden fällt. Der Ball sei 1 LE über dem Boden und wird dort zum Zeitpunkt 0s losgelassen. Die Kraft welche die Erdanziehung simuliert soll pro Sekunde die Geschwindigkeit des Ballesum 1 LE/s erhöhen.
+
Nehmen wir an wir möchten darstellen wie ein Ball zu Boden fällt. Der Ball sei 1 LE über dem Boden und wird dort zum Zeitpunkt 0s losgelassen. Die Kraft welche die Erdanziehung simuliert soll pro Sekunde die Geschwindigkeit des Balles um 1 LE/s erhöhen.
  
  
 
Die neue Geschwindigkeit die sich durch die Beschleunigung ergeben hat, läßt sich noch sehr einfach Berechnen:
 
Die neue Geschwindigkeit die sich durch die Beschleunigung ergeben hat, läßt sich noch sehr einfach Berechnen:
  neue_Geschwindigkeit := Beschleunigung*vergangene_Zeit + alte_Geschwindigkeit;
+
  neue_Geschwindigkeit := Beschleunigung * vergangene_Zeit + alte_Geschwindigkeit;
  
 
Wie sieht es aber mit der Position aus?
 
Wie sieht es aber mit der Position aus?
  
falsch wäre diese Berechnung:
+
Falsch wäre diese Berechnung:
  neue_Position := alte_Geschwindigkeit*vergangene_Zeit + alte_Position
+
  neue_Position := alte_Geschwindigkeit * vergangene_Zeit + alte_Position
 
Denn so würde sich der Ball in unserm Beispiel nach der ersten Sekunde noch gar nicht bewegt haben.
 
Denn so würde sich der Ball in unserm Beispiel nach der ersten Sekunde noch gar nicht bewegt haben.
  
genauso falsch wäre diese Berechnung:
+
Genauso falsch wäre diese Berechnung:
  neue_Position := neue_Geschwindigkeit*vergangene_Zeit + alte_Position
+
  neue_Position := neue_Geschwindigkeit * vergangene_Zeit + alte_Position
  
Denn dann würde sich der ball sofort mit der vollen Geschwindigkeit bewegen und würde im Bild 1 unseres Beispieles schon am Boden sein.
+
Denn dann würde sich der Ball sofort mit der vollen Geschwindigkeit bewegen und würde im Bild 1 unseres Beispieles schon am Boden sein.
  
 
Wer sich ein wenig mit Physik auskennt weiß das man bei konstant Beschleunigter Bewegung so die neue Position ausrechnet:
 
Wer sich ein wenig mit Physik auskennt weiß das man bei konstant Beschleunigter Bewegung so die neue Position ausrechnet:
  neue_Position := Beschleunigung*vergangene_Zeit*vergangene_Zeit + Geschwindigkeit*vergangene_Zeit + alte_Position
+
  neue_Position := Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + alte_Position
  
 
Beispielcode:
 
Beispielcode:
 
<pascal>
 
<pascal>
 
var
 
var
   Position: Double;
+
   Position       : Double;
   Geschwindigkeit: Double;
+
   Geschwindigkeit : Double;
procedure Berechne(vergangene_Zeit:Double);
+
procedure Berechne(vergangene_Zeit : Double);
 
const
 
const
 
   Beschleunigung = 1;
 
   Beschleunigung = 1;
 
begin
 
begin
   Position := Beschleunigung*vergangene_Zeit*vergangene_Zeit + Geschwindigkeit*vergangene_Zeit + Position
+
   Position := Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + Position
   // wichtig: alte geschwindigkeit erst ändern wenn sie nicht mehr gebraucht wird.
+
   // Wichtig: alte Geschwindigkeit erst ändern wenn sie nicht mehr gebraucht wird.
   Geschwindigkeit := Beschleunigung*vergangene_Zeit + Geschwindigkeit
+
   Geschwindigkeit := Beschleunigung * vergangene_Zeit + Geschwindigkeit
 
end;
 
end;
 
</pascal>
 
</pascal>

Version vom 19. August 2006, 17:31 Uhr

Kurz-Beschreibung

Timebased Movement sorgt dafür, dass die Bewegungsgeschwindigkeiten nicht vom CPU-/Renderspeed abhängen.


Prinzip

Nehmen wir an wir möchten einen Ball darstellen der sich mit konstanter Geschwindigkeit vom linken Bildschirmrand zum rechten Bildschirmrand bewegt.

Das erste Bild wird den Ball ganz links zeigen. Auf dem nächsten Bild wird der Ball ein Stück weiter sein, die Frage ist nur wie weit? Die Länge der Strecke die der Ball zurücklegen muss legen wir nun mal willkürlich auf 1 Längeneinheit (kurz: LE) fest. Die Strecke soll er in 5 Sekunden zurück legen.

Ein Rechner A braucht 1 Sekunde um 1 Bild zu Berechnen. Um das gewünschte Ergebnis zu erreichen müssten wir den Ball nach jedem Bild 0.2 Felder weiterbewegen.

In einer Sekunde hätten wir also folgende Bilder:

  • Bild 0: Ball Position: 0.0
  • Bild 1: Ball Position: 0.2 (weiterbewegt um 0.2 LE in 1.0 Sekunden)
  • Bild 2: Ball Position: 0.4 (weiterbewegt um 0.2 LE in 1.0 Sekunden)
  • Bild 3: Ball Position: 0.6 (weiterbewegt um 0.2 LE in 1.0 Sekunden)
  • Bild 4: Ball Position: 0.8 (weiterbewegt um 0.2 LE in 1.0 Sekunden)
  • Bild 5: Ball Position: 1.0 (weiterbewegt um 0.2 LE in 1.0 Sekunden)

Ein Rechner B braucht nur 0.5 Sekunden um ein Bild zu berechnen.

Ebenfalls in nur einer Sekunde hätten wir folgende Bilder:

  • Bild 0: Ball Position: 0.0
  • Bild 1: Ball Position: 0.1 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 2: Ball Position: 0.2 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 3: Ball Position: 0.3 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 4: Ball Position: 0.4 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 5: Ball Position: 0.5 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 6: Ball Position: 0.6 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 7: Ball Position: 0.7 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 8: Ball Position: 0.8 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 9: Ball Position: 0.9 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)
  • Bild 10: Ball Position: 1.0 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)

Bei dem einen Rechner muss der Ball bei jedem Bild um 0.2 LE bewegt werden, beim andern Rechner nur 0.1 LE pro Bild. Tut man dies nicht, bewegt sich der Ball zu schnell oder zu langsam.

Doch woher weiß man nun wie weit man seinen Ball auf den jeweiligen Rechner pro Bild bewegen muss?

In unserem Beispiel bewegt sich der Ball mit der konstanten Geschwindigkeit von 0.2 LE pro Sekunde. Mit folgender Formel können wir bei konstanter Geschwindigkeit die neue Position berechnen:

neue_Position = Geschwindigkeit * vergangene_Zeit + alte_Position

Wir brauchen also nur eine Geschwindigkeit festlegen und messen wieviel Zeit vergangen ist um die neue Position zu berechnen zu können.

Wohlgemerkt gilt diese Formel nur wenn sich das Objekt mit konstanter Geschwindigkeit fortbewegt.

Berechnung der vergangen Zeit

Allgemein:

VergangeneZeit := ( Zeit1 - Zeit0 ) / Frequenz;

Millisekunden genau unter Windows

Die wohl einfachste aber auch ungenaueste Möglichkeit unter Windows so etwas zu realisieren besteht darin mit Hilfe von GetTickCount die Zeit (in Millisekunden) seit dem letzen Windows-Start zu ermitteln.

//Benötigte Variablen
var
  BerechnungsZeit : LongWord;
  Position        : Double;

procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden
begin
  BerechnungsZeit := GetTickCount();
end;

procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen
const
  Frequenz = 1000; // Durch Windows festgelegt
var
  AktuelleZeit : LongWord;
begin
  AktuelleZeit := GetTickCount();
  Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);
  BerechnungsZeit := AktuelleZeit;
end;

procedure Berechne(vergangene_Zeit : Double);
const
  Geschwindigkeit = 0.5;
begin
  {Alle Berechnungen stehen hier }
  // z.B.
  Position := Geschwindigkeit * vergangene_Zeit + Position;
end;

Absolute Genauigkeit per Hardware

Man kann auch die Hardware zur Zeitmessung nutzen um so noch genauere Ergebnisse zu erziehlen. Es kann jedoch theoretisch sein, dass diese nicht zur Verfügung steht.

//Benötigte Variablen
var
  BerechnungsZeit : Int64;
  Frequenz        : Int64;
  Position        : Double;

procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden
begin
  if not QueryPerformanceFrequency(Frequenz) then // Frequenz ermitteln
   raise Exception.create('Kein Hardware Timer vorhanden');
  QueryPerformanceCounter(BerechnungsZeit); // Aktuelle Zeit ermitteln
end;
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen
var
  AktuelleZeit : Int64;
begin
  QueryPerformanceCounter(AktuelleZeit);
  Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);
  BerechnungsZeit := AktuelleZeit;
end;
procedure Berechne(vergangene_Zeit : Double);
const
  Geschwindigkeit = 0.5;
begin
  {Alle Berechnungen stehen hier }
  // z.B.
  Position := Geschwindigkeit * vergangene_Zeit + Position;
end;

Konstant Beschleunigte Bewegung

Nehmen wir an wir möchten darstellen wie ein Ball zu Boden fällt. Der Ball sei 1 LE über dem Boden und wird dort zum Zeitpunkt 0s losgelassen. Die Kraft welche die Erdanziehung simuliert soll pro Sekunde die Geschwindigkeit des Balles um 1 LE/s erhöhen.


Die neue Geschwindigkeit die sich durch die Beschleunigung ergeben hat, läßt sich noch sehr einfach Berechnen:

neue_Geschwindigkeit := Beschleunigung * vergangene_Zeit + alte_Geschwindigkeit;

Wie sieht es aber mit der Position aus?

Falsch wäre diese Berechnung:

neue_Position := alte_Geschwindigkeit * vergangene_Zeit + alte_Position

Denn so würde sich der Ball in unserm Beispiel nach der ersten Sekunde noch gar nicht bewegt haben.

Genauso falsch wäre diese Berechnung:

neue_Position := neue_Geschwindigkeit * vergangene_Zeit + alte_Position

Denn dann würde sich der Ball sofort mit der vollen Geschwindigkeit bewegen und würde im Bild 1 unseres Beispieles schon am Boden sein.

Wer sich ein wenig mit Physik auskennt weiß das man bei konstant Beschleunigter Bewegung so die neue Position ausrechnet:

neue_Position := Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + alte_Position

Beispielcode:

var
  Position        : Double;
  Geschwindigkeit : Double;
procedure Berechne(vergangene_Zeit : Double);
const
  Beschleunigung = 1;
begin
  Position := Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + Position
  // Wichtig: alte Geschwindigkeit erst ändern wenn sie nicht mehr gebraucht wird.
  Geschwindigkeit := Beschleunigung * vergangene_Zeit + Geschwindigkeit
end;

Links