Autor Beitrag
rushifell
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Mo 30.10.06 17:01 
Hallo,

Ich habe mit Hilfe von SDL ein Spiel in Delphi programmiert. Die Engine ist fast fertig, die Level zum Großteil spielbar. Da dies mein erstes Spiel ist, habe ich mich zuvor noch nie mit dem Geschwindigkeitsproblem bei Spielen beschäftigt. Ich möchte gerne, dass das Spiel auf jedem Rechner mit etwa gleicher Geschwindigkeit läuft. Das Problem ist hierbei nicht, dass das Spiel zu langsam, nein im Gegenteil, dass das Spiel auf manchen PCs einfach zu schnell ist. Das SDL_Delay habe ich komplett entfernt, da es nur zu einem ruckelnden Spielfluss führte. Ohne SDL_Delay läuft das Spiel sauber und ruckelfrei mit konstanter Geschwindigkeit, aber eben je nach PC unterschiedlich schnell.

Ich habe vom Timebased-Movement gelesen, das sehr interessant klingt und das ich auch ausprobieren werde. Hierbei wird die Anzahl der Pixel, um die das Bild verschoben wird, von der Geschwindigkeit abhängig gemacht. Meine Frage, gibt es weitere Methoden, um die Spielgeschwindigkeit zu kontrollieren? Wie handhabt ihr das bei Spieleprogrammierung?

cu
rushifell
Phobeus
ontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1280

Linux (FC6), WinXP Pro (Box)
D6 Pers, D7 Pro, FPC 2.x
BeitragVerfasst: Mi 01.11.06 08:14 
TimeBasedMovement ist eigentliche das Maß aller Dinge um sinnvoll und effizient frameunabhängige Bewegungen zu ermöglichen. Das Prinzip hat sich bereits seid Jahrzehnten bewert und tut es ebenfalls immer noch. Andere sinnvolle Methoden jenseits des Voodoos sind mir nicht bekannt.

Aber: Die Berechnung sollte nicht in Form von Pixeln erfolgen, sondern mit Hilfe eines Floats. "Pixel" sind exakt so genau, wie das menschliche Auge die Information verarbeitet, was einen bei der Geschwindigkeit doch arg einschränkt. Mindestengeschwindigkeit von einem Pixel könnte schon für viele Sachen "recht schnell" sein. Verwende daher bei SPielen stets für die Berechnung Floats, um diese dann erst beim Rendern auf eine pixelbasis zu bekommen. Auf diese Weise kannst Du wesentlich feinere Bewegungen berechnen als eine rein auf pixel basierende Lösung.

Und: Gute Wahl mit SDL ;)

_________________
"Menschen sterben nicht wenn man sie zu Grabe trägt, sondern wenn sie ihre Träume verlieren..."
rushifell Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Mi 01.11.06 21:46 
Genau das wollte ich wissen. Danke für Deine Antwort! Dann werd ich mal versuchen, ein Timebased Movement zu implementieren. Sollte wohl nicht allzuschwer sein.

Bin mit SDL auch mehr als zufrieden :-)

Gruß
rushifell
rushifell Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Fr 05.02.10 06:58 
Hallo,

ich grabe mal diesen alten Thread aus, da es sich um die gleiche Problematik handelt. Nachdem ich die Pixel-Variante ausprobiert hatte, habe ich mich letztendlich doch für die Timer-Variante entschieden. Mein Spiel hat sowieso eine geringe Bildschirm-Auflösung und mit einem Timer ist es einfach wesentlich leichter umzusetzten.

Nun habe ich mich in den letzten Tagen daran gemacht, mein Spiel zu tunen, also so wenig ruckeln wie nur möglich. Bei maximaler Geschwindigkeit läuft das Spiel schön flüssig, aber eben auf manchen PC's leider zu schnell. Deshalb muss ich das Spiel auf schnelleren PC's drosseln, was aber leider zu diesem nervigen Ruckeln führt.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure Init_Query;
begin
  QueryLogTime:=0;
  if not QueryPerformanceFrequency(Frequenz) then               //Frequenz wird ermittelt
     raise Exception.create('Kein Hardware Timer vorhanden');
  QueryPerformanceCounter(QueryLogTime);                        // Aktuelle Zeit ermitteln
end;


Alte Variante:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure Wait_Query(ms:Integer); //Warteschleife, ms = Zeit in Millisekunden
var
  AktuelleZeit : Int64;
  PositionX:Double;
begin
  Repeat     
   QueryPerformanceCounter(AktuelleZeit);
   Positionx:=((AktuelleZeit-QueryLogTime)/Frequenz)*1000;
  Until PositionX>=Ms;

 QueryLogTime := AktuelleZeit;
end;


Neue Variante:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure Wait_Query(ms:Integer); //Warteschleife, ms = Millisekunden
var
  AktuelleZeit : Int64;
begin
  Repeat    
   QueryPerformanceCounter(AktuelleZeit);
  Until (AktuelleZeit-QueryLogTime)*1000 >= Ms*Frequenz;

 QueryLogTime:=Round(Ms*Frequenz/1000)+QueryLogTime;
end;


Hier die Schleife im Spiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Init_Query
Repeat
 //Hier werden Berechnungen für das Spiel durchgeführt
 Wait_Query(17);
UpdateScreen; //Hier wird gezeichnet

Until Quit;


Der wesentliche Unterschied zwischen der alten und neuen Variante besteht in folgendem:

In der alten Variante hatte ich Wait_Query(17) noch nach UpdateScreen (also nach dem Zeichnen) stehen. In Wait_Query hatte ich immer mit der aktuellen Zeit weiter gerechnet, in der neuen Variante immer ausgehend von der Zeit, die in Init_Query berechnet wurde. Ich erhoffe mit dadurch ein "konstanteres" Zeichnen der Bildschirmausgabe.

Was denkt ihr darüber? Gibt es noch bessere Möglichkeiten? Würde mich freuen, wenn ihr mir noch Tipps geben könntet :-) Danke schonmal.

rushifell

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 06.02.10 15:41 
Ja. Time Based Movement verwenden ;-)

Ferner: Die Zeitbasis wird nicht von der Warteroutine festgelegt, sondern von der Hauptschleife. Damit wird das um einiges Regelmäßiger.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
rushifell Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Sa 06.02.10 15:59 
Hi, danke für Deine Antwort: :-)

Wird das mit TimeBased Movement wirklich flüssiger? Ich habe nur eine Auflösung von 320*240 Pixel.

Zitat:

Die Zeitbasis wird nicht von der Warteroutine festgelegt, sondern von der Hauptschleife.

Ich verstehe nicht ganz, wie Du das genau meinst? Könntest Du das bitte noch genauer erläutern? Danke.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 06.02.10 16:06 
user profile iconrushifell hat folgendes geschrieben Zum zitierten Posting springen:
Hi, danke für Deine Antwort: :-)

Wird das mit TimeBased Movement wirklich flüssiger? Ich habe nur eine Auflösung von 320*240 Pixel.

Ja, wird es.

user profile iconrushifell hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:

Die Zeitbasis wird nicht von der Warteroutine festgelegt, sondern von der Hauptschleife.

Ich verstehe nicht ganz, wie Du das genau meinst? Könntest Du das bitte noch genauer erläutern? Danke.

Derzeit wartest du unabhängig von der für die BErechnungen beanspruchten Zeit immer 17ms, soweit ich das in deinem Source verstanden habe. Wenn aber die Berechnungen unterschiedlich schnell verlaufen, läuft dein Programm daher auf schnelleren Rechnern halt schneller.

Um das zu vermeiden, definiert man nicht feste Zeitschritte je Schleifendurchlauf, sondern berechnet die aktuelle Zeit im Spiel basierend auf der real verstrichenen Zeit und skaliert jegliche Bewegungen darauf aufbauend.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
rushifell Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Sa 06.02.10 16:58 
Auf meinem Rechner läuft das Spiel mit maximaler Geschwindigkeit und damit auch schön flüssig. Auf meinem PC ist die Zeitverzögerung also nicht notwendig. Erst wenn ich 18 oder 19 Millisekunden eingebe, wird das Spiel auch auf meinem Rechner langsamer.

Auf einem anderen PC ist das Spiel wesentlich schneller. Ich habe das Delay von 17 Millisekunden eingefügt, damit das Spiel annährend genauso schnell läuft, wie auf meinem Rechner. Bis diese 17 Millisekunden abgelaufen sind, brauche ich keine neue Berechnung mehr.

Wenn ich das TimebasedMovement richtig verstanden habe, sollte ich das dann besser mit einem Dreisatz lösen.
ausblenden Quelltext
1:
2:
x = y Millisekunden  //x Pixel Bewegung pro y Millisekunden
2 = 17 Millisekunden //2 Pixel Bewegung pro 17 Millisekunden

Ich gehe einfach mal von der Hypothese aus, dass der schnellere Rechner, für einen Schleifendurchlauf y Ms gebraucht hat.
ausblenden Quelltext
1:
2:
x/2 = y/17
x = Round(y*2/17);

Wenn also z.B. y=17ms verstrichen wären, würde sich das Objekt um zwei Pixel weiterbewegen. Wenn es y=9 ms wären,
9*2/17=18/17=1.05 => 1 Pixel? So ähnlich zumindest.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Sa 06.02.10 17:14 
Ja, so in etwa. Du hast eine Geschwindigkeit v und ermittelst bei jedem Schleifendurchlauf den Zeitabstand zum letzten Durchlauf, Δt. Dann kannst du Δx = v * Δt zur aktuellen Position des Objektes addieren.
Wie gesagt solltest du aber ausschließlich mit Floats rechnen; gerundet wird nur beim Anzeigen.

_________________
>λ=
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Sa 06.02.10 17:28 

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
rushifell Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: So 07.02.10 11:43 
Wow :oops:
Hammergeil 8)
Vielen Dank nochmal an Euch alle. Den Wiki-Link habe ich eigentlich schon gekannt, war bei mir aber in Vergessenheit geraten. Es ist wirklich, kein Vergleich zu vorher. Ich hätte nicht gedacht, dass die Bewegung so flüssig sein können. Ich habe extra die alte und neue Variante nochmal im Window- und Fullscreen-Mode verglichen.

Ich habe konsequent mit Variablen vom Typ Double gerechnet. Das Ergebnis gerundet und auf dem Bildschirm ausgegeben. Wenn ich mir das im Nachhinein überlege, wundert es mich nicht. Schließlich hab ich immer mit gerundeteten Werten weitergerechnet. Aber dass das Ergebnis so gut ist, hätte ich wirklich nicht erwartet.

Jetzt muss ich das ganze nur noch in mein Spiel einbauen, und wenn das Ergebnis genauso ist, dann lohnt sich's auch.

Würdet ihr immer Zeichnen, auch wenn sich nichts bewegt, also die Pixeldifferenz gerundet 0 ergibt.

Danke :D
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 07.02.10 13:48 
Jep. Würde ich machen, weil es die Logik im Programm vereinfacht und das Zeichnen i.d.R. wenig ausmacht. Zudem wollen insbesondere OpenGL und SDL ein halbwegs regelmäßiges Refresh haben.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
rushifell Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: So 07.02.10 17:13 
Danke :D