2013-05-22 1 views
1

Я делаю сетевую игру «Броненосец» для школьного проекта. GUI имеет сетку JButtons, которая служит игровой панелью. Когда пользователь нажимает кнопку, он вызывает метод sendShot(). Этот метод отправляет свой снимок на удаленный компьютер, который проверяет, является ли его ударом или пропуском и возвращает результат. Затем первая машина получает этот результат и соответственно обновляет свой графический интерфейс. Код, который у меня есть, делает это, но проблема в том, что графический интерфейс не обновляется до тех пор, пока другая машина не отправит свой следующий снимок. Я предполагаю, что это потому, что я вызываю recieveShot() из метода sendShot(), но я не на 100% понятен почему, так как метод обновления GUI (gp.ob.updateBoard(sr))) вызывается до receiveShot(). Что я не понимаю здесь?GUI не обновляется, как ожидалось/проблема управления потоком

Кроме того, у меня возникает ощущение, что мой базовый метод потока программ здесь ошибочен и что receiveShot() не следует вызывать из метода sendShot(). Есть ли очевидные альтернативы этой схеме?

void sendShot(ShotAttempt sa){ 

    try { 
     oos.writeObject(sa); 
     oos.flush(); 
     System.out.println("shot fired"); 
     ShotResult sr = (ShotResult)ois.readObject(); 
     gp.ob.updateBoard(sr); 
    } catch (IOException | ClassNotFoundException e) { 
     System.out.println(e.printStackTrace());} 
     receiveShot(); 
} 

void receiveShot(){ 
    try{ 
    ShotAttempt sa = (ShotAttempt)ois.readObject(); 
    ShotResult sr = gp.db.acceptShot(sa); 
    oos.writeObject(sr); 
    oos.flush(); 
    } catch (IOException | ClassNotFoundException e){e.printStackTrace();} 
} 
+0

Возможно, это не имеет никакого отношения к этому, но вы дважды читаете «ShotResult» из потока ... один раз в 'sendShot' и еще раз в' recieveShot'. Кроме того, нам может потребоваться больше кода, прежде чем мы сможем вывести общую проблему ... – MadProgrammer

+0

вы можете вставить [SSCCE] (http://sscce.org) для быстрой справки. – Ashish

ответ

2

ГИП не не обновляется до тех пор, после того, как другая машина посылает свой следующий выстрел. Я предполагаю, что это потому, что я вызываю recieveShot() из метода sendShot(), но я не на 100% понятен, почему, поскольку метод обновления GUI (gp.ob.updateBoard (sr))) вызывается перед receiveShot().

Метод receiveShot() блокирует поток отправки событий Swing или EDT. Поскольку этот поток отвечает за всю графику Swing, взаимодействие с пользователем и обработку событий Swing, ни один Runnables, поставленный в очередь на событие Thread и не ожидающий обработки, будет обработан, даже если они были поставлены в очередь до того, как был вызван метод receiveShot(). Они могут обрабатываться только тогда, когда поток разблокирован, что будет после того, как вы получили снимок.

Предложения:

  • Вы должны сделать все ваши сокеты на фоне потоков.
  • Я бы создал программные состояния, возможно, состоящие из enum, например, называемые State, и дать ему как минимум два возможных значения, СЪЕМКИ И ПОЛУЧЕНИЕ.
  • Правильно настройте свое государство после отправки снимка в состояние. РЕЗЕРВ.
  • Вернитесь к State.SHOOTING после получения снимка.
  • Не разрешайте игроку посылать снимок в режиме приема. Таким образом, ваш код не будет требовать блокировки, чтобы предотвратить съемку пользователя.
  • У вас также может быть END_GAME как одно из ваших состояний.
  • Я бы дал свой класс setState(State state).
  • В этом методе я могу включить/отключить свои кнопки съемки в зависимости от нового состояния.
  • Вам понадобится один фоновый поток, возможно, SwingWorker, работающий непрерывно, прослушивание сокета для сообщений. Когда этот поток получает информацию о том, что он был снят, он затем обновляет состояние программы, вызывая setState(newState).
  • Я бы позаботился, чтобы вызвать setState в потоке событий Swing, чтобы изменения состояния выполнялись только одним потоком.
  • Тогда я бы назвал съемку на отдельной фоновой нити, но только для съемки. Он не будет постоянно работать.

Дополнительную информацию о Swing Event Dispatch Thread см. На странице Concurrency in Swing.

+0

Спасибо! Я пытаюсь склонить голову вокруг того, что вы предложили: «Когда же государство будет проверено? –

+0

@ user2356560: Вы можете проверять состояние всякий раз, когда пользователь пытается стрелять, когда он нажимает кнопку. Если состояние не является State.SHOOTING, то нажатие кнопки ничего не делает. Кроме того, вы можете прослушивать состояние для изменения, и если состояние не является State.SHOOTING, вы можете отключить кнопки с помощью 'setEnabled (false)' и наоборот, когда государство изменится. –

+0

'' Кроме того, вы могли бы прослушивать изменение состояния «Как прослушать изменения состояния? Какую конструкцию я могу использовать? –