![]() |
|
Zum besseren Verständnis wird zunächst nochmals der Klassenaufbau der Server-Komponente aus Kapitel 3.6 angegeben. Diese Hierarchie muss um zwei Klassen erweitert werden, um die Netzwerkfunktionalität des Servers und um die Klasse Daten. Der wesentliche Unterschied zur Darstellung in Kapitel 3.6 besteht darin, dass nun anstelle der lediglich skizzierten Aufrufe der Netzwerkfunktionen die tatsächliche Implementierung erfolgt. Im Folgenden wird zunächst die main-Methode der Klasse betrachtet, die den Server selbst steuert.
Abb. 7.1: Klassenhierarchie der Server-Komponente
import java.awt.*; static ServerSpiel ss; public static void main(String[] arguments) throws IOException { while (true) { try { network = new SVServer(); } catch (IOException e) { System.out.println("IO-Exception!"); } } } Die Funktionalität dieser Methode ist leicht zu verstehen. In einer while-Schleife werden Anfragen von Clients verarbeitet. Hierbei wird zunächst eine Netzwerkanbindung erstellt. Anschließend wird die Methode spiele aufgerufen, in der die eigentliche Spielfunktionalität enthalten ist. Zu Beginn dieser Methode wartet der Server auf Daten vom Client. Hierbei wird stets davon ausgegangen, dass der Client das Spiel beginnt.
static void spiele () throws IOException{ boolean serverDran=false, spielEnde=false, einTreffer=false, zweiTreffer=false; Point koord = new Point(0,0); //Warten, bis der Client eine Position (x,y) schickt Anschließend wird ein Spieldurchlauf in einer while-Schleife ausgeführt. Hierzu werden zunächst Schüsse des Clients verarbeitet.
while (spielEnde==false) { if (serverDran ==false) { if (ss.rechnerTreffer(daten.p)) { //Wir sind getroffen, teile dies dem Client mit daten.status=daten.TREFFER; if (ss.schiffZahlServer==0) { //Wir haben verloren???? return; } //Erwarte naechsten Schuss } else serverDran=true; } Ist der Server an der Reihe, so werden Koordinaten zunächst nach dem Zufallsprinzip ausgewählt, um einen ersten Treffer erzielen zu können.
else { //Jetzt schiessen wir koord=ss.schiesseInsBlaue(); //Frage den Client ob Treffer. if (daten.status != daten.TREFFER) { einTreffer=false; } else ss.schiffZahlClient--; } Hat der Server eine Koordinate eines gegnerischen Schiffs als Anhaltspunkt, so wird im Folgenden nach einer zweiten Koordinate gesucht, um die Richtung des Schiffs bestimmen zu können.
if ((zweiTreffer==false)&& (einTreffer==true)) { koord=ss.sucheZweitenTreffer(); //Frage den Client ob Treffer. // if Treffer beim Client: Richtung des } else ss.schiffZahlClient--; } Generell werden die Sprünge in die geeignete Schleife mit Hilfe der Variablen einTreffer und zweiTreffer realisiert. Sind zwei Koordinaten eines Schiffs bekannt, so kann dieses versenkt werden, weil die Richtung bekannt ist. Hierbei ist zu beachten, dass die Information, ob ein Schiff bereits versenkt ist, nicht mitgeteilt werden muss. Der Server muss diese Information daher durch geeignete Schüsse herausfinden. Ein Schiff ist dann versenkt, wenn keine Schusskoordinaten mehr gefunden werden können, die zu einem Schiff gehören könnten.
if ((zweiTreffer==true)&& (einTreffer==true)) { //Abschuss //Schiff versenkt } else { //Frage den Client ob Treffer. serverDran = false; } else ss.schiffZahlClient--; } } Nachdem ein Schiff versenkt wurde, muss überprüft werden, ob der Gegner noch über Schiffe verfügt.
//Sind wir immer noch dran? //gewonnen network.beenden(); } }// } //while spiel } //Methode spiel }//Klasse Es wurde bereits mehrfach betont, dass das Ziel der Erstellung dieser Anwendung darin besteht, Komponenten so zu entwickeln, dass sie ohne Modifikationen größeren Umfangs kombiniert werden können. Eine Änderung der anderen Klassen des Servers ist daher nicht notwendig. |
|
|