Results 1 to 1 of 1
  1. #1
    Prime624 is offline Member
    Join Date
    Feb 2013
    Location
    San Diego
    Posts
    98
    Rep Power
    0

    Default Java Graphics2D Lags when Image isn't Changed

    I am making a game with Java JPanel and Graphics2D. When I pan the map, there is lag for the first half second or so, but is smooth after that. It will lag again if I stop and start panning. (Link to videos with and without lag: https://www.dropbox.com/sh/xyztdvoau..._AVSPKHla?dl=0)

    This problem just arose when I was cutting down on unnecessary processing. For text boxes, I am drawing a BufferedImage of the text and painting that on the JPanel with drawImage(), but the problem started when I changed this to only paint each box once, instead of every frame.

    I've isolated the problem and found that if I change the saved text box image in any way (replacing it or painting on it whatsoever (even just a 1x1 square) removes the lag, but not doing this, or simply calling createGraphics() does not solve the issue.

    Another possible point of interest is the method in which I am calling drawImage():

    public void paintSelfWith(Graphics2D g2) {
    g2.drawImage(imgSelf, x, y, null);
    }

    I'm thinking maybe the image is being held by the Graphics2D object, but I haven't had any luck on Google or SO. Any insight on this issue is appreciated.

    I have cut the code down to 2 classes that still run and have this issue. The source is here: https://www.dropbox.com/sh/xyztdvoau..._AVSPKHla?dl=0
    Java Code:
    package wgp.simple_gui;
    
    import java.awt.*;
    import java.awt.event.*;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    /**
     * This is the only class in the simple_gui package that should contain any game
     * logic. Theoretically should be easy to replace this class with a different UI
     * package and controller class and everything will still work the same provided
     * the Controller class is basically the same.
     *
     * @author Prime624
     */
    public class Controller extends JPanel implements ActionListener, KeyListener {
    
    	public static void main(String[] args) {
    		Controller simpleGui = new Controller();
    	}
    
    	public static final int FPS = 60;
    	private final int MSPF;// Milliseconds per frame (1000 / fps).
    
    	Thread renderThread;
    
    	private GameView gameView;
    	private JFrame frame;
    	private Timer timer;
    	private boolean keyPressedLeft, keyPressedRight, keyPressedUp, keyPressedDown;
    
    	public Controller() {
    		MSPF = 1000 / FPS;
    
    		frame = new JFrame();
    		frame.add(this);
    		frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		frame.setVisible(true);
    		frame.setLocationRelativeTo(null);
    
    		gameView = new GameView(this, frame.getWidth(), frame.getHeight());
    
    		Runnable runnable = new Runnable() {
    			int counter = 0;
    
    			@Override
    			public void run() {
    				repaint();
    			}
    		};
    		ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
    		service.scheduleAtFixedRate(runnable, 0, MSPF, TimeUnit.MILLISECONDS);
    
    		timer = new Timer(17, this);
    		timer.start();
    
    		this.addKeyListener(this);
    		this.setFocusable(true);
    		this.requestFocus();
    	}
    
    	@Override
    	protected void paintComponent(Graphics g) {
    		Graphics2D g2 = (Graphics2D) g;
    
    		g2.setColor(Color.BLACK);
    		g2.fillRect(0, 0, getWidth(), getHeight());
    
    		if (gameView != null) {
    			gameView.renderWith(g2);
    		}
    	}
    
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		if (e.getSource() == timer) {
    			if (gameView != null && gameView instanceof GameView) {
    				// Panning.
    				if (keyPressedLeft) {
    					gameView.panHorizontal(-25);
    				} else if (keyPressedRight) {
    					gameView.panHorizontal(25);
    				}
    				if (keyPressedUp) {
    					gameView.panVertical(-25);
    				} else if (keyPressedDown) {
    					gameView.panVertical(25);
    				}
    			}
    		}
    	}
    
    	@Override
    	public void keyPressed(KeyEvent e) {
    		switch (e.getKeyCode()) {
    			case KeyEvent.VK_LEFT:
    				keyPressedLeft = true;
    				break;
    			case KeyEvent.VK_RIGHT:
    				keyPressedRight = true;
    				break;
    			case KeyEvent.VK_UP:
    				keyPressedUp = true;
    				break;
    			case KeyEvent.VK_DOWN:
    				keyPressedDown = true;
    				break;
    			case KeyEvent.VK_A:
    				keyPressedLeft = true;
    				break;
    			case KeyEvent.VK_D:
    				keyPressedRight = true;
    				break;
    			case KeyEvent.VK_W:
    				keyPressedUp = true;
    				break;
    			case KeyEvent.VK_S:
    				keyPressedDown = true;
    				break;
    		}
    	}
    
    	@Override
    	public void keyReleased(KeyEvent e) {
    		switch (e.getKeyCode()) {
    			case KeyEvent.VK_LEFT:
    				keyPressedLeft = false;
    				break;
    			case KeyEvent.VK_RIGHT:
    				keyPressedRight = false;
    				break;
    			case KeyEvent.VK_UP:
    				keyPressedUp = false;
    				break;
    			case KeyEvent.VK_DOWN:
    				keyPressedDown = false;
    				break;
    			case KeyEvent.VK_A:
    				keyPressedLeft = false;
    				break;
    			case KeyEvent.VK_D:
    				keyPressedRight = false;
    				break;
    			case KeyEvent.VK_W:
    				keyPressedUp = false;
    				break;
    			case KeyEvent.VK_S:
    				keyPressedDown = false;
    				break;
    		}
    	}
    
    	@Override
    	public void keyTyped(KeyEvent e) {
    	}
    
    	public void updateViews() {
    		gameView.update();
    	}
    
    }
    
    
    package wgp.simple_gui;
    
    import java.awt.*;
    import java.awt.image.BufferedImage;
    
    /**
     *
     * @author Prime624
     */
    public class GameView {
    
    	private final Controller viewController;
    	private int widthTotal, heightTotal;
    
    	private int tileSize, panHorz, panVert;
    
    	private BufferedImage terrainImage;
    	private int tileImageSize;
    	private CityLabel cityLabel;
    
    	public GameView(Controller viewController, int widthTotal, int heightTotal) {
    		this.viewController = viewController;
    		this.widthTotal = widthTotal;
    		this.heightTotal = heightTotal;
    
    		tileSize = 30;
    		panHorz = 0;
    		panVert = 0;
    
    		updateTileMapRender();
    		update();
    	}
    
    	// The effective width of this view.
    	public int getWidth() {
    		return widthTotal;
    	}
    
    	// The effective height of this view.
    	public int getHeight() {
    		return heightTotal;
    	}
    
    	public void update() {
    		cityLabel = new CityLabel();
    	}
    
    	public void updateTileMapRender() {
    		tileImageSize = 1;
    
    		terrainImage = new BufferedImage(100, 60, BufferedImage.TYPE_INT_RGB);
    		Graphics2D g2 = terrainImage.createGraphics();
    
    		for (int x = 0; x < terrainImage.getWidth(); x++) {
    			for (int y = 0; y < terrainImage.getHeight(); y++) {
    				g2.setColor(((x + y) % 10 < 5) ? Color.DARK_GRAY : Color.LIGHT_GRAY);
    				g2.fillRect(x * tileImageSize, y * tileImageSize, tileImageSize, tileImageSize);
    			}
    		}
    		g2.dispose();
    	}
    
    	public void renderWith(Graphics2D g2) {
    		g2.drawImage(terrainImage, -panHorz, -panVert, terrainImage.getWidth() * tileSize, terrainImage.getHeight() * tileSize, null);
    
    		// THIS LINE causes/fixes the bug.
    //		cityLabel.refresh();
    		cityLabel.paintSelfWith(g2);
    	}
    
    	public void centerAt(Point p) {
    		centerAt(p.x, p.y);
    	}
    
    	public void centerAt(int x, int y) {
    		panHorz = (x * tileSize) - (getWidth() / 2);
    		panVert = (y * tileSize) - (getHeight() / 2);
    	}
    
    	public void panHorizontal(int dist) {
    		panHorz += dist;
    		if (panHorz < -getWidth()) {
    			panHorz = -getWidth();
    		} else if (panHorz >= tileSize * terrainImage.getWidth()) {
    			panHorz = tileSize * terrainImage.getWidth();
    		}
    	}
    
    	public void panVertical(int dist) {
    		panVert += dist;
    		if (panVert < -getHeight()) {
    			panVert = -getHeight();
    		} else if (panVert >= tileSize * terrainImage.getHeight()) {
    			panVert = tileSize * terrainImage.getHeight();
    		}
    	}
    
    	private class CityLabel {
    
    		public int x, y, width, height;
    		public BufferedImage imgSelf;
    
    		public CityLabel() {
    			x = 300;
    			y = 300;
    			width = 100;
    			height = 100;
    			update();
    		}
    
    		public void refresh() {
    			Graphics2D g2 = imgSelf.createGraphics();
    			g2.fillRect(0, 0, 30, 30);
    			g2.dispose();
    		}
    
    		public void update() {
    			BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    			Graphics2D g2 = newImage.createGraphics();
    
    			g2.setColor(Color.RED);
    			g2.fillRect(0, 0, width, height);
    
    			g2.dispose();
    			imgSelf = newImage;
    		}
    
    		public void paintSelfWith(Graphics2D g2) {
    			g2.drawImage(imgSelf, x, y, null);
    		}
    
    	}
    
    }
    Last edited by Prime624; 12-26-2017 at 07:15 PM. Reason: Embedded code

Similar Threads

  1. Replies: 3
    Last Post: 10-14-2014, 08:14 PM
  2. My ip lags, localhost does not
    By Daslee in forum Networking
    Replies: 20
    Last Post: 04-14-2012, 09:20 AM
  3. Replies: 10
    Last Post: 04-13-2012, 06:54 PM
  4. Java Graphics2D Problem
    By stevokk in forum Java 2D
    Replies: 9
    Last Post: 02-18-2011, 08:35 PM
  5. My encrypting thingy lags alot..
    By Addez in forum New To Java
    Replies: 3
    Last Post: 09-15-2009, 11:33 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •