Работа с сокетами и ObjectInputStream/ObjectOutputStream

Работаю над созданием сетевого 2D шутера с использованием сокетов и JavaFX. Сервер запускается на компьютере пользователя, после чего к нему может подключиться второй игрок. Для передачи данных я использую Object Output Stream и Object Input Stream и передаю через них информацию в потоке. Проблема в том что пока игроки просто передвигаются - никаких задержек нет, но с каждым выстрелом задержка всё сильнее (у игрока выстрел произошёл, а у оппонента до 3 секунд задержка). Ниже идёт код самого потока (идентичен для класса клиента и сервера)

@Override
public void start() {
    try {
        outputStream= new ObjectOutputStream(socket.getOutputStream());
        inputStream= new ObjectInputStream(socket.getInputStream());
    } catch (IOException e) {
        e.printStackTrace();
    }

    AnimationTimer animationTimer = new AnimationTimer() { //таймер анимации JavaFX ~60 тиков в секунду
        @Override
        public void handle(long now) {

            movePlayerShip(); //обноляем координаты корабля, в этом же методе всё время передаются координаты этого корабля второму игроу
            moveBackground();   //двигаем фон
            movePlayerBullets(); // двигаем пули на экране, происходит локально, данные не передаются другому игроку

            try {
                //получаем массив объектов
                infoGet = (Object[]) inputStream.readObject();

                switch ((String)infoGet[0]){ //проверяем по первому элементу что именно пришло
                    case "playerMove": //если передвижение оппонента 

                        shipOpponent.setLayoutX((double)infoGet[1]); //на окне двигаем корабль по тем же координатам
                        shipOpponent.setLayoutY((double)infoGet[2]); //корабль представляет собой ImageView

                        shipOpponentBox.setLayoutX((double)infoGet[3]); //хитбокс тоже двигаем 
                        shipOpponentBox.setLayoutX((double)infoGet[4]);
                        infoGet = null; //очищаем для повторного получения данных
                        break;
                    case "shootPlayer": //если оппонент выстрелил
                        //создаём "пулю" на экране с теми же координатами, откуда выстрелил оппонент и задаём такую же траекторию
                        MultiplayerBullet opBullet = new MultiplayerBullet((double) infoGet[3],(double) infoGet[4],0 );
                        opBullet.setTarget((double) infoGet[1],(double) infoGet[2] );

                        gamePane.getChildren().add(opBullet);
                        opponentBullets.add(opBullet); //добавляем в arraylist с пулями противника на экране

                        shootSound.play(); //проигрываем звук выстрела
                        shootSound.seek(Duration.ZERO); //отматываем на начало для повторного проигрывание

                        break;
                    default: //если пришли неизвестные данные
                        System.out.println("got strange stuff");
                        break;
                    }

            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            moveOpponentBullets(); //обновление всех пуль противника на экране

        }
    };
    animationTimer.start();//запуск анимации

} 

Так выглядит метод для отправки данных когда игрок выстреливает:

    private void shootPlayer(MouseEvent event){

    MultiplayerBullet bullet = new MultiplayerBullet(shipPlayer.getLayoutX() + shipPlayer.getImage().getWidth() / 2, shipPlayer.getLayoutY() +  shipPlayer.getImage().getHeight()/2 , 1);
    bullet.setTarget(event.getSceneX(),event.getSceneY());

    //System.out.println(event.getSceneX() + " | " + event.getScreenX()  + " | " +  event.getX());

    infoSend[0] = "shootPlayer";
    infoSend[1] = event.getSceneX();
    infoSend[2] = event.getSceneY();
    infoSend[3] = bullet.getLayoutX();
    infoSend[4] = bullet.getLayoutY();

    try {
        outputStream.reset();
        outputStream.writeObject(infoSend);
        outputStream.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }

    playerBullets.add(bullet);  //добавляем в лист пули
    gamePane.getChildren().add(bullet); // добавляем на экран
    shipPlayer.toFront();
}

Это метод для отправки позиции игрока оппоненту:

 private void movePlayerShip(){

    if(isLeftKeyPressed){
        if(shipPlayer.getLayoutX() > 0 ){
            shipPlayer.setLayoutX(shipPlayer.getLayoutX() - 4 );
            shipPlayerBox.setX(shipPlayerBox.getX() - 4);
        }
    }
//Аналогично для остальных направлений, убрал что бы кода много не было. 
//Отправка происходит всегда в конце метода, даже если игрок не двигался
    infoSend[0] = "playerMove";
    infoSend[1] = shipPlayer.getLayoutX();
    infoSend[2] = shipPlayer.getLayoutY();
    infoSend[3] = shipPlayerBox.getLayoutX();
    infoSend[4] = shipPlayerBox.getLayoutY();
    try {
        outputStream.reset();
        outputStream.writeObject(infoSend);
        outputStream.flush();

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Искал информацию по данной теме - нашёл лишь то, что можно выставить SetTcpNoDelay(true) и делать reset потока для вывода. В чём может заключаться данная проблема с появлением задержек? По идее просто отсылается другой массив объектов. P.S. пули убираются с экрана при выходе за границу


Ответы (0 шт):