1

I am trying to code an application that gets user mouse input and draws a dot on each click (not that that is especially important). Where should the game loop functions be, in the paint method or in a separate while loop? Here is my code:

import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;


@SuppressWarnings("serial")
public class Main extends JPanel{

    static Rectangle scrnSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
    //static Dimension wholeScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
    //public static int taskbarHeight = wholeScreenSize.height - scrnSize.height;

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);
        g2d.fillOval(0, 0, 30, 30);
        g2d.drawOval(0, 50, 30, 30);        
        g2d.fillRect(50, 0, 30, 30);
        g2d.drawRect(50, 50, 30, 30);

        g2d.draw(new Ellipse2D.Double(0, 100, 30, 30));
        //do loop stuff here?
    }

    public static void main(String[] args) throws InterruptedException {
        //init
        JFrame frame = new JFrame("DrillSweet");
        frame.setLayout(new GridLayout());
        Main main = new Main();
        frame.add(main);
        frame.setSize(new Dimension(scrnSize.width, scrnSize.height));
        frame.setPreferredSize(new Dimension(scrnSize.width, scrnSize.height));
        frame.setMaximumSize(new Dimension(scrnSize.width, scrnSize.height));
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //game loop
        while(true){
            //do loop stuff here?
            main.repaint();
            Thread.sleep(10);
        }
    }

}
Clarinetncleats
  • 111
  • 1
  • 9

2 Answers2

2

First things you need know...

  1. You don't control the paint process, so don't screw with it. Painting is done by the RepaintManager, you can make suggestions to the RepaintManager about what should be painted, but it's the responsibility of the RepaintManager to decide what and when something should be painted.
  2. Swing is not a thread safe framework. That is, all updates to the UI must be done from within the context of the Event Dispatching Thread...Take a look at Concurrency in Swing for more details...
  3. Painting in Swing is a complex series of method calls which chain together to produce the final result, failure to honour this chain will result in nasty painting artifacts...

So, taking all that into account...

  1. DON'T EVER perform any operation within in ANY paint method that may take time to execute, this includes, looping infinitely, loading of resources or using things like Thread.sleep
  2. If you must change the UI, do so from within the context of the Event Dispatching Thread
  3. Call super.paint or better yet, override paintComponent instead (and call super.paintComponent before you do any custom painting)

Instead of a Thread, based on you needs, consider using a Swing Timer, which will allow you to schedule a regular callback which will be done within the context EDT. This will ensure a level of synchronisation, as any changes you make to properties of the UI can't be used within any paint method (as your call back and the paint method are been called from the same thread) and help prevent possible dirty paints...

You may also like to take a look at Painting in AWT and Swing and Initial Threads and Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more information...

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

I not an expert in java, but I find it really useful to have a separated Timer for repaint and another for calculations.

Something like:

ActionListener counter = new ActionListener() 
{
    public void actionPerformed(ActionEvent ev)
    {   
        repaint();
    }
};  
new Timer(40, counter).start();

and another timer for calculations

ActionListener counter = new ActionListener() 
{
    public void actionPerformed(ActionEvent ev)
    {   
        for(Enemies en: enemies)
        {
            en.moveEnemies();
        }

        turret.moveShoots();
        checkColision();
    }
};  
new Timer(5, counter).start();

With this, I ensure to have some precision with the calculation and constant game speed, independent from having good fps or a fluid animation.

MVAmorim
  • 105
  • 2
  • 3
  • 11