简体   繁体   中英

Stop JPanel's paintComponent method from painting the background

I'm making a snake game in Java.

To make it efficient, I only paint the positions that have changed this frame (the first and last cells of the snake).

Here's my code:

public class GameCanvas extends JPanel {

private final List<GameChange> changes;

public GameCanvas() {
    setBackground(Color.darkGray);

    changes = new ArrayList<>();
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    for (GameChange change : changes) {
        Vector2 pos = change.position;
        int val = change.value;

        if (val != 0) g2d.setColor(Color.BLACK);
        else g2d.setColor(Color.WHITE); //getBackground();

        g2d.fillRect(GameWindow.pixelSize * pos.x,GameWindow.pixelSize * pos.y, GameWindow.pixelSize, GameWindow.pixelSize);
    }

    changes.clear();
}

public void applyChanges(List<GameChange> changes) {
    this.changes.addAll(changes);
    repaint();
}
}

The only problem is that the paintComponent method is repainting the background and the middle of the snake is disappearing.

The black cell is the new head and the white one is the one that I'm deleting. The middle cell was supposed to be black.

EDIT:

Everyone is telling me to draw the whole map but I really want to work on performance. This is what I've done so far:

private void paintChanges(List<GameChange> changes) {
    Graphics2D g2d = (Graphics2D) getGraphics();

    // Here I paint only the changes
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;

    // Here I paint everything
}

When the snake moves I only paint the changes but if the the frame gets repainted automatically the snake wont disappear. It appears to be working but I'm not sure if it's safe to use the getGraphics() method.

This is obviously not your game but it may help dispel the notion that you need to do something special to increase painting efficiency.

  • To create the snake, hold the left button down and drag out a curved line.
  • then release the button and just move the mouse around in the panel and watch the "snake" follow the mouse.
  • you can add more points by dragging the mouse at any time.

This works by simply creating a list of points and drawing a line in between them. As the mouse moves it removes the first point and adds the current one to the end. The paint method just iterates thru the list for each mouse movement and draws all the lines, giving the appearance of movement.

There is one obvious (and perhaps other, not so obvious) flaws with this. The number of points is constant but the snake expands and contracts in size since the points are spread out as the mouse moves faster so the lines between the points are longer. But that is not related to painting but to the speed of the mouse movement.

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SimpleSnake extends JPanel {
    JFrame frame = new JFrame("Simple Snake");
    List<Point> snake = new ArrayList<>();
    final static int WIDTH = 500;
    final static int HEIGHT = 500;
    public static void main(String[] args) {
        SwingUtilities.invokeLater(()-> new SimpleSnake());
    }
    public SimpleSnake() {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        addMouseMotionListener(new MyMouseListener());
        setBackground(Color.white);
        frame.add(this);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(WIDTH, HEIGHT);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (snake.size() < 2) {
            return;
        }
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.black);
        g2d.setStroke(new BasicStroke(3)); // line thickness
        Point start = snake.get(0);
        for(int i = 1; i < snake.size(); i++) {
            Point next = snake.get(i);
            g2d.drawLine(start.x, start.y, next.x, next.y);
            start = next;
        }
        g2d.dispose();
    }
    
    public class MyMouseListener extends MouseAdapter {
        public void mouseDragged(MouseEvent me) {
            snake.add(new Point(me.getX(), me.getY()));
            repaint();
        }
        
        public void mouseMoved(MouseEvent me) {
            if(snake.isEmpty()) {
                return;
            }
            snake.remove(0);
            snake.add(new Point(me.getX(), me.getY()));
            repaint();
        }       
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM