Search code examples
javapaneldraw

JPanel drawing is slowed down after several instances are painted


I'm building a game and I'm painting the road sprites with the JPanel's draw function. The roads (Building class) can be built by dragging the mouse and on each field a new road sprite appeares. But after I've drawn like 20 road sprites, the drawing gets really slow.

I have a frame and there is this JPanel on it. Here is the code of the JPanel on which my game drawing is:

private class GamePanel extends JPanel implements ActionListener{
        
        Field[][] map = gameEngine.getMap().getFields();
        ArrayList<Building> buildings = gameEngine.getBuildings();
        Timer timer;
        ArrayList<Field> fields = new ArrayList<>();
        GameFrame frame;                                     //REFERENCE FOR THE CONTAINER OF THIS PANEL

        private int mousePosX;
        private int mousePosY;

        GamePanel(GameFrame frame){
        /*...*/
            Mouse mouseListener = new Mouse();
            addMouseListener(mouseListener);
            addMouseMotionListener(mouseListener);
            
            timer = new Timer(1000/30,this);
            timer.start();
        /*...*/
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);       
            draw(g);
        }

        public void draw(Graphics g){
            for(Building b : buildings){
                int drawPosX = b.getLocation().getPos().x*40;
                int drawPosY = b.getLocation().getPos().y*40;

                try {
                    BufferedImage img = ImageIO.read(new File("src/GFX/" + b.getType() + ".png"));
                    g.drawImage(img, drawPosX, drawPosY, null);
                } catch (IOException e) {
                }
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {                            
              // I thought this is not needed because I call "repaint()" only at mouse events (like 
              // building road by dragging)
        }

        public class Mouse extends MouseAdapter{
            @Override
            public void mouseDragged(MouseEvent evt){

                repaint();                            // THIS IS AN EXAMPLE TO WHERE I CALL THE REPAINT()

                fieldPosX = evt.getX() - (evt.getX() % 40);
                fieldPosY = evt.getY() - (evt.getY() % 40);
                
                gameEngine.placeRoad(new SimpleRoad(new Field(fieldPosX/40,fieldPosY/40)));
            }
            
            /*... OTHER MOUSE EVENTS ...*/
        }

        

I thought that calling repaint() only at mouse events will optimise the speed but it really isn't. I attached a GIF on which it can be seen that after 2 line of roads, it gets really slow.

GIF of me building a lot of roads

I heard about invokeLater and people advised me to use it but I don't know how to implement that in this project. Why is my game getting slower after several buildings, where am I making a mistake? Would invokeLater solve the problem? How do I place it in my project?

Thanks for helping!


Solution

  • Why is my game getting slower after several buildings,

    try
    {
        BufferedImage img = ImageIO.read(new File("src/GFX/" + b.getType() + ".png"));
        g.drawImage(img, drawPosX, drawPosY, null);
    }
    

    Don't do I/O in a painting method. As you add more building you are doing more I/O.

    The images should be read in the constructor of your class.

    You can save them in a HashMap for easy access in the painting method.

    Or, the image can be saved as part of the Building class itself.