PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Spielgeschwindigkeit auf PCs synchronisieren


Einfachkrank
2004-10-14, 13:29:57
Hi,

ich hab folgendes Problem: Programmiere gerade ein einfaches Spiel, bei dem der Spieler herunterfallende Gegenstände auffangen muss. Bei mir aufm Rechner(AMD Athlon64 3000+, Radeon 9800Pro 128MB, 512DDR) rennt das mit 500FPS. Dann hab ich es auf dem Rechner vom Vadda getestet(der hat en AMD Athlon 1400MHz, 512SD-RAM und NoName Grafikkarte). Auf seinem PC läuft das Spiel auch noch mit 300FPS, aber ist trotzdem irgendwie tierisch langsam...

Die Bewegung der Items und des Spielers wird alles durch die FPS im Spiel synchronisiert, aber warum ist es auf anderen Rechner trotzdem irgendwie langsamer?

MFG Einfachkrank

Gast
2004-10-14, 14:13:35
Welche Sprache?

Vielleicht ein Teil deines Quellcodes (besonders deine Zeiteinteilung ;))

MuLuNGuS
2004-10-14, 14:52:28
wie, du synchronisiert die bewegungen durch die FPS im spiel??

wenn die geschwindigkeit der bewegungen auf allen rechnern gleich sein soll mußt du das ganze zeitbasierend angehen.(insofern ich dich jetzt nicht falsch verstanden habe)

du berechnest einfach die zeit die seit dem letzten frame vergangen ist und multiplizierst es mit dem speed deines objektes.

mal angenommen seit dem letzten frame ist 1 sek. vergangen und dein objekt soll sich mit 10 pixeln in der sekunde bewegen, dann ist 1 x 10 deine geforderte geschwindigkeit.

sind seit dem letzten frame nur 0,5 sek sind es halt 0,5 x 10 = 5 pixel, nach zwei durchläufen ist die zurückgelegte strecke dann auch wieder 10 pixel.

egal wie schnell oder lahm der rechner ist, der zurückgelegte weg wird so innerhalb der gleichen zeit auch die gleiche entfernung haben.

Mul

Einfachkrank
2004-10-14, 17:00:06
Jo, also ich hab es in Visual C++ 6.0 Standard und OpenGL programmiert. Und was die Synchronisation betrifft funktioniert das ganz genau so bei mir. Die Geschwindigkeit der Objekte wird durch FPS dividiert... Das ist ja genau dasselbe dann, als wenn ich die Zeit für einen Frame damit multipliziere.

Einfachkrank
2004-10-14, 17:09:36
# define SPEED_PLAYER 1.0f
# define SPEED_OBJECT 2.0f
//...

while(!isDone) // haupschleife
{
timer = GetTickCount();

// objekte.pos += SPEED_OBJECT / fps;
// player.pos += SPEED_PLAYER / fps;

fps = 1000.0f / (GetTickCount() - timer);
}

So müsste es normalerweise immer gleich schnell sein, aber bei meinem Vadda aufm Rechner ist es halb so schnell, bei 300FPS...

PS: Sorry, für Doppelpost, war keine Absicht!

zeckensack
2004-10-14, 17:23:56
GetTickCount ist zu unpräzise.
Schau dir mal QueryPerformanceCounter (und QueryPerformanceFrequency) an.

Ganon
2004-10-14, 17:46:41
GetTickCount ist zu unpräzise.

Das hat was für Auswirkungen? Also in welchem Fall sollte man es nicht nutzen?

MuLuNGuS
2004-10-14, 21:35:38
Das hat was für Auswirkungen? Also in welchem Fall sollte man es nicht nutzen?

GetTickCount() liefert einen (ich sag jetzt mal) groben ungenauen wert der ihn ziemlich unbrauchbar macht.
scheinbar wird der wert auf den die funktion zurückgreift nicht sonderlich oft aktualisiert.
das resultat ist das alles was man darauf basierend bewegt ziemlich stark ruckelt, nix mit smoooooth.

die highperformance counter sind auf jeden fall die erste wahl.

Vedek Bareil
2004-10-15, 04:03:18
war das nicht so, daß GetTickCount() die Zahl der Ticks des Windows-Timers liefert, welcher bekanntlich nur 18.2 (Win9x) bzw. 100mal (WinNT+) pro Sekunde tickt?
GetTickCount - timer würde bei hoher FPS-Rate dann recht häufig 0 ergeben...

Spricht eigentlich irgendwas gegen

#include <time.h>

//...

while(!isDone) // haupschleife
{
time_t *Ptime;
time_t timer = time(Ptime);

// objekte.pos += SPEED_OBJECT / fps;
// player.pos += SPEED_PLAYER / fps;

fps = 1.0f/difftime(time(Ptime), timer);
/* difftime liefert die Zeitdifferenz in
Sekunden als Fließkommazahl*/
}
?

Demirug
2004-10-15, 07:47:53
GetTickCount hat auf den meisten Systemen eine Genauigkeit von etwa 16ms. Mit timeBeginPeriod und timeEndPeriod kann man diese auf 1ms erhöhen.

Wie zeckensack aber schon sagt sollte man in solchen Fällen aber besser QueryPerformanceCounter benutzten.

Ich rate übrigens dringend davon ab RDTSC zur Zeitmessung benutzen.


Das Berechnen von Bewegungsvektoren über die FPS erscheint mir zudem auch etwas "merkwürdig". Das Physik Modul sollte normalerweise sowas wie FPS gar nicht kennen. Geschwindigkeiten werden ja normalerweise in m/s definiert. Ergo gibt man dem Physikmodul normalweise auch einfach die Zeit (in Sekunden) die seit der letzten Aktualisierung vergangen ist. Das ganze erst in FPS umzurechnen und dann indirekt wieder zurück Sekunden ist IMHO auch unnötig umständlich.

MuLuNGuS
2004-10-15, 07:55:12
GetTickCount hat auf den meisten Systemen eine Genauigkeit von etwa 16ms. Mit timeBeginPeriod und timeEndPeriod kann man diese auf 1ms erhöhen.

Wie zeckensack aber schon sagt sollte man in solchen Fällen aber besser QueryPerformanceCounter benutzten.

Ich rate übrigens dringend davon ab RDTSC zur Zeitmessung benutzen.


Das Berechnen von Bewegungsvektoren über die FPS erscheint mir zudem auch etwas "merkwürdig". Das Physik Modul sollte normalerweise sowas wie FPS gar nicht kennen. Geschwindigkeiten werden ja normalerweise in m/s definiert. Ergo gibt man dem Physikmodul normalweise auch einfach die Zeit (in Sekunden) die seit der letzten Aktualisierung vergangen ist. Das ganze erst in FPS umzurechnen und dann indirekt wieder zurück Sekunden ist IMHO auch unnötig umständlich.

hab mich auch schon gefragt was die FPS geschichte da zu suchen hat, das bringt halt nix.

micki
2004-10-15, 09:59:32
oder man hat einen gesonderten logicloop der davon ausgeht in einem bestimmten zeitinterval aktualisiert zu werden. Das hilft bei phsyik berechnungen ein akkurates verhalten auf jedem system zu erhalten ohne die berechnungen besonders aufwendig zu gestalten (weil man nicht mit deltas umgehen muss bei z.b. nicht linearen bewegungen)

MfG
micki

Ganon
2004-10-15, 16:07:17
Hi.

Ich habe zur Zeit das in Anwendung (sorry, für die deutschen Variablen ;)):


// Animationszeit
#ifdef _WIN32
static DWORD letzteZeit;
#else
static struct timeval letzteZeit;
#endif
double AnimaBremse=0.0;

void FensterAnzeige(void)
{
// Animationszeit
#ifdef _WIN32
DWORD ZeitJetzt;
ZeitJetzt = GetTickCount();
AnimaBremse = (float) (ZeitJetzt - letzteZeit) / 1000.0;
#else
struct timeval ZeitJetzt;
gettimeofday(&ZeitJetzt, NULL);
// Zeit errechnen
AnimaBremse = (float)(ZeitJetzt.tv_sec - letzteZeit.tv_sec)+ 1.0e-6*(ZeitJetzt.tv_usec - letzteZeit.tv_usec);
#endif

glClearColor( .9f, .9f, .9f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();

//...code...

glPopMatrix();
glutSwapBuffers();

// Animationszeit
letzteZeit = ZeitJetzt;
}


Das Ganze soll unter OS X, Linux und Windows laufen. Dafür habe ich ja den _WIN32 Part.

Wie sollte er denn besser aussehen? Ich kann das Ganze schlecht unter Windows testen, da ich zur Zeit nur VirtualPC habe und dort die Framerate eher mies ist (30-50fps). Unter OS X liegt sie aber nahe 1000.

Unter OS X funzt es gut, aber unter Windows weiß ich es halt nicht bei hoher Framerate.

Wie wendet man das von euch genannte PerformanceCouter an?

Einfachkrank
2004-10-15, 18:42:53
Also noch mal zur FPS-Sache. Ist ein Unterschied zwischen

float fps = 1000.0f / (float)(GetTime() - timer);
// ...
pos += SPEED / fps;
und

float t = (GetTime() - timer) / 1000.0f;
// ...
pos += SPEED * t;

???

Coda
2004-10-15, 18:54:41
Ja ein div ist deutlich langsamer.

Einfachkrank
2004-10-15, 20:49:02
Oh, gut zu wissen.

PS: Mit QueryPerformanceCounter() funktioniert es, DANKE!!!

Demirug
2004-10-15, 21:03:42
Noch ein kleiner Tipp am Rande. Die "Spielzeit" sollte man immer von der "Realzeit" des Systems entkoppel. Das macht es viel einfacher eine Pausefunktion sowie einen schnellere bzw langsamere Ablauf der Dinge zu erreichen. Zudem kann man damit auch schön einen Benchmarkfunktion bauen indem man die "Spielzeit" pro Frame um einen festen betrag weiterstellt. Das stellt sicher das jede Karte das gleiche rendern muss.