Netzwerk
thx.
Ich werde es auch so machen das er nur die Tastatureingaben sendet und ale sagen wir mal 30 sek testet er ob die Positionen übereinstimmen( wenn nicht wird die Figur zu der richtigen Psoition vom Server gesetzt).
So ähnlich wie bei den meisten online spielen.
EVTL. werde ich die Tastatur eingaben als Variable verschicken. Escape = 1 ...
Ich werde es auch so machen das er nur die Tastatureingaben sendet und ale sagen wir mal 30 sek testet er ob die Positionen übereinstimmen( wenn nicht wird die Figur zu der richtigen Psoition vom Server gesetzt).
So ähnlich wie bei den meisten online spielen.
EVTL. werde ich die Tastatur eingaben als Variable verschicken. Escape = 1 ...
Benutze PB v 4.40 Beta 3
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):
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
).
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
----
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



ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Ach ja ich hatte noch was vergessen:
Also wenn Du nun die Daten übers Netzwerk schickst, brauchst Du im Grunde immer nur alle Richtungswechsel zu verschicken. Ein Richtungswechsel besteht in diesem Fall nur aus der neuen Richtung und dem Zeitpunkt des Wechsels (und natürlich der ID des Players / Gegners / Objekts). Das sollte eigentlich genügen, denn der Server, der das Spiel ja verwaltet, braucht nun nur noch die momentane Position und Zeit speichern (mit savePos (bzw. cachePos)) und dann den Richtungswechsel ausführen.
Da ich Dein Projekt nicht kenne, Du aber mit Sinus und Cosinus arbeitest, könnte es evtl. sogar korrekter sein, tatsächlich die Tastatureingaben zu schicken, allerdings würde ich dann immer nur die KeyPushed und KeyReleased-Events verschicken, das sind dann pro Bewegung meist 2 Events. Also nicht auf die Idee kommen und in jedem Frame, wo ein Key gepushed ist, dies als Event verschicken
Also wenn Du nun die Daten übers Netzwerk schickst, brauchst Du im Grunde immer nur alle Richtungswechsel zu verschicken. Ein Richtungswechsel besteht in diesem Fall nur aus der neuen Richtung und dem Zeitpunkt des Wechsels (und natürlich der ID des Players / Gegners / Objekts). Das sollte eigentlich genügen, denn der Server, der das Spiel ja verwaltet, braucht nun nur noch die momentane Position und Zeit speichern (mit savePos (bzw. cachePos)) und dann den Richtungswechsel ausführen.
Da ich Dein Projekt nicht kenne, Du aber mit Sinus und Cosinus arbeitest, könnte es evtl. sogar korrekter sein, tatsächlich die Tastatureingaben zu schicken, allerdings würde ich dann immer nur die KeyPushed und KeyReleased-Events verschicken, das sind dann pro Bewegung meist 2 Events. Also nicht auf die Idee kommen und in jedem Frame, wo ein Key gepushed ist, dies als Event verschicken



ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
bisher hab ich
und der ist ja auch nicht ganz richtig(bei 2D klappt es nun will ich es aber auch für später 3D haben)
Wie krieg ich es richtig hin?
wie kann ich dann einstellen das er nach der Player anzahl geht?
Code: Alles auswählen
For i = 0 To player
CameraLocate (0, *players(1)\xPos - Cos(2*#PI*(rot/360))*15, TerrainHeight(*players(1)\xPos,*players(1)\zPos)+10, *players(1)\zPos + Sin(2*#PI*(rot/360))*15)
EntityLocate(0, *players(1)\xPos,TerrainHeight(*players(1)\xPos,*players()\zPos),*players(1)\zPos)
Next
Wie krieg ich es richtig hin?
Code: Alles auswählen
*player/xPos
:nimmt er nicht
Benutze PB v 4.40 Beta 3
Hmm also bau Dir erstmal die folgenden Funktionen:
Die Berechnung stimmt zwar nicht, aber da ich in Mathe nicht grad der Oberfreak bin kann ich Dir hierbei auch nicht richtig helfen. Auf jeden Fall mußt Du noch den Zeitfaktor (currentTime - (*p\lastTime)) und die Geschwindigkeit (*p\movingSpeed) einbauen. Da kann Dir bestimmt einer unserer Mathematiker besser helfen 
Prinzipiell mußt Du nur Zeitfaktor * Geschwindigkeit rechnen und diesen Wert auf die momentane Position hinzuaddieren, aber wie das Sinus- und Cosinus-mäßig läuft, keine Ahnung.
Dann machst Du folgendes:
Diese Funktionen kannst Du nun mit einer ganz normalen Schleife aufrufen:
Das gleiche kannst Du nun mit jeder beliebigen Entity machen, also auch mit Gegnern usw. Da sich deren elementare Funktionen (Position setzen, rendern, etc) i.d.R. kaum unterscheiden, solltest Du sie auf jeden Fall von der gleichen Struktur abstammen lassen.
Also Du machst z.B. sowas:
Nun kannst Du die Funktionen, die für alle gelten sollen, nicht mit *p.player machen, sondern mit *o.movingObject. Trotzdem kannst Du alles übergeben! Das heißt, allgemeine Funktionen werden allgemein programmiert, aber ob Du nun einen Player oder BadGuy übergibst, spielt keine Rolle, da beide vom selben Basis-Objekt abstammen und die Funktion nur nach dem Basis-Objekt verlangt! Cool was 
Code: Alles auswählen
Procedure getPlayerX(*p.player, currentTime)
ProcedureReturn *p\xPos - Cos(2 * #PI * (rot/360)) * 15
EndProcedure
; ...und das gleiche für Y und Z

Prinzipiell mußt Du nur Zeitfaktor * Geschwindigkeit rechnen und diesen Wert auf die momentane Position hinzuaddieren, aber wie das Sinus- und Cosinus-mäßig läuft, keine Ahnung.
Dann machst Du folgendes:
Code: Alles auswählen
Procedure updatePlayer(*p.player, currentTime)
; hier drin alle weiteren Funktionen aufrufen,
; die den Player updaten, z.B. seine Position ändern,
; Kollisionen prüfen, und was weiß ich.
; natürlich immer beide Parameter weitergeben!
EndProcedure
Procedure renderPlayer(*p.player, currentTime)
EntityLocate(*p\entity, getPlayerX(*p, currentTime), getPlayerY(*p, currentTime), getPlayerZ(*p, currentTime))
EndProcedure
Code: Alles auswählen
#NUMBER_OF_PLAYERS = 4
Global Dim *players.player(#NUMBER_OF_PLAYERS -1)
Repeat
currentTime = ElapsedMilliseconds()
For i = 0 to #NUMBER_OF_PLAYERS -1
updatePlayer(*players(i), currentTime)
renderPlayer(*players(i), currentTime)
Next i
; der Rest Deiner Hauptschleife
; ...
Forever
Also Du machst z.B. sowas:
Code: Alles auswählen
Structure movingObject
xPos.f
yPos.f
zPos.f
lastTime.l
entity.l ; hier drin speicherst Du die Nummer der 3D-Entity
; ... und noch alles weitere, was ALLE benötigen!
EndStructure
; davon leitest Du nun den Player ab:
Structure Player extends movingObject
lives.b
score.l
energy.l
EndStructure
; und beliebig viele andere Dinge:
Structure BadGuy extends movingObject
evilness.l
scoreValue.l
EndStructure



ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
danke.
Und die Positionen die ich mit getx... ermittelt habe wie soll ich die so festlegen das die dort starten. bsp.(wie davor:?
schonmal danke für die antworten im vorraus, sonst klappt alles.
Und die Positionen die ich mit getx... ermittelt habe wie soll ich die so festlegen das die dort starten. bsp.(wie davor:
Code: Alles auswählen
Global Dim *players.player(#NUMBER_OF_PLAYERS -1)
*players(1) = newPlayer(300, 300)
schonmal danke für die antworten im vorraus, sonst klappt alles.
Benutze PB v 4.40 Beta 3
Ganz einfach, Du bastelst Dir eine newPlayer()-Funktion:
Die setPlayerX()-Funktion muß aber auch wieder 100% sicher sein, d.h. hier mußt Du die lastTime des Players dann wiederum auf die aktuelle Zeit setzen usw.
Code: Alles auswählen
Procedure.l newPlayer(x, y, z, time)
*new = AllocateMemory(SizeOf(player))
setPlayerX(*new, x, time)
setPlayerY(*new, y, time)
; und anderen initialisierungskram...
ProcedureReturn *new
EndProcedure


ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Es kalppt nu bis auf eine kleinigkeit.
ist Invalid memoryacess.
was kann ich dagegen machen?
Code: Alles auswählen
Procedure getPlayerX(*p.player, currentTime)
ProcedureReturn *p\xPos
EndProcedure
Procedure getPlayerY(*p.player, currentTime)
ProcedureReturn *p\yPos
EndProcedure
Procedure getPlayerZ(*p.player, currentTime)
ProcedureReturn *p\zPos
EndProcedure
was kann ich dagegen machen?
Benutze PB v 4.40 Beta 3
wie jetzt?
Hier sind bestimmt einige fehler:
Wenn ich diese Probleme soweit geschaft habe das es läuft werde ich mich um Update Player kümmern
Hier sind bestimmt einige fehler:
Code: Alles auswählen
#NUMBER_OF_PLAYERS = 4
Structure movingObject
xPos.f
yPos.f
zPos.f
lastTime.l
entity.l
EndStructure
Structure Player Extends movingObject
lives.b
score.l
energy.l
EndStructure
Procedure getPlayerX(*p.player, x, currentTime)
ProcedureReturn *p\xPos
EndProcedure
Procedure getPlayerY(*p.player, y, currentTime)
ProcedureReturn *p\yPos
EndProcedure
Procedure getPlayerZ(*p.player, z, currentTime)
ProcedureReturn *p\zPos
EndProcedure
Procedure.l newPlayer(x, z, y, time)
*new = AllocateMemory(SizeOf(player))
getPlayerX(*p.player, x, time)
getPlayerZ(*p.player, z, time)
getPlayerY(*p.player, y, time)
ProcedureReturn *new
EndProcedure
Global Dim *players.player(#NUMBER_OF_PLAYERS -1)
*players(1) = newPlayer(300, 300, 200, currentTime)
Procedure renderPlayer(*p.player, currentTime)
CameraLocate (0, getPlayerX(*p.player, x, currentTime) - Cos(2*#PI*(rot/360))*15, TerrainHeight(getPlayerX(*p.player, x, currentTime),getPlayerZ(*p.player, z, currentTime))+10, getPlayerZ(*p.player, z, currentTime) + Sin(2*#PI*(rot/360))*15)
EntityLocate(*p\entity, getPlayerX(*p.player, x, currentTime), TerrainHeight(getPlayerX(*p.player, x, currentTime),getPlayerZ(*p.player, z, currentTime)), getPlayerZ(*p.player, z, currentTime))
EndProcedure
;...
Repeat
currentTime = ElapsedMilliseconds()
For i = 0 To #NUMBER_OF_PLAYERS -1
renderPlayer(*players(i), currentTime)
Next i
Benutze PB v 4.40 Beta 3