Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mo Jul 14, 2025 23:59

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 11 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: 2d: Bewegungen verlangsamen
BeitragVerfasst: Sa Mär 22, 2008 23:33 
Offline
DGL Member

Registriert: Mo Aug 15, 2005 19:29
Beiträge: 38
Guten Abend Community,
ich weiß nicht genau, wie ich mein Problem schildern soll und ich weiß auch, dass es nur eine Kleinigkeit ist, bei der ich leider nicht den Fehler finde.

Folgende Ausgangssituation:
Ich programmiere ein 2d Spiel und bin soweit mit dem Zeichnen der Karte fertig. Jetzt wollte ich mich an das Implementieren des Spielers machen, alles schön mit Klassen und drumrum. Geht soweit auch alles astrein; nur eine Sache bereitet mir kopfschmerzen. Da mein Spiel auf einem 32x32-Raster aufbaut, will ich, dass sich mein Character immer um 32px bewegt.

Beispiel, um den Spieler nach unten zu bewegen:
Code:
  1.  
  2.   if GetAsyncKeyState(vk_down) <> 0 then
  3.     Player1.MoveDown:=true;
  4.  
  5.   if Player1.MoveDown then begin
  6.     if MoveCounter>=32 then begin
  7.       Player1.MoveDown:=false;
  8.       MoveCounter:=0;
  9.     end else begin
  10.       Player1.pos.y:=Player1.pos.y+1;
  11.       inc(MoveCounter);
  12.     end;
  13.   end;
  14.  


Er wird solange um 1 Pixel verschoben, bis er auf einem anderen 32x32-Feld ist. Klappt soweit auch astrein - allerdings nur viel zu schnell. Ich vermute, dass sich das ganze mit Timebased Movement lösen lässt. Rumprobiert habe ich damit vorhin schon, allerdings war dann mein Speedfactor ab und zu <= 0.4, was durch abrunden zu 0 führt. Wenn ich jetzt Player1.pos.y:=Player1.pos.y+1*Speedfactor; mache und der Speedfactor, wie oben schon gesagt, <= 0.4 ist, wird der Spieler um 0 Pixel verschoben.

Kann mir jemand weiterhelfen? Ich hoffe, dass ich mich verständlich ausgedrückt habe, denn ich kann mein Problem nicht so gut beschreiben.

Schönen Abend noch,
Spessi


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 22, 2008 23:58 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ja, dein Problem ist klar und altbekannt.

Um erklären zu können, wie du Timebased Movement, solltest du mal zeigen, welche Methode du zum Rendern benutzt. Also ob OnIdle, ne Schleife oder Timer.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 00:01 
Offline
DGL Member

Registriert: Mo Aug 15, 2005 19:29
Beiträge: 38
Hallo Lord Horazont,
ich benutze das OpenGL 1.5 Template vom File-Bereich von DelphiGL.


Zur Zeit sieht das ganze bei mir so aus:

Code:
  1.  
  2. procedure TGLForm.ApplicationEventsIdle(Sender: TObject; var Done: Boolean);
  3. var
  4.   x,y,i: integer;
  5.   u,v: real;
  6. begin
  7. // In die Projektionsmatrix wechseln
  8. glMatrixMode(GL_PROJECTION);
  9. // Identitätsmatrix laden
  10. glLoadIdentity;
  11. glViewport(0,0,ClientWidth,ClientHeight);
  12. glOrtho(0, SizeX, SizeY, 0, 0, 128);
  13. // In die Modelansichtsmatrix wechseln
  14. glMatrixMode(GL_MODELVIEW);
  15. // Identitätsmatrix laden
  16. glLoadIdentity;
  17. // Farb- und Tiefenpuffer löschen
  18. glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  19.  
  20. Player1.Move;
  21.  
  22. // Drawing Map
  23. u:=0;
  24. v:=0;
  25. i:=0;
  26. glDepthMask(False);
  27. for x := 0 to 19 do begin
  28.   for y := 0 to 14 do begin
  29.     case MapArray[x][y] of
  30.       0..255: begin
  31.         i:=MapArray[x][y];
  32.         textures[0].bind;
  33.       end;
  34.       256..511: begin
  35.         i:=MapArray[x][y]-256;
  36.         textures[1].bind;
  37.       end;
  38.       512..767:  begin
  39.         i:=MapArray[x][y]-256-256;
  40.         textures[2].bind;
  41.       end;
  42.     end;
  43.     case i of
  44.       0..31: begin               // Zeile 1
  45.         v:=0;
  46.         u:=(i*32)/ 1024;
  47.       end;
  48.       32..63: begin              // Zeile 2
  49.         v:=0.125;
  50.         u:=((i-32)*32) / 1024;
  51.       end;
  52.       64..95: begin              // Zeile 3
  53.         v:=0.25;
  54.         u:=((i-64)*32) / 1024;
  55.       end;
  56.       96..127: begin              // Zeile 4
  57.         v:=0.375;
  58.         u:=((i-96)*32) / 1024;
  59.       end;
  60.       128..159: begin              // Zeile 5
  61.         v:=0.5;
  62.         u:=((i-128)*32) / 1024;
  63.       end;
  64.       160..191: begin              // Zeile 6
  65.         v:=0.75;
  66.         u:=((i-160)*32) / 1024;
  67.       end;
  68.       192..223: begin             // Zeile 7
  69.         v:=0.875;
  70.         u:=((i-192)*32) / 1024;
  71.       end;
  72.       224..255: begin            // Zeile 8
  73.         v:=1.0;
  74.         u:=((i-224)*32) / 1024;
  75.       end;
  76.     end;
  77.     glBegin(GL_QUADS);
  78.       glTexCoord2f(u,v);                glVertex3i(x*32,y*32,0);
  79.       glTexCoord2f(u+0.03125,v);        glVertex3i(x*32+32,y*32,0);
  80.       glTexCoord2f(u+0.03125,v+0.125);  glVertex3i(x*32+32,y*32+32,0);
  81.       glTexCoord2f(u,v+0.125);          glVertex3i(x*32,y*32+32,0);
  82.     glEnd;
  83.   end;
  84. end;
  85. glDepthMask(true);
  86.  
  87. u:=0;
  88. v:=0;
  89. textures[3].Bind;
  90. // Drawing Character
  91. glPushMatrix;
  92. glBegin(GL_QUADS);
  93.   glTexCoord2f(u,v);           glVertex3i(round(Player1.pos.x),round(Player1.pos.y),0);
  94.   glTexCoord2f(u+0.25,v);      glVertex3i(round(Player1.pos.x+32),round(Player1.pos.y),0);
  95.   glTexCoord2f(u+0.25,v+1.0);  glVertex3i(round(Player1.pos.x+32),round(Player1.pos.y+32),0);
  96.   glTexCoord2f(u,v+1.0);       glVertex3i(round(Player1.pos.x),round(Player1.pos.y+32),0);
  97. glEnd;
  98. glPopMatrix;
  99.  
  100.  
  101. ShowText;
  102. // Hinteren Puffer nach vorne bringen
  103. SwapBuffers(DC);
  104.  
  105. // Windows denken lassen, das wir noch nicht fertig wären
  106. Done := False;
  107.  
  108. // Nummer des gezeichneten Frames erhöhen
  109. inc(Frames);
  110. // FPS aktualisieren
  111. if GetTickCount - StartTick >= 500 then
  112.  begin
  113.  FPS       := Frames/(GetTickCount-StartTick)*1000;
  114.  Frames    := 0;
  115.  StartTick := GetTickCount
  116.  end;
  117. end;
  118.  


Ich denke, dass man das Timebased Movement mit Sicherheit irgendwie in den FPS-Counter mit einarbeiten kann, oder? Habe mir vorhin schon den Artikel im Wiki dazu angesehen, zusätzlich auch noch den Artikel beim Bomberman-Clone, da es da auch erklärt wird. Aber irgendwie komme ich auf keinen grünen Zweig..


Gruß
Spessi


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 00:29 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Also ich habe mein TBM immer so in der art aufgebaut:

Code:
  1.  
  2. procedure DoFrame; // Bei dir halt das OnIdle-Event
  3. var
  4.   CurrentFrame: Cardinal;
  5.   TimeInterval: Cardinal;
  6.   PassedSeconds: Double;
  7. begin
  8.   CurrentFrame := GetTickCount;
  9.   TimeInterval := CurrentFrame - LastFrame; // LastFrame: Würde ich als Member von
  10.   // deiner Form-Klasse vom Typ Cardinal deklarieren
  11.   LastFrame := CurrentFrame;
  12.   PassedSeconds := TimeInterval / 1000;
  13.   // Stell irgendwas damit an und render...
  14. end;
  15.  


Was jetzt dein Playermovement betrifft: Du solltest deine Position nicht als Integer sondern als Double speichern und dann nur beim Rendern auf das aktuelle Feld runden. So hast du die "zwischenwerte" mit drin.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 00:47 
Offline
DGL Member

Registriert: Mo Aug 15, 2005 19:29
Beiträge: 38
Hallo,
warum sollte ich LastFrame als Member von der Form-Klasse deklarieren? Wäre es nicht sinnvoller, wenn ich PassedSeconds als Member der Form-Klasse deklariere? So wie ich das verstehe wäre ja PassedSeconds dann der Wert, den ich mit meinen Player-Movement-Berechnungen multiplizieren muss, oder?
Warum dividierst du durch 1000? Kann man mit dem Wert rumspielen, und somit die 'Geschwindigkeit' festlegen?


Edit: Ich habe deinen Code komplett ÜBER den ganzen Renderkram geschrieben. Ist das überhaupt richtig? Logischerweise ja, aber man weiß ja nie ;)
Hab auch mal zu Testzwecken alle Werte ausgeben lassen, sie steigen immer an:
Bild

Gruß


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 02:47 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Okt 07, 2006 16:27
Beiträge: 52
Wohnort: Marbach(bei Chemnitz)
Zur Erklärung:
im Endeffekt ist es egal, wo du Last Frame deklarierst, solange du es nicht lokal tust, weil dann isses humbug. Nur isses halt Stilistisch schöner/besser wenn du es so machst wie vorgeschlagen

Gettickcount gibt die Zeit in Millisekunden an, seit der dein Windows gestartet ist (da gab es Witzigeweise mal ein Windows, was nach c.a. 16 tagen an nem Integerüberlauf abgestürzt ist).
Wenn du den Wert speicherst, irgendwas machst und dann den alten gespeicherten, von dem neuem Wert abziehst, dann erhältst du die zeit in Millisekunden, die das irgendwas gedauert hat. In dem Fall(dem beispiel von Lord Horrazont) is das die variable TimeInterval.
Da eine Sekunde 1000 Millisekunden hat, ergibt die Division durch 1000 die vergangene Zeit in Sekunden. In dem Falle halt passedSeconds.
Womit du multiplizierst ist im endeffekt egal, ob du mit TimeInterval oder Passed seconds multiplizierst, du must halt nur noch ne Speedfaktor einnehmen und den dann anpasssen, bis es ne schöne Bewegungsgeschwindigkeit gibt.
Einziges Problem: wenn du was darstellst, was sehr schnell geht, dann hast du das problem, das du mir der Method nur zeitunterschiede > 15ms rauskriegst. Falls das Darstellen schneller geht erhältst du 0 und irgendwas * 0 = 0. Ergo Stillstand. könntest du lösen, indem du z.B. die Zeit misst, die er braucht um 10 Frames zu malen.

Zu den Werten: die stimmen nie im Leben. Wenn du LastFrame von CurrentFrame abziehst, kommt da 0 raus und nicht irgendwas komisches. Da solltest du nochmal in deinen code blicken.


sry, für die Rechtschreibung, aber es ist mitten in der Nacht und ich seit 18h wach und in denen hab ich auch nich grad gefaulenzt ...

_________________
Es gibt eine Theorie, die besagt, wenn jemals irgendwer genau rausfindet, wozu das Universum da ist und warum es da ist, dann verschwindet es auf der Stelle und wird durch etwas noch Bizarreres ersetzt.
Es gibt eine andere Theorie, die besagt, dass das schon passiert ist.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 05:13 
Offline
DGL Member

Registriert: Mo Aug 15, 2005 19:29
Beiträge: 38
Hallo, also irgendwie blicke ich wirklich nicht durch. Entweder ist heute echt nicht mein Tag, oder - naja, es gibt kein oder :)

Habs jetzt so gemacht:

Code:
  1.  
  2. procedure TGLForm.ApplicationEventsIdle(Sender: TObject; var Done: Boolean);
  3. var
  4. [...]
  5.   CurrentFrame: Cardinal;
  6.   PassedSeconds: Double;
  7.   TimeInterval: Cardinal;
  8. begin
  9.   CurrentFrame := GetTickCount;
  10.   TimeInterval := CurrentFrame - LastFrame;
  11.         [.... rendern .....]
  12.   LastFrame := CurrentFrame;
  13.   PassedSeconds := TimeInterval / 1000;
  14. end;
  15.  



Und beim Bewegen eben:
Code:
  1.  
  2.     if Player1.MoveDown then begin
  3.       if MoveCounter>=32 then begin
  4.         Player1.MoveDown:=false;
  5.         Player1.Moving:=false;
  6.         MoveCounter:=0;
  7.       end else begin
  8.         Player1.pos.y:=(Player1.pos.y+1)*TimeInterval;       // Hier die wichtige Zeile - es hieß ja, dass es egal sei, mit was ich multipliziere. <!-- s:) --><img src=\"{SMILIES_PATH}/icon_smile.gif\" alt=\":)\" title=\"Smile\" /><!-- s:) -->
  9.         inc(MoveCounter);
  10.       end;
  11.     end;
  12.  


Ordentliche Werte krieg ich jetzt zumindest schonmal ausgegeben:
Bild

In der ersten Zeile steht CurrentFrame, in der zweiten TimeInterval, in der dritten LastFrame und in der vierten PassedSeconds. (Und in der allerersten die FPS \";-)\") Wobei TimeInterval kontinuierlich zwischen 0 und 16 hin- und herwechselt.


Edit1:
Ok, habs jetzt doch hingekriegt. Ich muss natürlich Player1.pos.y:=Player1.pos.y+(1*TimeInterval); rechnen. Da das ganze jetzt allerdings recht zügig ging (ZU schnell) hab ich das ganze noch mit 0.06 multipliziert. Die Geschwindigkeit passt jetzt zwar, allerdings kommt es durch auf / abrunden doch immer wieder vor, dass er aus dem 32x32 Grid rauskommt. Da landet er mal auf 257, anstatt auf 256.
Habe die komplette Bewegung nochmal anders gemacht, aber da ist der fehler immernoch:
Code:
  1.  
  2.     if Player1.MoveDown then begin
  3.       if Player1.pos.y>=DestBuff then begin
  4.         Player1.MoveDown:=false;
  5.         Player1.Moving:=false;
  6.         Player1.pos.y:=round(Player1.pos.y);
  7.       end else begin
  8.         Player1.pos.y:=Player1.pos.y+(1*GLForm.TimeInterval*0.06);
  9.       end;
  10.     end;
  11.  


DestBuff wird beim Tastendruck der jeweiligen Pfeiltaste entsprechend angepasst.
Code:
  1. DestBuff:=Player1.pos.y+32;
[/code[]

b]Edit 2:[/b]
Ahhh! Bin nun doch an ne Lösung gekommen - auch wenn DAS mit _Sicherheit_ nicht die Schnellste und Beste ist.

Code:
  1.  
  2.     if Player1.MoveDown then begin
  3.       if Player1.pos.y>=DestBuff then begin
  4.         Player1.MoveDown:=false;
  5.         Player1.Moving:=false;
  6.         buffvar:=round(Player1.pos.y/32);
  7.         Player1.pos.y:=buffvar*32;
  8.       end else begin
  9.         Player1.pos.y:=Player1.pos.y+(1*GLForm.TimeInterval*0.06);
  10.       end;
  11.     end;
  12.  

Ich verschiebe den Char jetzt solange, bis er die gewünsche Position (=DestBuff) erreicht hat. Anschließend dividiere ich die aktuelle Position durch 32 und speichere sie in einer Integer-Variable. Dadurch wird die Aktuelle Position im 32x32 Grid ohne Nachkommastellen gespeichert. Anschließend multipliziere ich diesen Wert wieder mit 32 und erreiche somit die aktuelle Spieler-Position, die genau im 32x32 Raster ist. Vom Funktionieren her nearly perfect - aber ihr habt sicherlich noch Tipps, wie man das ganze verbessern könnte, oder?

Werde mich jetzt ins Bett begeben, der Post hier ist über Nacht noch lang geworden ;-)
Ich hoffe ihr könnt mir noch Antworten dazu geben und ich hab euch nicht zu viel verwirrt *g*

Gute Nacht,
Spessi


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 12:57 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Okt 07, 2006 16:27
Beiträge: 52
Wohnort: Marbach(bei Chemnitz)
Du kannst doch einfach nach Abschluss der Bewegung der Position den Wert von buffvar geben.
Da sparst du dir ne Division und ne Multiplikation ...

Und du könntest beim verändern der Position das 1* weglassen. Weil irgendwas * 1 = irgendwas ... Ich weis nich inwiefern das Delphi im Compiler selber rausnimmt ... Wobei, dadurch das du mit gleitkommazahlen Rechnest kann es sogar etwas bewirken weil in Delphi manchmal 1 <> 1.0 ...
Jedenfall bläht es nur den Quelltext unnötig auf :wink:

_________________
Es gibt eine Theorie, die besagt, wenn jemals irgendwer genau rausfindet, wozu das Universum da ist und warum es da ist, dann verschwindet es auf der Stelle und wird durch etwas noch Bizarreres ersetzt.
Es gibt eine andere Theorie, die besagt, dass das schon passiert ist.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 17:10 
Offline
DGL Member

Registriert: Mo Aug 15, 2005 19:29
Beiträge: 38
Hallo,
danke, ja, die Fehler habe ich heute Nacht dann auch noch bemerkt. Es war leider schon spät ;-) Aber du meintest sicher, dass ich der Player-Position am Ende die Variable DestBuff zuweisen soll, nicht die BuffVar. Die BuffVar habe ich mittlerweile komplett rausgeschmissen.
Es hat nun zwar den Anschein, dass das "laufen" (verschieben) etwas ruckelt, aber das liegt sicherlich an meinem billigen OnBoard Grafik-Chip hier im Notebook ;-)

Also dankeschön für eure Hilfe!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 17:53 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Okt 07, 2006 16:27
Beiträge: 52
Wohnort: Marbach(bei Chemnitz)
Na ja, es wird halt immer um 1 px verschoben und wenn die Auflösung zu gering ist, sieht man das.
Vor allem, wenn das Zeitintervall zwischen zwei Sprüngen zu groß ist. Aber du hast ja nen fps counter. Der sagt dir ja, wie schnell das geht. Eigendlich sollte es ab 30 fps flüssig laufen.

_________________
Es gibt eine Theorie, die besagt, wenn jemals irgendwer genau rausfindet, wozu das Universum da ist und warum es da ist, dann verschwindet es auf der Stelle und wird durch etwas noch Bizarreres ersetzt.
Es gibt eine andere Theorie, die besagt, dass das schon passiert ist.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mär 23, 2008 18:12 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich habe das bei mir so gelöst, dass ich immer, wenn der Abstand zwischen beginn des letzten Frames und beginn des aktuellen Frames kleiner als 10 ms war, er dann einen Frame fallengelassen hat, also ich die Renderroutine einfach verlassen habe ohne irgendetwas zu tun (außer in deinem Falle natürlich Done auf False setzen). So kannst du sicher sein, dass du da immer halbwegs gescheite werte rausbekommst und du sparst Rechenleistung, zumindest wenn du das mit Sleep(5); oder so kombinierst.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 11 Beiträge ] 
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.010s | 15 Queries | GZIP : On ]