JavaFX просто отображает графику и работает ВСЕГДА в одном своем потоке. Для взаимодействия с ней(что то пошевелить на экране) из другого потока используется такая штука Platform.runLater(java.lang.Runnable runnable).
В вашей задаче я себе представляю картину так:
Сервер:
1)держит состояния 4х переменных. ПоложениеИ1(у),ПоложениеИ2(у),ПоложениеМяча(х,у),ВекторНаправленияМяча(х,у). По хорошему еще дополнительно количество очков для каждого игрока и флаг для каждого игрока о готовности игры\паузы.
2)слушает сокет и ожидает игроков. Как только игроки подключились начинает принимать от игроков их положения клюшек и вносить в переменные. Симулирует игровое поле в отдельном потоке по фиксированному числу тиков с положениями клюшек игроков, мяча и его движения. Отправляет игрокам положения клюшек, и мяча. Опционально шлет количество очков и запускает\паузит игру по флагам от игроков.
Не забывает что все в игре максимально детерминированно, т.е. размер поля для симуляции известен, положения игроков известно и т.д. Т.е. все прекрасно симулируется.
Клиент:
1) держит состояния 4х переменных. ПоложениеСебя(у),ПоложениеИ2(у),ПоложениеМяча(х,у),ВекторНаправленияМяча(х,у).
2) В одном потоке подключается к серверу. Принимает все координаты и шлет положения в поток javafx.
3) Поток javafx рисует графику(помним что все размеры заранее известны), слушает нажатия кнопок\мыши и шлет на сервер.
В минимальном виде это будет работать.
Т.е. по итогу игровая логика происходит на сервере. Игроки же просто получают координаты друг друга и мяча, в ответ шлют серверу положение своей клюшки.