Netzwerkfähiges Pong Spiel

Status
Nicht offen für weitere Antworten.

IceTi

Bekanntes Mitglied
Hi,

ich muss für die Uni eine Pong Spiel in einem Applet machen.
Dieses Spiel soll dann auch Netzwerkfähig sein (mit einer Socket Verbindung).

Das Spiel ist soweit kein Problem eine einfache Socket Verbindung habe ich auch schon (aus den FAQ´s hier).
Nun weiss ich aber nicht genau wie ich das machen soll.
Als erstes möchte ich erstmal die Punkte für Player1 und Player2 an den Server schicken und der muss diese dann ahlt an die beiden Client verschicken. Nur wie handle ich das mit zwei verschiedenen Punkteständen ?

Könnt ihr mir da weiter helfen?

DANKE
 
ich würde die spielelogik komplett vom server steuern lassen, so dass sich die clients die punktstände beim server abholen.

Die clients sind sozusagen nurnoch für die bewegung der paddel zuständig.
die paddelpossition werden an den server gegeben.
der Ball wird ebenfalls von dem server verwalltet, und die clients holen sich die possition des balls nur zum zeichnen vom server ab.

damit dürfte das alles eigendlich kein Problem darstellen, oder habe ich dich jetzt falsch verstanden
 
Stimmt, so muss das auf jeden Fall realisiert werden....

Nur wie verschicke ich z.B. dann die Ball Koordinaten, und die Punkte stände und wie unterscheidet der Cleint dann was was ist?
 
da musst du dir entweder ein eigenes textbasiertes protokoll entwickeln alà "POSS:<x><y>" oder du verwendest einen ObjectStream und versendest gleich ganze objecte über den Stream alà clientStream.write(pos)
 
Damit kann ich jetzt erstmal gar nichts anfangen 🙂

Vielleicht fange wir mal damit aa, das der Server die Punkte verwaltet und hochzählt u.s.w.

Da weiß cih auch schon nicht wie ich anfagen soll.
P1 punktet schickt an den Server " ich habe einen Punkt gemacht" der Server zählt eine Variabe hoch und schickt den Wert an beide Clients.. wie mache ich das ?
 
moment, vieleicht erst man grundsätzlich, die beiden clients sollen auf dem selben speilfeld gegeneinander spielen, oder?
und wenn du jetzt wie gesagt den ball vom server verwalten läst, dann erkennt der server wann jemand gepunktet hat, und senden dann den neuen Punktestand an die clients.
 
Wie genau meinst du das?
Es soll so sein, dass der Server z.B. auf meinem Notebook läuft. Ich dann von meinem PC speilen kann und vom Notebook auch.

Oder habe ich die Frage falsch verstanden ?
 
Dein Notebook kann doch Server und Client sein...

Erkläre mal genauer wie du es die vorstellst!
 
Genau! Auf dem Notebook läuft der Server und ich spiele auch damit (als Client halt) und vom PC aus spiele ich auch.

Ich weiss ja schon wie ich z.B. Zahlen zum Server schicken kann, aber der weiss dann ja nicht ob das nun von Player1 oder 2 kommt.


EDIT: Ich brauche erstmal sowas wie eine Anmeldung... Ich möchte auch noch so ein Menü machen wo man halt wählen kann, dass man ein Spiel erstellt oder ob man beitreten möchte.... Der Player der das Spiel erstellt ist dann halt Player 1 und der andere 2... aber WIE mache ich das ?
 
Warum nicht? Wenns vom einen Client kommt (eigener Socket) kann's ja nicht vom anderen kommen. Alles eindeutig. Also warum sollte der Server das nicht unterscheiden können?
 
omg, ok ich hab dich falsch verstanden.
ich dachte es sollen immer 2 gegeinander spielen.

Du musst einfach für jeden client der sich an dem server anmelded einen thread starten (Klasse Thread) der die daten des Klients verwaltet (Socket, punkte ...) damit hast du automatisch für jeden client einen eigen thread mit eigenen streams, wodurch du nichtmehr zuornen must wass von wem kommt.
 
Folgenden Ablauf kann ich mir vorstellen:
- Server läuft
- Clients verbinden sich mit Server --> bekommen ID zugewiesen
--> Anhand dieser ID sind sie absofort eindeutig identifizierbar
- Server berechnet Ball-Koordinaten, verwaltet Punkte
- Clients können über ihrer ID auch ihre Punkte erfahren
- ...

#edit :
Willst du nun gegeneinander oder allein spielen?
Wie Jojo sagt, für jedes Spiel ein extra Thread
 
das hört sich gut an ... einen "Haupt" Thread habe ich schon am laufen... wie mache ich nun einen 2ten oder wie weisse ich jeweils einem Thread einen Player zu ?


EDIT: Auch das mit der ID hört sich gut an (wobei das mit den Threds noch besser ist), aber da auch die Frage wie soll ich das machen.

Hier mal ein bisschen Code:
Code:
import java.io.*;
import java.net.*;
import java.util.*;

public class PongServer {
  
	public static void startServer() throws IOException{
		ServerSocket server = new ServerSocket(1234);						// Neuer Server, welcher auf Port 1234 lauscht
		System.out.println("Server started...");								// Ausgabe
	
		while(true) {
			Socket s = server.accept();														// Auf Verbindungen warten...
			ServerThread th = new ServerThread(s);								// Kommunikation an einen nebenläufigen Thread abgeben
			th.start();																						// Thread wird gestartet															
		}
	}
	
	
	
	public static void main(String[]args) throws Exception{
		startServer();
	}
}

ThreadClass:
Code:
import java.io.*;
import java.net.*;
import java.util.*;
	


public class ServerThread extends Thread{
	private Socket s;
	int AnzahlPlayer = 2;
	int PunktePlayer1 = 0;
	int PunktePlayer2 = 0;

	
	
	// Konstruktor
	public ServerThread(Socket s) {
	this.s = s;
	}

public void run(){
	
	try{
		BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
		String punkte= in.readLine();
		System.out.println(punkte);
				
		//BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

		//out.write(text);
		//out.newLine();
		
		in.close();
		//out.flush();
		//out.close();

	}catch(IOException e){
		System.out.println(e);
	}
}
}
 
Mein Client sieht so aus:
Code:
public class PongClient extends Ball{
	Socket PongServer;
	int port = 1234;
	String serverName = "localhost";
	int spielerpkt = 0;
	String test = "nix";

	public void setSpielerPkt(int p){
		spielerpkt = p;
	}
	
	
PongClient() throws IOException{

	PongServer = new Socket (serverName, port);
	BufferedWriter out = new BufferedWriter(new OutputStreamWriter(PongServer.getOutputStream()));
	out.write("Client verbunden!");
	out.newLine();
	out.flush();
	out.close();
}
}


Wie mache ich das nun genau mit den beiden Threads ?
Ich guck mir die Seite gleich mal an...
 
Lesetipp :###
Threads / Insel


Kurzform:
Verwalte die Threads in einem Pool (Bsp: Hashtable: Key=ThreadID, Wert=Thread). Da dem Client ja seine ThreadID bekannt, ist eine Zuordnung permanent möglich...

#edit: Mein Gott war ich langsam...
 
:-(

irgendwie blicke ich da jetzt gar nicht mehr druch....
Ein Client connected sich also und startet den Thread und der läuft bis dan applet geschlossen wird.
Verbindet sich nun ein 2. Client muss auch eine 2.Thread gestartet werden oder?

Wie mache ich das den in meinem Code ?
 
Hoi,

Hauptthread ist schonmal gut...
...für jeden akzeptierten Client startest Du einen Thread in dem eine Endlosschleife läuft. Da gibts viele Beispiele für(auch hier im Forum)

In der Schleife kannst Du ereignisse abarbeiten.
So ein Ereignis könnte sein, dass der Server eine Nachricht schickt.
Nachrichten können zB die Position des Balles beinhalten oder die Punkte oder das das Spiel zu ende ist.
Dazu kannst Du Dir ein protokoll ausdenken(wie oben angefangen)
POS:x/y
PKT😛1/3
PKT😛2/5
WIN😛2
LOS😛1

Die Nachrichten werden vom Server immer an alle Clients gesendet. In der Nachricht stehen eben die Dinge die Du auf der Oberfläche updaten muss.
Also auch mind. einen Thread pro Client der die Nachrichten des Servers verarbeitet.

Ganz klar muss der Server die Logik und alle Daten verwalten, sonst sendest Du Dich tot mit Nachrichten und musst mit Inkonsitenz leben(meistens).
Also gibts im Server Konstrukte die die daten verwalten. Schreib Dir Methoden/Klassen, die die Werte in "Nachrichten" verpacken und an alle verbundenen Clients senden.
Clients kannst Du in Maps oder Collections speichern im Server, damit Du weißt, wer alles mitspielt.

Lies Dir ein paar Beispiele zum Multithreading durch. Da steht das grundlegendste.

Die Client senden, wie gesagt auch Nachrichten an den Server. Der muss diese verarbeiten und neue Nachrichten an alle Clients senden.

!! Also nicht denken, wenn der Client sein Paddel bewegt, dass Du das direkt in Deinem Applet zeichnest. Schick die Bewegung zum Server, warte auf die Antwort und zeichne das. Sonst bekommst ein verbuggtes Game 🙂 !!!


Frag ruhig, aber lies Dir erstmal ein paar Beispiele durch und teste. Leuchtspurmunition. Einfache Beispiele obs klappt, dann kommen schon noch genug Fragen auf....

greetz
SLi
 
Ufff... ich bin totaler Anfänger was Socket und Threads angeht....
Wie mache ich mir Protokolle?

Naja... aber danke für die Tipps auch wenns ein bisschen viel auf einmal für mich ist... wollte doch erstmal mit den Punkten anfangen...
 
Protokoll hört sich komplizierter an als es ist. Es geht dabei eigentlich um nichts anderes, als dass du dir Regeln für die Kommunikation festlegst. Somit weißt du wie die Daten die du sendest aufgebaut sind.

Das heisst du kannst zum Beispiel ein textbasiertes Protokoll erstellen, dass ist erstmal nichts weiter als ein String.

Bsp: für Ballkoordianten und die Punkte
Code:
int x = 3; // x koordinate
int y = 8; // y koordinate
int p1 = 2 // Punkte Spieler 1
int p2 = 1 // Punkte Spieler 2
String prtkl = "";
prtkl = prtkl.concat("POS_x:"+x);
prtkl = prtkl.concat("\nPOS_y:"+y);
prtkl = prtkl.concat("P1:"+p1);
prtkl = prtkl.concat("P2:"+p2);

// sende den String prtkl

Du weißt also nun wie dein String aufgebaut ist. Am Client kannst du ihn nun zeilenweise einlesen. Dann prüfst du einfach was vor dem Doppelpunkt steht und schon weißt du welche variable, welchen Wert hat.
 
genau.

Ein simples protokoll ist zB FTP oder auch HTTP.
Es stellt Regeln auf, wie eine Nachricht, ein String, aussehen und interpretiert werden muss.

HTTP:

GET /index.html (sagt dem Server, dass er die datei index.html zurücksenden soll)

FTP:

PUT c:\test\text.txt (sagt dem server, dass er eine Datei bekommt)


Alternativ zu Protokollen kannst Du auch serialisierte Objekte verwenden, die alle Informationen beinhalten. Also zum Beispiel eine Klasse die Serializable implementiert und somit über einen Stream verschickt werden kann. Diesen Stream nimmst Du auf und baust Dir wieder ein Objekt, so ein, wie es verschickt wurde(also vom gleichen "Klassen" Typ) dann hast Du alle Daten die Du brauchst.

ZB:
int nBallCoordX;
int nBallCoordY;
int nPaddelCoordPlayerOneX;
int nPaddelCoordPlayerOneY;
.
.
.
int nPointPlayerOne;
...
usw.

Verstehst?

Dann brauchst Du kein Protokoll, sondern hast alle wichtigen Daten in einem Objekt. Nachteil ist, das die Netzwerklast höher ausfallen KANN. Muss man abschätzen wieviele daten in einem bestimmten zeitraum geschickt werden müssen. Für alles braucht man Overheaddaten, die von protokollen wie TCP/IP kommen(damit hast Du aber durch die Socketklassen nichts zu tun)

greetz
SLi
 
mensch nu verwirt den mal ni so, ich glaube IceTi hat erstmal genug für die nächsten tage 😉
 
Ich guck mir grad mal die Seite an die mir "der JoJo" geschickt hat, ich programmiere das mach "nach" damit ich erstmal einen MultiThreading Server habe ... dann guck ich mal weiter ...
 
Stellt der Server eigentlich die Dienste für mehrere Spiele, oder jeweils nur für zwei Spieler, die ein Spiel eröffnen?
 
der JoJo hat gesagt.:
du musst eine eigene classe z.b. ServerThread implementieren die von Thread abgeleitet ist. wenn sich jetzt ein neuer Client anmelded, startest du mit new ServerThread(clientSocket).start() einen neuen thread für diesen client

guck dier dazu am besten mal das hier an: www.ingamers.de/coding-java/multithreaded-server-7838.html

#edit: ja so meinte ich das


Habe dieses Programm nun mal achprogrammiert, wenn ich dann das main Programm starte, stehet da krurz "Listening on Port 1200" und dann wird das Fenster wieder geschlossen, er startet den Thread oder so wohl irgendwie nicht....
Was mache ich falsch?

Und verstehe ich das richtig, wenn sich dort ein Cleint verbindet, wird dieser dann in einen Thread gepackt, wenn sich der 2. verbindet wird dieser in einen anderen Thread gesteckt oder?

Wie kann ich dann auf Varibeln aus Thread1 (Cleint1) und umgekehrt zugreifen ??

DANKE
 
für den zugriff must die die clients in einer Liste speichern, bzw. wenn es eh immer nur 2 sein sollen kannst du ja zwei threads anlegen alà
Code:
ClientWorker client1 = null;
ClientWorker client2 = null;

in deiner hauptschleife vom server schreibst du dann
Code:
public void Run()
{
  int anzClients = 0;
  try
  {
    while(true)
    {
      sckClient = sckServer.accept();
      System.out.println("Incoming Connection from " + sckClient.getInetAddress());
      switch(anzClients)
      {
        case 0: client1 = new ClientWorker(sckClient);break;
        case 1: client2 = new ClientWorker(sckClient);break;
        default: System.err.println("Fehler");
      }
      anzClients++;
    }
  }
  catch(IOException e)
  {
    //Error-Output
  }
}

jetzt musst du nurnoch deiner ClientWorker classe die passenden Methoden zum datenaustausch spendieren und Fertig.
Du kannst dann nähmlich aus der runn methode von client1 mit client2.doSomeThing() auf client2 zugreifen und andersherrum. du musst nur immer vorher prüfen, ob der client nicht null ist.
 
Ich hab das nun so: Hier erstmal die Run() Methode vom Server:



Code:
	  public void Run(){

    try{
      while(true){
      Client = Server.accept();
      System.out.println("Incoming Connection from " + Client.getInetAddress()+" accept");
      switch(anzClients)
      {
        case 1: client1 = new ClientWorker(Client);break;
        case 2: client2 = new ClientWorker(Client);break;
        default: System.err.println("Fehler");
      }
      System.out.println(anzClients+" Client(s) verbunden");
      anzClients++; 
      
      }
    }
    catch(IOException e){
    }
  }



Und hier der ClientWorker:
Code:
import java.io.*;
import java.net.*;

public class ClientWorker implements Runnable{
	 
  private Socket Client;
  private BufferedReader in;
// 	private PrintWriter out;
	private BufferedWriter out;
  private Thread runner;
  private int Score = 0;


  public ClientWorker(Socket Client){
  this.Client = Client;

    try{
      in = new BufferedReader(new InputStreamReader(Client.getInputStream()));
     // out = new PrintWriter(new OutputStreamWriter(Client.getOutputStream()));
			out = new BufferedWriter(new OutputStreamWriter(Client.getOutputStream()));

      runner = new Thread(this);
      runner.start();
    }
    catch(IOException e){
    }
  }
  

  public void run(){
    try{
      while(true){
      	
        String rawPacket = in.readLine();
         if(rawPacket != null){
         		if(rawPacket.equals("GiveMeMyScore")){
						sendScore();
						}
          	ProcessPacket(rawPacket);

        }
        else{
          Client.close();
          Client = null;
          runner = null;
          break;
        }
      }
    }
    catch(IOException e){
    }
  }

  public void ProcessPacket(String rawPacket){
    System.out.println("Incoming Packet: " + rawPacket);
         	}


  

	public void sendScore()throws IOException{
		        Score +=1;
         		out.write(""+Score);
         		out.newLine();
         		out.flush();
	} 
}


Macht der Client nun einen Punkt, wird auf dem Client die Methode setScore() aufgerufen, diese schickt der Server den Text "GiveMeMyScore" der Server Antwortet dann mit und zählt eine Variable Score einen höher.
1. Frage: Das ist bestimmt schoneinmal ziemlich doof gelöst oder ?
Wie bekomme ich das besser hin?

Nun meldet sich ein 2. client an und für den werden dann halt die Punkte seperat gezählt.
Meine 2. Frage ist nun wie kann ich dem 2. Client die Punkte des 1. Clients schicken ??


VIELEN DANK erstmal für alle Antworte, ich glaube so langsam komme ich voran ;-)
 
wenn wirklich immer nur zwei leute spielen sollen, kannst du ja dem ClientWorker eine Methode setMitspieler(ClientWorker mitspieler) geben, die du aufrufst, sobald sich ein zweiter spieler anmeldet. Damit kennen sich dann die Clients untereinander und können Nachrichten über public methoden austauschen ... Äh, ich hoffe du verstehst mich
 
Hmm so richtig vertehe ich das nicht, kannst du das etwas genauer erklären?
 
ok anders ausgedrückt.

du musst der Klasse ClientWorker eine neue Variable geben, und eine setter dafür berreit stellen:
Code:
class ClientWorker
{
  private ClientWorker mitspieler = null;

  public void setMitspieler(ClientWorker mitspieler)
  {
    this.mitspieler = mitspieler;
  }
  ...

dann must du die switchanweisung im serverthread erweitern:

Code:
switch(anzClients)
{
  case 1: client1 = new ClientWorker(Client);break;
  case 2:
  {
    client2 = new ClientWorker(Client);break;
    //weise die mitspieler zu
    client1.setMitspieler(client2);
    client2.setMitspieler(client1);
  }
  default: System.err.println("Fehler");
}

jetzt kannst du zum datenaustausch in der run methode des ClientWorkers zum beispiel folgendes machen:

Code:
while(true)
{
  String rawPacket = in.readLine();
  if(rawPacket != null)
  {
    if(rawPacket.equals("GiveMeMyScore"))
    {
      sendScore();
      mitspieler.sendeAuchWas(); //hier kannst du daten an den Mitspieler senden
    }
    ProcessPacket(rawPacket);
  }
  ...
 
der JoJo hat gesagt.:
Code:
switch(anzClients)
{
  case 1: client1 = new ClientWorker(Client);break;
  case 2:
  {
    client2 = new ClientWorker(Client);break;
    //weise die mitspieler zu
    client1.setMitspieler(client2);
    client2.setMitspieler(client1);
  }
  default: System.err.println("Fehler");
}

:meld: Wird nicht ganz klappen - "break;" muss am Ende des "case2"-Blocks stehen.

--> scheiss Besserwisser :wink:
 
Ok, dass werde ich nachher mal machen... Wie mache ich das den eleganter mit dem "GiveMeMyScore" ??

Das geht doch bestimmt auch anders oder ? Irgendwie mit den Protokollen oder so ?

DANKE
 
das ist doch eine Form eines Protokolls, du hast festgelegt, wenn der Client sendet "GiveMeMyScore", sendest du ihm die score. Gennau das ist ein Protokoll.
 
hmm also irgendwie will das immer noch nicht, es funzt nur so das jedes neugestartet Applet seine Eigenen Punkte gezählt bekomme.

Wie mache ich das, das sich quasi 2 Applets zusammen tuen und die selben Daten vom Server bekommen und nicht getrennt ?

Das bekomme ich noch nich tso richtig hin
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben