1

I have made a simple ball and paddle Multiplayer game in java. It uses MultiCastSocket to send and receive data.Ball is being moved only on system of player
1. Position of ball is sent by all players on the network. All players receive the data and but only players other than p1 read it and update their ball position. Now the problem here is that although the ball is moving smoothly on p1 but on other player's systems it is not in continuous motion. Discrete instances of ball on the screen are visible.Following is a code snippet of the networking part of my code: (here myTag is the player number rec is an object of Receive data class that just receives data and stores in a String named data)

private class ScheduleTask extends TimerTask {

    @Override
    public void run() {


        paddleArr[myTag].moveX();

        for(int i=0; i<4; i++){
            if(i != myTag){
                if(!others.contains(i)){
                    Computer comPaddle = new Computer(paddleArr[i], ball);
                    if(paddleArr[i].isHorizontal()){comPaddle.moveSideways();}
                    else {comPaddle.move();}
                }
            }
        }
        if(myTag==0){ball.move();}

        if(ball.getXdir()*ball.getXdir()+ball.getYdir()*ball.getYdir() >= 80){
            ball.setXdir(ball.getXdir()*0.67);
            ball.setYdir(ball.getYdir()*0.67);
        }


       if(newgame){
           try {
            socket = new MulticastSocket(4446);
            group =InetAddress.getByName("228.6.7.8");
            socket.joinGroup(group);
        } catch (IOException e) {
            // TODO Auto-generated catch block

            System.out.println("error");
        }
           rec = new ReceiveData(socket, group, port, myTag);
        newgame = false;   
       }

       //System.out.println(rec.data);

       if(bak > 10){
           setAllPos(rec.data.trim());
       }
       bak++;

       checkCollision();
       repaint();

        try {
            socket = new MulticastSocket(4446);
            group = InetAddress.getByName("228.6.7.8");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String str = myTag+" "+(ball.getMyX())+" "+(ball.getMyY())+" "+(ball.getXdir())+" "+(ball.getYdir())+" "+(paddleArr[myTag].getMyX())+" "+(paddleArr[myTag].getMyY());
        buf = str.getBytes();
        // Create a DatagramPacket 
        DatagramPacket packet = new DatagramPacket(buf, buf.length,group, 4446);
        // Do a send.
        try {
            socket.send(packet);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println("send failed");
        }
        // And when we have finished sending data close the socket
        socket.close();

    }
}

public void setAllPos(String s){
    //System.out.println(s);
    String[] data = s.split(" ");
    if(myTag != 0){
        if(data[0].equals("0"))
        {
            ball.setMyX(Double.parseDouble(data[1]));
            ball.setMyY(Double.parseDouble(data[2]));
            ball.setXdir(Double.parseDouble(data[3]));
            ball.setYdir(Double.parseDouble(data[4]));
            repaint();
            //ball.move();
            //paddleBottom.setMyX(Integer.parseInt(data[5]));
            //content.udpPosition = data[5];
            //System.out.println("Ball pos set");
        }
    }
Ataur Rahman Munna
  • 3,887
  • 1
  • 23
  • 34
Sarvesh
  • 11
  • 1

1 Answers1

0

Unfortunately, you cannot do networking game by just applying latest position you got over network. It is wasteful for bandwidth (as you would need to send at least one message each frame) and not reliable (as network packets might have random delays, so you will see uneven motion).

There are two basic options to solve it and they can be combined for even better results:

1) Keep local 'shadow' copy of the ball on each client which represents slightly delayed version of what is happening on other machine. Then, when you receive network update, instead of jumping to new position, start interpolating between your current position and target position, so you can reach there in short time. If you receive new update in meantime, start interpolating towards new position. This way, you won't perceive any strange jumps at the cost of slight constant lag (which can be reasonably low)

2) Instead of sending just position, send velocity as well (which you already do). Perform simulation of movement on each machine based on that, rather than based on position updates. Everything will be smooth, but you can get out of sync with position and errors will compound

Proper solution is to compound both solutions. Interpolate position and perform simulation on received velocity (which can be also time interpolated if needed).

You can read about some math behind it here https://en.wikipedia.org/wiki/Dead_reckoning#Dead_reckoning_for_networked_games plus look up 'dead reckoning' on the web for more details. There should be quite a few articles about that on gamasutra.

You might also want to check out http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/Quake3Networking and other sources on quake3 network protocol - it is good example how it can be done in very efficient way with non-reliable networks (and introduce you to https://en.wikipedia.org/wiki/Lamport_timestamps implicitly in meantime)

Artur Biesiadowski
  • 3,595
  • 2
  • 13
  • 18