1

I am currently working in a implementing a quoridor game in java , using AI game-playing algorithms. After the "human" clicks to make his move , the gui needs to be updated and the AI start thinking. I have something like this inside the panel:

public void mouseClicked(MouseEvent e)
    {
       gameBoard.executeMove( movePawn );
       repaint();
       gameboard.callAi();
    }

After I call the funtcion callAi() , I get into a loop that is consuming too much time to finish. The gui on the other hand freezes , it doesnt update , even thought the repaint method is called before the AI "start thinking". I tried to put a delay before I call the AI , but it was not working. I wrote this one:

try
{ TimeUnit.MILLISECONDS.sleep(5);}
catch{}

What can I do to solve this one ? Maybe it has something to do with threads , but I am not too friendly with threads in Java.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
Joan Plepi
  • 490
  • 2
  • 5
  • 15
  • You can try `object.repaint(); object.updateUI();`. Here "object" means your component which you want to refresh, for example, when "gameBoard" is like JPanel you can: `gameBoard.repaint(); gameBoard.updateUI();` – Vasyl Lyashkevych Jul 13 '17 at 01:28
  • 2
    @VasylLyashkevych `updateUI` is NOT for generating notifications that the UI state has changed and should be updated, but instead, to instruct the components that the Look and Feel delegate has been changed and they should reinstall the update - there should never be a need to call this method unless you are attempting to change the look and feel at runtime - it would also not even come close to solving the issue the OP is having – MadProgrammer Jul 13 '17 at 01:32
  • 3
    You have tripped over the single threaded nature of Swing, basically, you're blocking the thread which is responsible for processing the paint events. See [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for more details and possible solutions – MadProgrammer Jul 13 '17 at 01:33
  • @MadProgrammer Thank you! I misunderstood the question – Vasyl Lyashkevych Jul 13 '17 at 01:36
  • @MadProgrammer isn't that method "sleep()" enough to call the AI after 5 miliseconds ? 5 miliseconds should have been enough for the GUI to update or am I wrong ?? – Joan Plepi Jul 13 '17 at 01:36
  • 2
    @JoanPlepi How can the GUI update when you're blocking the thread responsible for processing the paint request? You're assuming that `repaint` performs the actual painting, when it doesn't, it simply makes a request to the `RepaintManager` which then determines what needs to be painted and schedules a paint event onto the event queue, which is then processed by the Event Dispatching Thread - which you are blocking – MadProgrammer Jul 13 '17 at 01:39
  • 1
    @JoanPlepi I think you need to go have a look at [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) to better understand how painting actual works ... plus the previous link I mentioned – MadProgrammer Jul 13 '17 at 01:40
  • @MadProgrammer , I think I understand this one , that the function is blocking the thread, but how can I put a delay in calling the function which blocks the thread ? This way the repaint is done , and after that I call the function and block the thread. – Joan Plepi Jul 13 '17 at 01:44
  • 2
    @JoanPlepi As is recommended in the **Concurrency in Swing** link, make use of a `SwingWorker` to perform the long running operation, use it's functionality to then update the UI safey - as Swing is also not thread safe – MadProgrammer Jul 13 '17 at 01:50
  • 1
    I think you need to read what @MadProgrammer suggests. Calling a long running operation in the UI is a mistake. You need a background thread that invokes callAi() and use an invokeLater call to the UI. – bichito Jul 13 '17 at 01:51
  • or simply pull out the AI logic from the event loop. Run it in a separate thread, so the event loop can keep updating the screen (e.g. to show a rotating ball saying computer thinking) – Adrian Shum Jul 13 '17 at 02:46

2 Answers2

3

I would highly recommend reading up on what the EDT (Event Dispatch Thread) is.

Java Event-Dispatching Thread explanation

One of the answers does a good job explaining it. Quick TLDR: Basically one of the reasons the GUI freezes is because of the AI method you included on the EDT (I can't say for certain about the gameBoard.executeMove(...) method). EDT is meant for updating the GUi, not running methods that take a lot of compute time.

Get the game logic code out of the GUI and into the main thread/new thread (not the EDT). If you absolutely need game logic inside the EDT then make a new Thread in the EDT, have it do its game calculations, and finally use Swing.Utilties.invokeLater(...) method to update the GUI.

Maybe it has something to do with threads , but I am not too friendly with threads in Java.

Definitely want to get familiar with threads when you are making a game, specially the EDT.

BWC semaJ
  • 139
  • 2
  • 16
2

You should use a SwingWorker to do the AI work on this. All the updating and processing happens on a single thread within Swing so if you block that then you will freeze the UI.

https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

Tim B
  • 40,716
  • 16
  • 83
  • 128