Gioco Client/Server

di il
4 risposte

Gioco Client/Server

Ho scritto in Java con le componenti di Swing, Pong game. Tecnicamente funziona così:
Server apre l'interfaccia gioco, le due istanze di client invece inviano al server i key per muovere i due paddle.
Ora avevo lasciato il progetto, e l'ho ripreso ieri sera, quello che vorrei fare è che i due client al loro avvio abbiano l'interfaccia grafica, inviando i comandi al server che li elabora.

Il server in questo momento crea un JPanel dove gli passa oggetti Paddle1,2 e Ball. Quindi è unico. Se invece lo facessi con i client, ogni client avrebbe un'istanza di JPanel diverso.
Come dovrei procedere?

Client1 genera JPanel1 con il riferimento al Client1, Server non da avvio al gioco perchè manca un player.
Client2 genera JPanel2 con il riferimento al Client2, Server avvia il gioco, dovrebbe lui leggere i comandi e processarli e inviarli ai client. Ma non ha senso, se invece i due client comunicano tra di loro senza parlare con il server?
Oppure potrei generare il Panel dal server e inviarlo ai due client, ma lo trovo una cattiva tecnica.

Non posto il codice perchè sarebbe superfluo, a me servirebbe più l'idea di base, perchè sono un pò bloccato.

4 Risposte

  • Re: Gioco Client/Server

    Ogni client ha la sua interfaccia grafica ed il server NON HA niente di grafico.
    Sembra stupido, visto che l'interfaccia e' la stessa, ma l'alternativa e' moooooooooolto piu' complicata:

    1) dovresti trasmettere ai client una parte dello schermo del server
    2) il server dovrebbe inviare ai client i messaggi di agghiornamento delle swing.

    Invece il server invia si client SOLO 3 informazioni: la posizione della pallina, la posizione delle due racchette.. Con queste info, ogni client genera la sua rappresenrazione del gioco.
    Nota che in questo modo, ogni client potrebbe essere implementato in modo diverso

    I client inviano al server SOLO la posizione della PROPRIA racchetta.
  • Re: Gioco Client/Server

    La prima soluzione infatti mi sembrava troppo complicata, passare un oggetto così complesso al Client mi sembrava una pessima gestione.

    Seconda soluzione.
    Client extends JFrame.
    ClientController per l'invio dei dati al Server.
    Server deve inviare le posizioni e generare nuove Ball.
    Tutti i calcoli per le collissioni ecc, li fanno i Client? o forse è meglio il Server, anche perchè così sa se deve generare nuove Palline o no.

    Quindi in pratica in while(true){ } faccio Read e Write dei dati posizionali? per distingure quale paddle modificare, insieme alla stringa che gli passo, ad esempio W per indicare top, passo W1. Così sarà if(string.equals("w1")) allora player1.setKeyPressed(VK_W);



    Per avere un concetto molto più gerarchico e di pulizia del codice, che tipo di design pattern utilizzare in questi contesti?
  • Re: Gioco Client/Server

    Ovviamente NO:
    E' IL SERVER che gestiisce tutta la logica del gioco
    I CLIENT SOLO visualizzano e inviano la posizione della racchetta.

    Qui' c'e' un TRUCCO:

    1) il client invia la posizione della rachetta MA NON LA DISEGNA IN QUESTA FASE.
    Il server invia la posizione delle rachette e della palla a TUTTI I CLIENT (e' una duplicazione di informazione MA SEMPLIFICA NOTEVOLMENTE la gestione del server E la gestione del client)
    E SOLO AL RICEVIMENTO DELLE POSIZIONI DA PARTE DEL SERVER il client ridisegna TUTTO

    Lascia perdere i design pattern: qui' ne stai usando a camionate, NON solo uno!

    LA PRIMA COSA E' avere CHIARO come i vari pezzi funzionano, al codice ci pensi poi.
    Nel senso: devi avere chiaro come farlo, ma non serve il dettaglio implementativo minimo (quale API usare per QUALE tasto, ecc).
  • Re: Gioco Client/Server

    Errore: java.io.StreamCorruptedException: invalid type code: AC
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1716)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:499)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:457)
    at ClientHandler.run(ClientHandler.java:53)

    su questo codice:
    import java.awt.event.KeyEvent;
    import java.io.EOFException;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.Socket;
    import java.net.SocketException;
    
    public class ClientHandler implements Runnable {
    
        private ObjectOutputStream outputStream;
        private ObjectInputStream inputStream;
    
        private boolean running;
        private Player player;
        private Socket socket;
    
        public ClientHandler(Socket socket, Player player) {
            this.player = player;
            this.socket = socket;
            try {
                outputStream = new ObjectOutputStream(this.socket.getOutputStream());
                inputStream = new ObjectInputStream(this.socket.getInputStream());
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
    
        public void close() throws IOException {
            running = false;
            inputStream.close();
            outputStream.close();
        }
    
        public void sendPacket(Object obj) {
            try{
                outputStream.reset();
                System.out.println("SERVER INVIA: "+obj.hashCode());
                outputStream.writeObject(obj);
                outputStream.flush();
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
    
            running = true;
    
            while(running) {
                try {
                    String userInput = (String) inputStream.readObject();
                    if(userInput!=null) {
                        System.out.println("SERVER RICEVE: "+userInput);
                        if(userInput.equals("w")) {
                            player.setKeyPressed(KeyEvent.VK_W);
                            player.setKeyReleased();
                        } else if(userInput.equals("s")) {
                            player.setKeyPressed(KeyEvent.VK_S);
                            player.setKeyReleased();
                        }
                    }
                } catch (EOFException | SocketException e){
                    running = false;
                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                }
    
            }
        }
    }
    
    L'oggetto che gli passo in write è una Classe Serializzata, UpdatePacket che contiene i riferimenti alla palla e ai due paddle.
    L'errore me lo da su un readObject, Stringa che riceve dal client che fa riferimento al movimento della racchetta di quel player.
    Ora so che questo errore dovrebbe indicare che ci sono altri flussi aperti su quella socket, ma i due Stream istanziati sono unici per questa classe. Ne ho istanziati altri due nel Client, per ricevere e inviare gli oggetti. Sbaglio qualcosa?

    EDIT: scrivendo la parte sottolineata mi sono reso conto che nel client ad ogni nuova chiamata su sendPacket o ReceivedPacket, aprivo un nuovo Stream. Quindi ho risolto. Ora devo solo capire come fare un draw sugli oggetti del JPanel acquisiti.

    EDIT: Ok ho risolto tutto, il giochino starta tranquillamente con due client, il server riceve elabora e invia i dati. Se posso postare tutto su github magari da ricevere un feedback, su cosa potrei migliorare. Nel frattempo ringrazio l'utente migliorabile, di cui ho grandissima stima, in quanto reputo i suoi consigli, di grandissima utilità in ogni occasione.
Devi accedere o registrarti per scrivere nel forum
4 risposte