# PongSpiel Netzwerk



## Minti (11. Mai 2015)

Guten Tag,

Ich habe die Aufgabe bekommen ein Netzwerk für ein SpielProjekt zu erstellen in der Uni. Dabei handelt es sich um ein Pongspiel welches mit Javafx geschrieben wurde. Dabei haben wir alle Klassen im MVC-Prinzip eingeteilt.
Auch habe ich schon einen (Chat)Server geschrieben/frankenstein'd/ aus anderen Beispielen zusammengebastelt der auf eine Nachricht von einem Client wartet und diese dann anschließend an alle anderen Clients schickt

Jetzt zum eigentlichen Problem:

Ich bekomme es einfach nicht das Spiel mit sowohl Server als auch Client zu verbinden. Mein Ansatz den ich gerade hätte wäre dieser:

Der Client (beinhaltet nur Keylistener und den View) schickt bei einem Tastendruck eine Nachricht an den Server.
Dieser wiederum hat Kontrolle über den Rest des Controllers und der Modelklasse und führt alle Berechnungen durch. Danach schickt er wieder alle relevanten Informationen ( Positionen der Schläger und des Balles) wieder zu einem "Clientthread" zurück der dann wiederum auf die lokale Modelklassen schreibt. Schlussendlich liest der Client wieder von der dieser lokalen Modelklasse zurück und stellt alles auf der Timeline dar.

Davor habe ich schon versucht meinen gesamten Controller in den Client hineinzupacken, jedoch war dann das Spielfenster gefreezed als der Client sich verbunden hatte.

Ist diese Einteilung von Aufgaben sinnvoll und wie bekomme ich es zum Beispiel hin einen KeyListener in den Client zu implementieren. Da habe ich zur Zeit die meisten Probleme..


Javacode: 
Controller:

```
package controller;

import view.LocalMultiView;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
import javafx.geometry.Bounds;
import model.Player;
import model.ScreenModel;


public class LocalMultiController 
{


//    private model.RacketModel racketModel;
//    private model.BallModel ballModel;
    private ScreenModel model;
    private view.LocalMultiView view;
    private Integer i = 0;


    private Player life1;
    private Player life2;


    
    public LocalMultiController (ScreenModel model)
    {
//        this.racketModel = new RacketModel();
//        this.ballModel = new BallModel();
        this.view = new LocalMultiView();
        this.model = model;
        
        this.life1 = new Player(3);
        this.life2 = new Player(3);
        
        addEvent();
    }
    
    public void show ()
    {
        view.show(model.getStage());
    }
    
    public void addEvent ()
    {
        final Circle ball = view.getBall();
        final Rectangle schlaeger1 = view.getRacket1().getRacket();
        final Rectangle schlaeger2 = view.getRacket2().getRacket();
        Scene scene = view.getPlayScene();
        final Pane canvas = view.getPane();
        
        
        /**
         * Eventhandler für linken Schläger: S: runter, W: hoch
         */
        scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() 
                {
            public void handle(KeyEvent ke) 
            {
                double yPos1 = schlaeger1.getY();
                if (ke.getCode() == KeyCode.S) 
                {
                    if ((yPos1 + schlaeger1.getHeight() + 20) > canvas.getBoundsInLocal().getMaxY()) 
                    {
                        yPos1 = canvas.getBoundsInLocal().getMaxY() - schlaeger1.getHeight();
                    } 
                    else 
                    {
                        yPos1 += 20;
                    }
                    schlaeger1.setY(yPos1);
                } 
                else if (ke.getCode() == KeyCode.W) 
                {
                    if (yPos1 - 20 < 0) 
                    {
                        yPos1 = 0;
                    } 
                    else 
                    {
                        yPos1 -= 20;
                    }
                    schlaeger1.setY(yPos1);
                }
            }
        });
        
        /**
         * Eventhandler für rechten Schlaeger: Pfeil hoch: hoch, Pfeil runter: runter
         */
        scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() 
                {
            public void handle(KeyEvent ke) 
            {
                double yPos2 = schlaeger2.getY();
                
                if (ke.getCode() == KeyCode.DOWN) 
                {
                    if ((yPos2 + schlaeger2.getHeight() + 20) > canvas.getBoundsInLocal().getMaxY()) 
                    {
                        yPos2 = canvas.getBoundsInLocal().getMaxY() - schlaeger2.getHeight();
                    } 
                    else 
                    {
                        yPos2 += 20;
                    }
                    schlaeger2.setY(yPos2);
                } 
                else if (ke.getCode() == KeyCode.UP) 
                {
                    if (yPos2 - 20 < 0) 
                    {
                        yPos2 = 0;
                    } 
                    else 
                    {
                        yPos2 -= 20;
                    }
                    schlaeger2.setY(yPos2);
                }
            }
        });


        /**
         * Timeline mit unendlicher Wiederholung alle 20 Millisekunden
         * für die Bewegung des Balls
         */
        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(20),
                new EventHandler<ActionEvent>() 
                {
                    double xPos = 3;
                    double yPos = 5;


                    @Override
                    public void handle(ActionEvent arg0) 
                    {
                        /*
                        // Every 20 frames 10% faster
                        if (i++ % 50 == 0) {
                            xPos += (xPos<0 ? -1 : 1) * 0.5;
                            yPos += (yPos<0 ? -1 : 1) * 0.5;
                        }
                        */
                    
                        double oldX = ball.getLayoutX();
                        double schlaeger1CollisionX = schlaeger1.getX() + schlaeger1.getWidth();
                        double schlaeger2CollisionX = schlaeger2.getX();
                        
                        
                        ball.setLayoutX(ball.getLayoutX() + xPos);
                        ball.setLayoutY(ball.getLayoutY() + yPos);


                        Bounds bounds = canvas.getBoundsInLocal();
                        //Kollision unten
                        boolean boundBottom = ball.getLayoutY() >= (bounds
                                .getMaxY() - ball.getRadius());
                        
                        //Kollision oben
                        boolean boundTop = (ball.getLayoutY() - ball.getRadius()) <= 0;
                        
                        //Kollision rechts
                        boolean boundRight = ball.getLayoutX() >= (bounds
                                .getMaxX() - ball.getRadius());
                        
                        //Kollision links
                        boolean boundLeft = (ball.getLayoutX() - ball.getRadius()) <= bounds.getMinX();
                        
                        //Kollision Schlaeger
                        boolean boundSchlaeger1 = ball.getLayoutX() - ball.getRadius() <= schlaeger1CollisionX && oldX >= schlaeger1CollisionX && ball.getLayoutY() + ball.getRadius() >= schlaeger1.getY() && ball.getLayoutY() - ball.getRadius() <= schlaeger1.getY() + schlaeger1.getHeight() && xPos < 0;
                        boolean boundSchlaeger2 = ball.getLayoutX() + ball.getRadius() >= schlaeger2CollisionX && oldX <= schlaeger2CollisionX && ball.getLayoutY() + ball.getRadius() >= schlaeger2.getY() && ball.getLayoutY() - ball.getRadius() <= schlaeger2.getY() + schlaeger2.getHeight() && xPos > 0;
                        
                        //Richtungswechsel
                        if (boundBottom || boundTop) 
                        {
                            yPos *= -1;
                        }
                        //Abprallen
                        if (boundSchlaeger2 || boundSchlaeger1) 
                        {
                            xPos *= -1;
                        }
                        
                        if (boundLeft)
                        {
                            ball.relocate(20, 30);
                            xPos = 3;
                            yPos = 5;
                            life1.subLife();
                            System.out.println("Sp1: " + life1.getLife());
                        }
                        
                        if (boundRight)
                        {
                            ball.relocate(20, 30);
                            xPos = 3;
                            yPos = 5;
                            life2.subLife();
                            System.out.println("Sp2: " + life2);
                        }
                        
                        if (life1.getLife() == 0)
                        {
                            xPos = 0;
                            yPos = 0;
                            // To-Do Player2 hat gewonnen
                            //Try again
                        }
                        if (life2.getLife() == 0){
                            xPos = 0;
                            yPos = 0;
                            //To-Do Player1 hat gewonnen
                            //Try again
                        }
                        
                    }
                }));
        
        // unendliche Anzahle an Wiederholungen
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();
    }
}
```

Server:

```
package net;


import java.io.*;
import java.net.*;
import java.util.*;




public class Server {
    


    private ArrayList<ClientThread> ClientListe;
    private int port;
    private boolean Loopjanein;
    
    public Server(int port) {


        this.port = port;
        ClientListe = new ArrayList<ClientThread>();
    }
    
    public void start() {
        Loopjanein = true;
                try 
        {
            


            ServerSocket serverSocket = new ServerSocket(port);
            while(Loopjanein) 
            {
                // format message saying we are waiting
                System.out.println("Server waiting for Clients on port " + port + ".");
                Socket socket = serverSocket.accept();      
                if(!Loopjanein) 
                    break;
                ClientThread t = new ClientThread(socket);
                ClientListe.add(t);                                    
                t.start();                                    
            }    


            try {
                serverSocket.close();
            }catch(Exception e) {}
        }    catch (IOException e) {
        }
    }        


    private void display(String msg) {
        String yay = " " + msg;
        System.out.println(yay);


    }


    private synchronized void allsenden(String message) { // broadcast
        String Message = message + "\n";
        System.out.print(Message);
        
        for(int i = ClientListe.size(); --i >= 0;) {
            ClientThread ClientT = ClientListe.get(i);
            if(!ClientT.writeMsg(Message)) {
                ClientListe.remove(i);
                display("Disconnected Client " + ClientT.username + " removed from list.");
            }
        }
    }




    synchronized void rm(int id) {
        for(int i = 0; i < ClientListe.size(); ++i) {
            ClientThread ct = ClientListe.get(i);
            if(ct.id == id) {
                ClientListe.remove(i);
                return;
            }
        }
    }


    public static void main(String[] args) {
        int portNumber = 1500;
        Server server = new Server(portNumber);
        server.start();
    }


    /** One instance of this thread will run for each client */
    public class ClientThread extends Thread {
        Socket socket;
        ObjectInputStream sInput;
        ObjectOutputStream sOutput;
        OutputStream OS;
        int id;
        String username;
        ChatMessage cm;
        ClientThread(Socket socket) {


            this.socket = socket;
            System.out.println("Thread trying to create Object Input/Output Streams");
            try
            {
                sOutput = new ObjectOutputStream(socket.getOutputStream());
                sInput  = new ObjectInputStream(socket.getInputStream());
                username = (String) sInput.readObject();
                display(username + " just connected.");
            }
            catch (IOException e) {
                display("Exception creating new Input/output Streams: " + e);
                return;
            }
            catch (ClassNotFoundException e) {
            }


        }


        public void run() {
            boolean keepGoing = true;
            while(keepGoing) {
                try {
                    cm = (ChatMessage) sInput.readObject();
                }
                catch (IOException e) {
                    display(username + " Exception reading Streams: " + e);
                    break;                
                }
                catch(ClassNotFoundException e2) {
                    break;
                }


                String message = cm.getMessage();
                switch(cm.getType()) {
                case ChatMessage.MESSAGE:
                    allsenden(username + ": " + message);
                    break;
                case ChatMessage.LOGOUT:
                    display(username + " disconnected with a LOGOUT message.");
                    keepGoing = false;
                    break;


                }
            }


            rm(id);
            close();
        }
        
        private void close() {
            try {if(sOutput != null) sOutput.close();}
            catch(Exception e) {}
            try {if(sInput != null) sInput.close();}
            catch(Exception e) {};
            try {if(socket != null) socket.close();}
            catch (Exception e) {}
        }
        private boolean writeMsg(String msg) {
            if(!socket.isConnected()) {
                close();
                return false;
            }
            try {
                sOutput.writeObject(msg);
            }
            catch(IOException e) {
                display("Error sending message to " + username);
                display(e.toString());
            }
            return true;
        }
    }
}
```

Client:

```
package net;import java.net.*;
import java.io.*;
import java.util.*;


import model.ScreenModel;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;


public class Client  {


    private ObjectInputStream sInput;        
    private ObjectOutputStream sOutput;        
    private Socket socket;


    private static ScreenModel model;
    private static view.LocalMultiView view;
    private static Integer i = 0;
    private String server, username;
    private int port;




    public Client(String server, int port, String username) {
        this.server = server;
        this.port = port;
        this.username = username;


    }


    public boolean start() {


        try {
            socket = new Socket(server, port);
        } 


        catch(Exception ec) {
            display("Error connectiong to server:" + ec);
            return false;
        }
        
        String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
        display(msg);
    


        try
        {
            sInput  = new ObjectInputStream(socket.getInputStream());
            sOutput = new ObjectOutputStream(socket.getOutputStream());
        }
        catch (IOException eIO) {
            display("Exception creating new Input/output Streams: " + eIO);
            return false;
        }




        new ListenFromServer().start();


        try
        {
            sOutput.writeObject(username);
        }
        catch (IOException eIO) {
            display("Exception doing login : " + eIO);
            disconnect();
            return false;
        }


        return true;
    }




    private void display(String msg) {


            System.out.println(msg);      


    }
    


    public void sendMessage(ChatMessage msg) {
        try {
            sOutput.writeObject(msg);
        }
        catch(IOException e) {
            display("Exception writing to server: " + e);
        }
    }




    private void disconnect() {
        try { 
            if(sInput != null) sInput.close();
        }
        catch(Exception e) {} 
        try {
            if(sOutput != null) sOutput.close();
        }
        catch(Exception e) {}
        try{
            if(socket != null) socket.close();
        }
        catch(Exception e) {} 
    }


    public static void main(String[] args) {


        int portNumber = 7777;
        String serverAddress = "localhost";
        String userName = "Anonymous";


        switch(args.length) {
            case 3:
                serverAddress = args[2];
            case 2:
                try {
                    portNumber = Integer.parseInt(args[1]);
                }
                catch(Exception e) {
                    System.out.println("Invalid port number.");
                    System.out.println("Usage is: > java Client [username] [portNumber] [serverAddress]");
                    return;
                }
            case 1: 
                userName = args[0];
            case 0:
                break;
            default:
                System.out.println("Usage is: > java Client [username] [portNumber] {serverAddress]");
            return;
        }
        Client client = new Client(serverAddress, portNumber, userName);
        if(!client.start())
            return;
            


        Scanner scan = new Scanner(System.in);
        while(true) {  // waypoint


            String msg = scan.nextLine();
            if(msg.equalsIgnoreCase("LOGOUT")) {
                client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, ""));
                break;
            }
            else if(msg.equalsIgnoreCase("WHOISIN")) {
                client.sendMessage(new ChatMessage(ChatMessage.WHOISIN, ""));                
            }
            else {
                client.sendMessage(new ChatMessage(ChatMessage.MESSAGE, msg));
            }
        }


        client.disconnect();    
    }








    class ListenFromServer extends Thread {


        public void run() {
            while(true) {
                try {
                    String msg = (String) sInput.readObject();
                        System.out.println(msg);




                    }


                catch(IOException e) {
                    display("Server has close the connection: " + e);


                    break;
                }
                catch(ClassNotFoundException e2) {
                }
            }
        }
    }
}
```

Ich probiere es jetzt mal aus den Controller im größten Teil einfach so zu lassen, jedoch bei den KeyEventlistener Methoden ausführen zu lassen die im Client stehen und die wiederum Nachrichten an den Server schicken.

Grüße Minti


----------



## Major_Sauce (17. Mai 2015)

Tach,

ich bin gerade bei meinem ersten JavaFX Projekt und ich habe das ganz einfach gelöst:

Ich habe das so gelöst:

Key Listener:

```
package controlls;

import java.util.ArrayList;

import javafx.event.EventHandler;
import javafx.scene.input.KeyEvent;

public class KeyListener implements EventHandler<KeyEvent> {

	private static ArrayList<Key> keys = new ArrayList<Key>();
	
	public void handle(KeyEvent e) {
		for(Key key : keys){
			if(key.getKeyCode() == e.getCode()){
				if(e.getEventType() == KeyEvent.KEY_PRESSED){
					key.setPressed();
				} else if(e.getEventType() == KeyEvent.KEY_RELEASED){
					key.setReleased();
				}
			}
		}
	}

	public static void registerKey(Key key){
		if(!keys.contains(key)){
			keys.add(key);
		}
	}
	
	public static void unregisterKey(Key key){
		if(keys.contains(key)){
			keys.remove(key);
		}
	}
	
}
```

Und eine Key.class :


```
package controlls;

import javafx.scene.input.KeyCode;

public class Key {

	private KeyCode keyCode;
	private boolean pressed;
	
	public Key(KeyCode keyCode){
		this.keyCode = keyCode;
		register();
	}
	
	public void setPressed(){
		pressed = true;
		onPress();
	}
	
	public void setReleased(){
		pressed = false;
		onRelease();
	}
	
	public void onPress(){}
	
	public void onRelease(){}
	
	public KeyCode getKeyCode(){
		return keyCode;
	}
	
	public void register(){
		KeyListener.registerKey(this);
	}
	
	public void unregister(){
		KeyListener.unregisterKey(this);
	}
	
	public boolean isPressed(){
		return pressed;
	}
	
}
```

wenn ich nun auf eine Tasteneingabe reagieren will mache ich sowas hier:


```
//konstruktor
public Client(){
	new Key(KeyCode.SPACE){
		@Override
		public void onPress() {
			super.onPress();
			//Hier etwas einfügen. Bsp:
			//moveUp();
		}
	};
}
```

Alternativ kannst du das auch in einer Update()-Mathode oder ähnlichem machen: 


```
private Key moveUp;

	//konstruktor
	public Client(){
		moveUp = new Key(KeyCode.SPACE);
	};

	public void update(){
		if(moveUp.isPressed()){
			//Mach wieder was...
			//moveUp();
		}
	}
```

Kannst den Code gerne verwenden, wenn du willst...

mfg Major


----------

