2

I'm working on a large Monopoly game as a project in school and ran into a pretty big performance issue. Right now I have a paint method that is drawing the entire board everytime it gets called... this is a big problem because the board only needs to be drawn once in the beggining and only whenever someone buys a house or something. The only components I want to be painted a lot are the players because they are the ones that move around the most and need to be painted.

Here is the paint method of my board:

public void paint(Graphics g){
        super.paint(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        //Draw all the spots
        for(int i = 0; i < spots.length; i++){
            g2d.setColor(Color.white);
            g2d.fill(spots[i].getRect());
            if(spots[i] instanceof Property){
                if(i < 10){
                    g2d.setColor(spots[i].getColor());
                    Rectangle temp = new Rectangle(spots[i].getRect().x,spots[i].getRect().y,spots[i].getRect().width,spots[i].getRect().height/3);
                    g2d.fill(temp);
                    g2d.setColor(Color.black);
                    g2d.drawString(((Property)spots[i]).getName(), spots[i].getRect().x, spots[i].getRect().height);
                }else if(i >= 10 && i < 20){
                    g2d.setColor(spots[i].getColor());
                    Rectangle temp = new Rectangle(spots[i].getRect().x+spots[i].getRect().width-spots[i].getRect().width/3,spots[i].getRect().y,spots[i].getRect().width/3,spots[i].getRect().height);
                    g2d.fill(temp);
                }else if(i >= 20 && i < 30){
                    g2d.setColor(spots[i].getColor());
                    Rectangle temp = new Rectangle(spots[i].getRect().x,spots[i].getRect().y+spots[i].getRect().height-spots[i].getRect().height/3,spots[i].getRect().width,spots[i].getRect().height/3);
                    g2d.fill(temp);
                    g2d.setColor(Color.black);
                    g2d.drawString(((Property)spots[i]).getName(), spots[i].getRect().x, spots[i].getRect().y);
                }else if(i >= 30 && i < 40){
                    g2d.setColor(spots[i].getColor());
                    Rectangle temp = new Rectangle(spots[i].getRect().x,spots[i].getRect().y,spots[i].getRect().width/3,spots[i].getRect().height);
                    g2d.fill(temp);
                }
            }else if(spots[i] instanceof Railroad){
                if(i == 5)
                    g2d.drawImage(imgTrain3, spots[i].getRect().x, spots[i].getRect().y+spots[i].getRect().height/4, null);
                else if(i == 15)
                    g2d.drawImage(imgTrain4, spots[i].getRect().x+spots[i].getRect().width/4, spots[i].getRect().y, null);
                else if(i == 25)
                    g2d.drawImage(imgTrain1, spots[i].getRect().x, spots[i].getRect().y+spots[i].getRect().height/4, null);
                else if(i == 35)
                    g2d.drawImage(imgTrain2, spots[i].getRect().x+spots[i].getRect().width/4, spots[i].getRect().y, null);
            }else if(spots[i] instanceof Chance){
                if(i == 7)
                    g2d.drawImage(imgChance2, spots[i].getRect().x, spots[i].getRect().y, null);
                else if(i == 22)
                    g2d.drawImage(imgChance2, spots[i].getRect().x, spots[i].getRect().y+spots[i].getRect().height/3, null);
                else if(i == 36)
                    g2d.drawImage(imgChance3, spots[i].getRect().x, spots[i].getRect().y, null);
            }else if(spots[i] instanceof Community){
                if(i == 2)
                    g2d.drawImage(imgComm1, spots[i].getRect().x, spots[i].getRect().y+spots[i].getRect().height/3, null);
                else if(i == 17)
                    g2d.drawImage(imgComm2, spots[i].getRect().x, spots[i].getRect().y, null);
                else if(i == 33)
                    g2d.drawImage(imgComm3, spots[i].getRect().x+spots[i].getRect().width/3, spots[i].getRect().y, null);
            }else{
                g2d.setColor(spots[i].getColor());
                g2d.fill(spots[i].getRect());
            }
        }
        //Draw the outline of every spot
        g2d.setColor(Color.black);
        for(Spot index : spots)
            g2d.draw(index.getRect());
        //Draw the outline of the whole board
        g2d.drawRect(newX, newY, boardSize, boardSize);
        //Draw the Players location
        for(Player index : players)
             g2d.drawImage(index.getImage(), index.getLoc().x, index.getLoc().y, null);
    }

Basically a ton of text to represent the board, and this is being done everytime the board repaints. Any advice?

Bonus question: I also just started working on the move animation for the players after they roll (currently just jump to the destination). I created a timer that takes 1 second per roll (ex: if you roll a 5 it takes 5 seconds to move). Only problem is that I don't really have a good idea for how to show the slow moving of the player piece from the starting location to end. Just need someone to give me a basic idea so I can head in the right direction.

mbreen
  • 558
  • 3
  • 9
  • 20

2 Answers2

4

Paint the board to a BufferedImage. In the paint method, draw the image of the board, then draw the pieces over the top.

BTW - when using Swing, don't paint in top-level containers, instead use a JComponent or JPanel. For the latter two, override paintComponent(Graphics) rather than paint(Graphics).

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • So it still draws the board on every repaint call but because it is an image it is more efficient? Currently I can see visible lag when the player moves, will this be less noticable with a BufferedImage? – mbreen Mar 04 '12 at 14:29
  • 1
    @mbreen: Try it :-). Yes, it will be faster, and you will need to draw the whole board anyway occasionally in case your Java window is obscured by other windows. – Paŭlo Ebermann Mar 04 '12 at 14:40
  • If it truly takes a long time to draw the BG, yes. But it should be possible to draw hundreds of objects per call to the paint method without noticeable lag. Perhaps it'd be better to look at posting an [SSCCE](http://sscce.org/) so we can look more closely at the overall process being used. Also, highly recommend chasing up any rendering examples from the tutorial that toto2 found. Try increasing them from painting 1 ..ball(line, ..whatever) to painting scores of them - and see how they perform. – Andrew Thompson Mar 04 '12 at 14:41
  • Alright I've been looking around of a good explaination of the BufferedImage class but I can't find any that I understand/can implement. Correct me if I'm wrong: I create a variable BufferedImage board = new BufferedImage(); then I make a method which does everything my paint method did except this time it draws to the image... then my paint method draws that image? – mbreen Mar 04 '12 at 14:56
  • 1
    Yes, then [`paint something to the new image!`](http://stackoverflow.com/a/8214990/418556) – Andrew Thompson Mar 04 '12 at 15:14
  • I'm still having a lot of problems with this... if I gave you a link to my entire board class could you take a quick look at it to see what I'm doing wrong? I would really appreciate that. – mbreen Mar 04 '12 at 17:13
  • Sorry, no. Something I was about to mention earlier was: For better help sooner, post an [SSCCE](http://sscce.org/). It was only that it seemed simple to offer some general advice, that I held off. But now, it is definitely time for an SSCCE. An SSCCE would be short enough to post into a (new - hint, hint) question. – Andrew Thompson Mar 04 '12 at 17:37
  • Ok that's fine. Thanks you all your help though! – mbreen Mar 04 '12 at 17:49
1

You can avoid redrawing the whole surface with: jComponent.repaint(someRectangle). See also this example.

However, you have to figure yourself the rectangle (or rectangles) that needs updating between each moves. You not only need the rectangles where new things appear, but also where things disappear.

For animations in Swing, look at this tutorial. You'll notice both the examples I linked in this post are from the official Swing tutorial.

toto2
  • 5,306
  • 21
  • 24