Reputation: 89
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.
Upvotes: 0
Views: 375
Reputation: 40034
This is obviously not your game but it may help dispel the notion that you need to do something special to increase painting efficiency.
"snake"
follow the mouse.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();
}
}
}
Upvotes: 1