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

Aktuelle Zeit: So Dez 22, 2024 09:18

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



Ein neues Thema erstellen Auf das Thema antworten  [ 15 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Do Feb 07, 2008 14:11 
Offline
DGL Member

Registriert: So Mai 06, 2007 14:10
Beiträge: 7
Hallo an alle,
ich habe ein problem mit dem allseits beliebten timebased movement.. ich hab mir schon die meisten threads dazu hier durchgelesen aber keiner hatte wirklich das problem was ich habe.
ich hab in mein einfaches testprogramm jetzt timebased movement eingebaut und ich bin auch der meinung das alles stimmen müsste.. hier mal der code:
Code:
  1.  
  2. procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
  3. var i:integer;
  4. begin
  5.   QueryPerformanceCounter(Start);
  6.   if GetAsyncKeyState(vk_right) <> 0 then playerx:=playerx+1*speedfactor;
  7.   if GetAsyncKeyState(vk_left) <> 0 then playerx:=playerx-1*speedfactor;
  8.   Render;
  9.   QueryPerformanceCounter(Ende);
  10.   speedfactor:=(ende-start) / frequenz;
  11.   Done:= false;
  12. end;

also, da ich nen relativ schnellen rechner habe, ist mein speedfactor relativ gering.. ich hab mir dann mal meine speedfactorwerte auslesen lassen und bekomm da werte zwischen 0.00001 bis 0.001 ... ohne jedoch nen scalefactor von mindestens 10000 zu nehmen (in meinem code hier weggelassen), seh ich von irgendwelchen bewegungen so gut wie garnichts. und wenn ich dann einen entsprechend hohen sclaefactor gewählt habe ruckelt meine spielfigur sowas von.. mal bewegt sie sich gleichmäßig, mal sind kleine ruckler von ein paar pixeln drin und mal is sie plötzlich am anderen ende vom bildschirm..

ich nehm jetzt mal an dass das an meinem so stark variierenden speedfactor liegt, der einfach manchmal große sprünge macht.. also ich weiß jetzt nicht ob das normal ist, da sich ja normalerweise der speedfactor und die rendergeschwindigkeit ausgleichen um so gleichmäßige bewegungen zu erzeugen, aber das hier ist alles andere als gleichmäßig..

in nem anderen thread hab ich nun ne mögliche lösung gelesen, indem man einfach folgendes macht:
Code:
  1. if speedfactor<0.1 then speedfactor:=0.1

im prinzip hilft das, die animationen werden dadurch gleichmäßig, aber kann das nicht große probleme mit sich führen wenn man das programm auf nem anderen(langsameren) pc ausführt?
wenn mein pc zum beispiel einen durchschnitts speedfactor von 0.0001 hat und der so auf 0.1 gesetzt wird, und ein anderer langsamer pc hat von sich aus nur einen speedfactor von 0.1 ,so würden doch die bewegungen auf seinem pc im prinzip 1000 mal langsamer ausgeführt werden und das will ich ja nun auch beim besten willen nicht..
schließlich ist ja das ziel dass es überall gleich laufen soll^^
ich hoffe ihr wisst was ich meine und habt dafür vielleicht ne lösung..

ne andere frage wäre : vsync..
also bei mir ist es standardmäßig an(nvidia) bzw anwendungsgesteuert, aber wenn ich es ausschalte erhalte ich komplett andere bewegungen(viel schneller), aber trotzdem noch ruckeld..
jetzt ist es doch so, dass sich mein programm komplett anders verhält, wenn ich es auf einem pc mit aktiviertem vsync ausführe als auf einem auf dem vsync ausgeschalten ist? und jetzt meine frage, gibt es einen einfachen befehl, wie ich vsync in meiner anwendung aktivieren oder deaktivieren kann? total viele aktuelle spiele haben dafür ja auch ne option ;)

vielen dank schonmal!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 14:55 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Was ist in deinem Code eigentlich "frequenz"?
Soweit ich das Problem in erinnerung habe, gibt man Bewegungsgeschwindigkeiten im Programm an in entfernung/Zeiteinheit. Timebased movement sorgt dafür, die Entfernung jetzt passend zur tatsächlich benötigten Zeit zu verändern.

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 14:56 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Ich werfe jetzt einfach mal in den Raum, dass deine CPU eine mit 2 oder 4 Kernen bzw eine Intel CPU mit Hyperthreading ist?

Diese Lösung mit dem Begrenzen des SpeedFactors ist meiner Meinung nach nur ein Bekämpfen der Symthome. Das ändert aber nichts an der Grundproblematik. Und die ist folgende. Dein Programm läuft nicht nur auf dem selbem Kern. Das heißt durch den Sheduler von Windows läuft es mal auf CPU 1 und mal auf CPU 2. Diese Wechsel finden extrem häufig statt. Also auch innerhalb deiner Methode zwischen QueryPerformanceCounter(Start) und QueryPerformanceCounter(Ende). Da aber jeder Prozessorkern einen eigenen Timer hat misst du unterschiedliche Werte, da der Performancetimer ist so extrem hoch aufgelöst ist. Von AMD gibt es zwar ein Tool welches die Timer angleichen kann aber das wird eigentlich nur dem Endanwender etwas nützen. Das Programm sollte mittlerweile trotzdem damit klar kommen.

Du kannst mit der Methode SetProcessAffinityMask festlegen auf welchen Prozessoren deine Anwendung ausgeführt werden darf. Entweder setzt du das beim Start der Anwendung. Oder aber zu Begin des IdleHandlers und am Ende wieder auf die vollständige Maske zurück. Wenn du das Innerhalb von OnIdle jedes mal setzt, dann könntest du dafür sorgen, dass deine Anwendung abwechselnd auf dem Einen dann auf dem anderen Prozessor laufen würde. Natürlich müsstest du dann die Maske abwechseln. Dann ist nicht ein Prozessor vollständig beschäftigt und der andere schläft dauerhaft. Wobei wenn ich so drüber nachdenke. Die AffinityMask ist gewissermaßen ein Blockieren was durchaus noch andere Probleme haben könnte. Du könntest natürlich auch nur das QueryPerformanceCounter mittels SetProcessAffinityMask auf einen Prozessor binden. Dann hätte Windows ansonsten die frei Auswahl welchen Prozessor es für dein Programm benutzt. Das wäre hilfreich um evtl andere Anwendungen nicht zu blockieren.

Allerdings weiß ich nicht ob SetProcessAffinityMask schon direkt dafür sorgt, dass deine Anwendung evtl. den Prozessor wechselt. Ansonsten kann es sein, dass er erst später auf einen anderen Prozessor gezungen wird. Dann ist das Ergebniss wieder falsch. Da hilft dann evtl. ein sleep(0). Dadurch findet ein Taskwechsel statt, der aber deine Anwendung nicht schlafen legt, sofern niemand anderes etwas tun möchte. Und damit solltest du dann auch Augenblicklich den Prozessor wechseln, da der Sheduler beim Aktivieren des Prozesses deiner Anwendung wieder einen Prozessor zuweist.

Alternativ dazu kannst du auch mit GetTickCount arbeiten falls es nicht zu ungenau ist. Da das von Windows selbst kommt ist es nicht abhängig von der Hardware. Dafür aber ziemlich ungenau.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 15:22 
Offline
DGL Member

Registriert: So Mai 06, 2007 14:10
Beiträge: 7
also frequenz ist eine variable vom typ int64 und wird beim OnCreate folgendermaßen definiert
Code:
  1. QueryPerformanceFrequency(Frequenz);

so wie ichs bei jedem TBM code gesehen hab das ich mir bisher angeschaut hab und auch richtig sein dürfte..

Und ja, ich hab tatsächlich eine 2 kernige CPU.. danke, darauf wär ich wohl nicht unbedingt gekommen, hört sich aber logisch an, dass das die ursache für mein problem sein könnte.. ich werd gleich mal anfangen, die tips von dir auszuprobieren..

und ja, GetTickCount ist mir schon etwas zu ungenau, hab es anfangs damit probiert, aber das möcht ich nur ungern verwenden..
aber danke nochmal, ich werd gleich mal etwas rumprobieren.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 15:33 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Mär 09, 2005 15:54
Beiträge: 372
Wohnort: München
Programmiersprache: Delphi, C#, FPC
Kann es sein, dass du vSync anhast? Das kann bei deiner Methode auch ein Problem sein. Ich würd es folgendermaßen lösen
Code:
  1.  
  2. begin
  3.   QueryPerformanceCounter(t2);
  4.   SpeedFactor := (t2 - t1) / frequenz;
  5.   QueryPerformanceCounter(t1);
  6.   if GetAsyncKeyState(vk_right) <> 0 then playerx:=playerx+1*speedfactor;
  7.   if GetAsyncKeyState(vk_left) <> 0 then playerx:=playerx-1*speedfactor;
  8.   Render;
  9.   Done:= false;
  10. end;
  11.  


Dadurch hast du den vorteil, dass alles bei der Zeitberechnung mitbeachtet wird. DeltaTime [hier der speedfactor] ist dann nicht nur die Zeitdauer zum Rendern, sondern die Dauer, bis OnIDLE wieder aufgerufen wird.

Das lustige ist, ich hab auch nen AMD Dualcore drinn und hab mit QueryPerformanceCounter noch keine Probleme wegen negativem DeltaTime gehabt. Und ich begrenze meinen Prozess nicht nur auf eine CPU. Das kann immer Zufall sein, doch ich bin wirklich noch nie rückwärts gelaufen, obwohl ich vorwärts gedrückt habe.

_________________
Aktuelles Projekt: Gael - Development Blog
Website: LightBlackSoft.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 16:20 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
littleDave: Hast du vielleicht den "AMD DualCore Optimizer" installiert? Das ist nämlich dieses kleine Tool von AMD, welches die Zeiten miteinander abgleicht.

Ich weiß aber nicht was es alles für Gründe haben kann, dass die Zeiten voneinander abweichen. Wenn du Glück hast starten die beiden Kerne fast zeitgleich und das Rendern dauert entsprechend lange. Dann wird eine Abweichung wohl eher kaum ins Gewicht fallen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 16:34 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Mär 09, 2005 15:54
Beiträge: 372
Wohnort: München
Programmiersprache: Delphi, C#, FPC
Lossy eX hat geschrieben:
littleDave: Hast du vielleicht den "AMD DualCore Optimizer" installiert? Das ist nämlich dieses kleine Tool von AMD, welches die Zeiten miteinander abgleicht.


Nicht das ich wüsste, kenn das Programm überhaupt nicht. Hab aber noch mal geschaut: kein annähernd ähnlicher Eintrag in der SoftwareListe bzw. annähnern ähnlicher Ordner gefunden.

Ich hab das Problem natürlich mit unterschiedlichen Timern auch, nur halt nicht bei meiner Engine, sondern z.B. bei UT2003. Der wirft mir, wenn ich dem Programm keine limitierung auf CPUs setzte, sofort eine Exception mit "negativer deltaTime" raus.

"Lossy eX hat geschrieben:
und das Rendern dauert entsprechend lange


Das kann natürlich sein, ich werd bei Gelegenheit eine Assertion eintragen, die überprüft, ob DeltaTime negativ ist.

_________________
Aktuelles Projekt: Gael - Development Blog
Website: LightBlackSoft.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 17:23 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Aug 18, 2007 18:47
Beiträge: 694
Wohnort: Köln
Programmiersprache: Java
bei mir ähnlich:

Code:
  1.  
  2. procedure TForm1.OnCreate;
  3. begin
  4.   QueryPerformanceCounter(QPCLast);
  5.   QueryPerformanceFrequency(QPCFreq);
  6. end;
  7.  
  8. procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
  9. begin
  10.   Render;
  11.   ProcessInput;
  12.   QueryPerformanceCounter(QPCNow);
  13.   FrameTime := (QPCNow-QPCLast) / QPCFreq * 1000; // in ms
  14.   QPCLast := QPCNow;
  15.   Done:= false;
  16. end;
  17.  


btw: hab auch einen amd dual core. keinen optimizer und null probleme.

_________________
Es werde Licht.
glEnable(GL_LIGHTING);
Und es ward Licht.


Zitat aus einem Java Buch: "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off"

on error goto next


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 17:46 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2622
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich nutze folgende 2 Codes für mein TBM und habe auf mein AMD X2 CPU auch noch nie Probleme gehabt.
Unter Linux sowieso nicht ^^.
Link to WindowsTimer.pas
Link to LinuxTimer.pas

Ich empfehle die Tastenbelegung umzuschreiben, nicht jeden Frame nach der Taste in der API nachfragen sondern KeyUp/Down Event nutzen und eine Keymask führen. Das ist ein simpler Adressen zugriff(auf ein array) und nicht ein proceduraufruf, ms interne routinen und ret. Gerade im Bereich der Mainloop sollte man jegliche Proceduraufrufe vermeiden, da diese da richtig teuer sind(vorallem bei delphi, da delphi noch ne menge prüfungen auf die rückgabe und übergebenen parameter macht).

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Feb 07, 2008 22:11 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
ein call auf GetKeyboardState sollte man sich noch leisten können. (ich traue KeyUp/KeyDown dafür nicht genug wegen focus-switch etc)
Außerdem würde ich noch einen frameratenbegrenzer einbauen, da floats bei zu hohen frequenzen rundungsfehler bekommen (z.B. if DeltaT<5ms then sleep(1)). Ich rufe den counter auch nur 1x pro frame ab, und bilde die differenz zum letzen mal. Nach oben würde ich auch eine Begrenzung einbauen(z.B. if DeltaT>100ms then DeltaT=100ms)

Code:
  1. var last:int64;
  2.  
  3. procedure OnIdle(bla);
  4. var Time:int64;
  5.       DeltaT:real;
  6. begin
  7.   Done:=false;
  8.   QueryPerformanceCounter(time);
  9.   DeltaT := (time - last) / frequenz;
  10.   if DeltaT<0 then DeltaT:=0;
  11.   if DeltaT<0.005
  12.     then begin
  13.       sleep(5-round(DeltaT*1000));
  14.       exit;//Exit before time:=last!
  15.     end;
  16.   time:=Last;
  17.   if DeltaT>0.1 then DeltaT:=0.1;
  18.  
  19.   if GetAsyncKeyState(vk_right) <> 0 then playerx:=playerx+1*DeltaT;
  20.   if GetAsyncKeyState(vk_left) <> 0 then playerx:=playerx-1*DeltaT;
  21.   Render;
  22. end;

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Feb 08, 2008 07:57 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Warum nach oben eine Begrenzung? Bei einem langsamen Rechner würde das Spiel dann ja auch langsamer werden und der nutzen von Timebased Movement wäre zumindest in diesem Fall dahin.

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: Fr Feb 08, 2008 08:34 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Lord Horazont: Ich glaube du missverstehst da etwas. Das Spiel sollte natürlich nur dann ausgebremmst werden, wenn es schneller als z.B. 30 fps läuft. Wenn es langsamer läuft dann darf natürlich nichts gebremmst werden. Aber selbst wenn es dauerhaft mit ca 30 läuft benötigt man Timebased Movement. Denn die Dauer der Frames schwankt trotzdem.

Ein solcher Begrenzer ist im übrigen nicht unsinnig. Denn für einige Spiele (nicht für alle) genügt es, wenn ca. 30 Bilder in der Sekunde dargestellt werden. Und genau solche Spiele kann man dauerhaft auf einem Notebook spielen. Das hatte ich bei einem Online Rollenspiel gesehen. Das hatte nur süße 2-3% Last. Mehr brauchte es aber auch nicht. ;)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Feb 08, 2008 08:39 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich rede nicht von dem Sleep-Aufruf. Dass der sinnvoll und gut ist, ist mir klar, den benutze ich bei mir selber auch, aus Genauigkeitsgründen (es wird nur dann gerendert/TBM ausgeführt, wenn deltaTime ... (wunderbar in diesem moment hat windows auf englisches tastaturlayout umgeschaltet und dank fehlenden adminrechten habe ich keine moeglichkeit, umzuschalten... dumme schulrechner) deltaTime < 10ms ist, warte bis zum naechsten.

gruss 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: Fr Feb 08, 2008 10:06 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Achso. Ja. Okay. Die Abfrage begrenzt die DeltaTime auf mindestens 10 Fps. Egal ob der Rechner langsamer ist. Macht natürlich eher nicht so viel Sinn, da es ja dann bei langsamen Rechnern noch langsamer wird was man eigentlich verhindern wollte. Ist natürlich vollkommen richtig der Einwand. Hatte ich nicht drauf geachtet. :roll:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Feb 09, 2008 11:46 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
Unter 10 FPS macht das spielen keinen Sinn. Außerdem gibt das wenn man keine kontinuierliche Kollisionsabfrage hat Ärger.Zudem verhindert es Sprünge. Bei meinem Verfahren der Zeitmessung ist es so, dass es sonst zu riesigen Sprüngen käme wenn der user ein TMainMenu aufruft oder so. Da dann der Idleloop anhält wenn ich mich richtig erinnere. Konnte man in der Kombination mit der Kollision in einem meiner Spiele für das Tunneln durch wände nutzen, obwohl das Spiel keine Quantenmechanik wiederspiegeln sollte ;)
Bei >100 oder 200 fps bremse ich, damit es weniger Leistung frisst, und es keinen Ärger mit FP-Genauigkeit gibt.

_________________
Bild


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


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 22 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:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.014s | 16 Queries | GZIP : On ]