Just hoping people can help me understand properly how the RepaintManager works when trying to create animations. Basically I am creating a program that draws and updates creatures/images to a JFrame. Each creature object contains all the information for paint to be able to draw it such as x,y coordinates and an BufferedImage. Currently every time a creature object moves it calls repaint(), which as you will see below in my paint/paintComponent (not sure which is is best) method will run a loop through all existing creatures and update their position & graphics on the screen.
So my query, is this the best way to do this as I am concerned that the RepaintManager is redrawing everything on the screen, which is not very efficient. I have a read a few posts/articles about clipping or overriding update methods but just cant quite get my head around them - so is it possible to every time repaint is called it only updates objects/creatures that have changed?
Some code of what I am talking about:
public void paintComponent (Graphics g) {
super.paintComponent(g);
//setDoubleBuffered(true); //Probably not needed?
Graphics2D g2d = (Graphics2D) g;
//Draws the land area for penguins.
g2d.setColor(new Color(121,133,60));
g2d.fill3DRect(land.x, land.y, land.width, land.height, true);
//OR g2d.fill(land);
g2d.setColor(Color.BLUE);
g2d.fill(sea);
drawCreatures(g2d);
}
All graphics in the paint method won't change and shouldnt need to be repainted, however the method below will...
private void drawCreatures(Graphics2D g2d) {
try {
for (Creature c : crlist) {
g2d.drawImage(c.createImage(txs,tys), c.getPos(1).width, c.getPos(1).height, this);
//g2d.drawImage(cImg,c.getPos(1).width,c.getPos(1).height,this);
if (c instanceof Fish && c.getMating().equals(Mating.WBABY)) {
int xos=0;
for (Creature fb : c.getChildren()) {
if (fb.getMating().equals(Mating.BABY)) g2d.drawImage(fb.createImage(txs,tys),c.getPos(1).width+xos,c.getPos(1).height+50,txs/2,tys/2,this);
xos+=25;
}
}
if (c.getInfo()==true) displayInfo(g2d,c); //This changes when a creature is clicked on.
else if (c.getState()!=State.NORMAL || c.getMating().equals(Mating.LOVE)) drawState(g2d,c); //updated through a creature's move/search methods.
}
}
catch(ConcurrentModificationException cme) { System.out.println("CME ERROR!"); }
}
The important part is the first line of the enhanced for loop as this draws images to the JFrame window. The createImage method simply gets the creatures image and converts/modifies e.g. flips it when they move left before paint uses it.
Animation is currently handled by each creature running a Thread, however I am also wondering if a Swing Timer would be better as I am currently getting ConcurrentModificationException when a creature tries to add a new creature to crlist.
private class Creature implements Behaviours<Creature>, Runnable {
//...variables
//...constructor
//...methods for updating the creature/object
@Override
public void run() {
while (getState()!=State.DEAD) {
move(); //where the coordinates of a creature is updated.
repaint();
try { Thread.sleep(1000); }
catch(InterruptedException e) {}
}
}
So every 1 sec for each creature move and repaint is called, but I would like a way either not have to loop through each creature in paint or ensure when repaint is called it only updates the creature that called it.
Any suggestions or just pointing me to another post would be appreciated. Thanks.
you can use this code. you have to extends your drawing objects to PaintObject, background as well. and implement their paint in their own. I hope this code can give you idea. you can collect all area needs to be repaint. then, find which object are in there. after, repaint only this area