Hmmm also ich hoffe daß ich das jetzt eingermaßen erklären kann. Also wenn Du zeitgesteuert programmieren willst, dann bräuchtest Du eine getPlayerX()-Funktion, die Du mit einem Zeitparameter aufrufen kannst. Somit kannst Du die X-Position zu jedem beliebigen Zeitpunkt aufrufen und alle Situationen rekonstruieren, das ist wichtig wenn Du Server und Client einigermaßen synchron haben willst.
Das Prinzip ist das folgende:
1) Du speicherst NICHT die aktuelle Position des Spielers, sondern immer nur die zuletzt geänderte Position, zusammen mit dem Zeitpunkt. Deine Spieler-Struktur besitzt also auf jeden Fall eine xPos.f, eine yPos.f, und eine lastTime.l
2) Sobald der Spieler eine Taste drückt bzw. die Figur ihre Richtung wechselt (kann auch für CPU-Gegner gelten, die ja nicht tastaturgesteuert sind), rufst Du eine Funktion savePosition(*p.player, currentTime.l) auf, die sich die aktuelle Position merkt (also in xPos.f und yPos.f hineinschreibt) und die aktuelle Zeit ebenfalls (lastTime = currentTime).
3) Wenn Du nun die Position benötigst, sei es für das Anzeigen oder die Erkennung von Kollisionen, rufst Du getPlayerX(*p.player, currentTime.l) bzw. getPlayerY(...) auf. Diese rechnen einfach anhand der zuletzt gespeicherten Position die aktuelle Position aus, denn sie wissen ja die Richtung, die Geschwindigkeit und die Zeit, die seitdem vergangen ist.
Somit hast Du jederzeit Zugriff auf beliebige Zeitpunkte, kannst also auch ein Stückweit in die Zukunft und in die Vergangenheit sehen. Natürlich nur im Millisekundenbereich und natürlich ist das auch nicht immer 100% korrekt, aber es ist deutlich besser als andere Verfahren, wo Du eben einfach immer nur einen Wert auf die Position aufaddierst.
Die momentane Zeit erfragst Du einfach durch TimeGetTime oder ElapsedMilliseconds etc. und übergibst sie an Deine levelUpdate()-Funktion oder was auch immer Du da hast.
Hier ein paar Beispiele für die Funktionen (entnommen aus meinem derzeitigen Projekt, daher stimmen jetzt die Namen nicht so wie oben):
Code: Alles auswählen
Procedure cachePos(*o.MovingObject, time)
*o\x = getX(*o, time)
*o\y = getY(*o, time)
*o\lastTime = time
EndProcedure
Procedure moveLeft(*o.MovingObject, time)
If *o\xdir <> -1
cachePos(*o, time)
*o\xdir = -1
*o\facing = #DIR_LEFT
EndIf
EndProcedure
Procedure stopLeft(*o.MovingObject, time)
If *o\xdir = -1
cachePos(*o, time)
*o\xdir = 0
EndIf
EndProcedure
Procedure.f getX(*o.movingobject, time)
ProcedureReturn *o\x + (time - *o\lastTime) * (*o\speed) * (*o\xdir) / 1000
EndProcedure
Procedure.f getY(*o.MovingObject, time)
ProcedureReturn *o\y + (time - *o\lastTime) * (*o\speed) * (*o\ydir) / 1000
EndProcedure
Deine Bewegungen sind scheinbar anders, Du benutzt ja Sinus- und Cosinus-Funktionen. Aber auch hier ist es natürlich möglich, das umzusetzen, mußt halt nur die Berechnungen entsprechend anpassen.
----
Nun wieder something completely different

Die Tastatureingaben schickst Du nicht über Escape = 1, KeyDown = 2 oder sowas, sondern Du kannst direkt die Konstante schicken (also z.b. #PB_Key_Escape), die sind ja eindeutig und Du brauchst nicht hin- und herzurechnen.
Das mit den 30 Sekunden ist eigentlich keine schlechte Idee, somit kannst Du sichergehen, daß noch alles paßt.
Zum Thema "muß ich player1, player2, player3 machen": Nein, Du hast alle Player in einem Array oder einer LinkedList und kannst dann ForEach bzw. eine normale For-Schleife verwenden. Am besten eine updatePlayer()-Funktion basteln, die ihrerseits weitere Funktionen aufruft, und an diese eine Funktion dann den Pointer übergeben und per Schleife halt mehrmals mit unterschiedlichen Pointern aufrufen.
----
Und jetzt noch ein ganz anderer Tip. Programmiere erstmal einen kleinen Pong-Clone und mach den Netzwerkfähig (mit den oben beschriebenen Zeit-Funktionen). Wenn Du das 100% hinkriegst, würd ich erst mit dem eigentlichen Spiel weitermachen, denn es ist schwerer als man denkt (ich hab auch mal ein Network-Pong gemacht und das ist voller Fehler

).