I’m making a simple tower defense game in Swing and I’ve run into a performance problem when I try to put many sprites (more than 20) on screen.
The whole game takes place on a JPanel which has setIgnoreRepaint(true).
Here is the paintComponent method (con is the Controller):
public void paintComponent(Graphics g){
super.paintComponent(g);
//Draw grid
g.drawImage(background, 0, 0, null);
if (con != null){
//Draw towers
for (Tower t : con.getTowerList()){
t.paintTower(g);
}
//Draw targets
if (con.getTargets().size() != 0){
for (Target t : con.getTargets()){
t.paintTarget(g);
}
//Draw shots
for (Shot s : con.getShots()){
s.paintShot(g);
}
}
}
}
The Target class simple paints a BufferedImage at its current location. The getImage method doesn’t create a new BufferedImage, it simply returns the Controller class’s instance of it:
public void paintTarget(Graphics g){
g.drawImage(con.getImage("target"), getPosition().x - 20, getPosition().y - 20, null);
}
Each target runs a Swing Timer to calculate its position. This is the ActionListener it calls:
public void actionPerformed(ActionEvent e) {
if (!waypointReached()){
x += dx;
y += dy;
con.repaintArea((int)x - 25, (int)y - 25, 50, 50);
}
else{
moving = false;
mover.stop();
}
}
private boolean waypointReached(){
return Math.abs(x - currentWaypoint.x) <= speed && Math.abs(y - currentWaypoint.y) <= speed;
}
Other than that, repaint() is only called when placing a new tower.
How can I improve the performance?
This may be your problem – having each target/bullet (I assume?) responsible for keeping track of when to update itself and draw itself sounds like quite a bit of work. The more common approach is to have a loop along the lines of
Essentially, an object further up the chain has the responsibility to keep track of all entities in your game, tell them to update themselves, and render them.