patternjavaMinor
Movement around a large map
Viewed 0 times
movementmaplargearound
Problem
I'm trying to make a small shooter game, where you can only see a small portion of the map around you. The map will also be much larger then the actual JPanel (The panel is 1000 by 1000, the map currently is 5000 by 5000).
When I added movement, the game seemed to lag slightly, mainly noticeable in the graphics flickering, however the game was still playable
Adding in a few walls drawn on the map significantly dropped performance, however, and now the game is entirely unplayable.
I'm looking for some tips to help optimize my code to lower this lag.
The other major problem I've been having is in regards to how I draw the map. When I move the area of the map I'm able to see down and to the left, the actual image moves up and to the right. This means that the Maps coordinates (and therefore the players coordinates), are negative. This isn't entirely game breaking, but is an annoyance nonetheless.
I've only included classes associated with movement below, but if the JPanel and JFrame classes are necessary, I can add them
Edit
Removing the line
image.getGraphics().draw3DRect(10, 10, 10, 10, true);
seemed to speed up the game considerably, to the point of near to no lag
However, I'm still almost certain my code is far from efficient - are there any other tweaks I could use to speed it up?
GameManager (Holds the gamethread, and runs the majority of the logic)
```
package Logic;
import java.util.ArrayList;
import Runner.Panel;
import Entities.*;
import java.awt.Graphics;
import Movement.*;
public class GameManager {
private final Panel gamepanel;
private boolean game_is_running = true;
private final Map map = new Map();
private Player player = new Player(100, 100);
private Movement movement = new Movement(0);
ArrayList walls = new ArrayList();
public GameManager(Panel p) {
gamepanel = p;
initializeWalls();
gamethread.start();
}
private void initializeWalls() {
//adds walls on the map image
When I added movement, the game seemed to lag slightly, mainly noticeable in the graphics flickering, however the game was still playable
Adding in a few walls drawn on the map significantly dropped performance, however, and now the game is entirely unplayable.
I'm looking for some tips to help optimize my code to lower this lag.
The other major problem I've been having is in regards to how I draw the map. When I move the area of the map I'm able to see down and to the left, the actual image moves up and to the right. This means that the Maps coordinates (and therefore the players coordinates), are negative. This isn't entirely game breaking, but is an annoyance nonetheless.
I've only included classes associated with movement below, but if the JPanel and JFrame classes are necessary, I can add them
Edit
Removing the line
image.getGraphics().draw3DRect(10, 10, 10, 10, true);
seemed to speed up the game considerably, to the point of near to no lag
However, I'm still almost certain my code is far from efficient - are there any other tweaks I could use to speed it up?
GameManager (Holds the gamethread, and runs the majority of the logic)
```
package Logic;
import java.util.ArrayList;
import Runner.Panel;
import Entities.*;
import java.awt.Graphics;
import Movement.*;
public class GameManager {
private final Panel gamepanel;
private boolean game_is_running = true;
private final Map map = new Map();
private Player player = new Player(100, 100);
private Movement movement = new Movement(0);
ArrayList walls = new ArrayList();
public GameManager(Panel p) {
gamepanel = p;
initializeWalls();
gamethread.start();
}
private void initializeWalls() {
//adds walls on the map image
Solution
You mentioned that the main goal was performance. I'll summarize some hints, of which some touch the performance aspect, and others may affect the performance, and others are simply intended to improve the code in other ways:
1) You mentioned that removing the line
caused a speedup. Although I can't imagine why this should be the case, as this is only done once when the map is painted, one should solve this differently - because it is done once each time that the map is painted. This is simply not necessary. You can add this rectangle to the image once in the constructor, after the image has been loaded. And then, you should dispose the graphics when you no longer need it. The same applies for other cases where you directly operate on
IIRC, the
Additionally, you should consider setting the color that you want the rectangle to be painted with. Otherwise, it is not clear what color the rectangle will have.
(Note that the way of loading and the error handling are horrible as well. You should likely not load the image from a fixed path. Instead, you should use
2) A wild guess, but this can make a significant (!) difference: You could make sure that the images are in a format that can be painted efficiently. When you load an image with
and then load your image as
3) The line
looks odd. Negating a number by multiplying it with -1 is something that I'd consider as a very bad style. It should likely be
instead.
4) Parts of the "lags" that you are experiencing may come from the game loop. It explicitly says
which should simply not be necessary. Swing is internally coalescing the repaint triggers. This means that when you call
5) Although it is not used yet: The method
will create a new rectangle instance each time. This may create a lot of garbage, and eventually decrease the performance. But consider that, unfortunately,
1) You mentioned that removing the line
image.getGraphics().draw3DRect(10, 10, 10, 10, true);caused a speedup. Although I can't imagine why this should be the case, as this is only done once when the map is painted, one should solve this differently - because it is done once each time that the map is painted. This is simply not necessary. You can add this rectangle to the image once in the constructor, after the image has been loaded. And then, you should dispose the graphics when you no longer need it. The same applies for other cases where you directly operate on
image.getGraphics().IIRC, the
dispose call on the actual image implementation returned by ImageIO is a no-op. But this is not guaranteed. Future implementations might require dispose to be called.Additionally, you should consider setting the color that you want the rectangle to be painted with. Otherwise, it is not clear what color the rectangle will have.
public class Map extends Entity {
public Map() {
try {
image = ImageIO.read(new File("resources/Maps/TestMap.jpg"));
} catch (Exception ex) {
System.out.println("WARNING: MAP NOT FOUND" + "\n" + "ERROR CODE 1");
System.exit(-1);
}
Graphics g = image.getGraphics();
g.setColor(Color.BLACK);
g.draw3DRect(10, 10, 10, 10, true);
g.dispose();
}(Note that the way of loading and the error handling are horrible as well. You should likely not load the image from a fixed path. Instead, you should use
getClass().getResourceAsStream() to obtain the image input stream. This will become important when you want to deploy the application as a JAR file. Additionally, System.exit(...) usually is a no-go. Creating a "dummy image" and/or printing an error message should be sufficient here.2) A wild guess, but this can make a significant (!) difference: You could make sure that the images are in a format that can be painted efficiently. When you load an image with
ImageIO, you never know which BufferedImage.TYPE_... the resulting image has. It's often a good idea to convert the image into a known type that can be painted efficiently. For example, you can use a methodprivate static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}and then load your image as
image = convertToARGB(ImageIO.read(...));3) The line
g.drawRect((int)(m.getX()*-1-x*-1), (int)(m.getY()*-1-y*-1), 100, 100);looks odd. Negating a number by multiplying it with -1 is something that I'd consider as a very bad style. It should likely be
g.drawRect((int)(-m.getX()+x), (int)(-m.getY()+y), 100, 100);instead.
4) Parts of the "lags" that you are experiencing may come from the game loop. It explicitly says
//repaints the game as fast as it can
gamepanel.repaint();which should simply not be necessary. Swing is internally coalescing the repaint triggers. This means that when you call
repaint() 1000 times in a row in a very short time, it may effectively cause the component to be painted only once. However, this does not come for free. Flooding the paint system with unnecessary repaint() triggers is certainly not beneficial. You should only call repaint() when there really have been changes. Namely, after the call to update(). (In fact, you might even consider a short Thread#sleep in the main loop, but this depends on several other factors). 5) Although it is not used yet: The method
public Rectangle getBounds(){
Rectangle ret = new Rectangle((int)x,(int)y,width,height);
return ret;
}will create a new rectangle instance each time. This may create a lot of garbage, and eventually decrease the performance. But consider that, unfortunately,
Rectangle is not immutable, so directly returning a single instance of the rectangle may not be applicable here.Code Snippets
image.getGraphics().draw3DRect(10, 10, 10, 10, true);public class Map extends Entity {
public Map() {
try {
image = ImageIO.read(new File("resources/Maps/TestMap.jpg"));
} catch (Exception ex) {
System.out.println("WARNING: MAP NOT FOUND" + "\n" + "ERROR CODE 1");
System.exit(-1);
}
Graphics g = image.getGraphics();
g.setColor(Color.BLACK);
g.draw3DRect(10, 10, 10, 10, true);
g.dispose();
}private static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}image = convertToARGB(ImageIO.read(...));g.drawRect((int)(m.getX()*-1-x*-1), (int)(m.getY()*-1-y*-1), 100, 100);Context
StackExchange Code Review Q#128951, answer score: 2
Revisions (0)
No revisions yet.