\$\begingroup\$
\$\endgroup\$
I made a Snake clone for a programming class. I wanted some feedback regarding coding style and will appreciate any other opinions concerning my code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Snake extends JFrame {
/* Some properties. */
private final int BOARD_WIDTH = 20 * 30; // Tilesize * number of columns
private final int BOARD_HEIGHT = 20 * 30;
private final int TILE_SIZE = 20;
private final int ALL_TILES = 900; // Total numer of tiles
private final int DELAY = 100;
/* The coordinates of the snake. */
private int[] xCoor = new int[ALL_TILES];
private int[] yCoor = new int[ALL_TILES];
/* Coordinates for apple. */
private int apple_x, apple_y;
/* Pressed Key. */
int pressedKey = KeyEvent.VK_DOWN;
int oldPressedKey;
private int snakeSize = 3;
private boolean inGame = true;
public class Board extends JPanel implements KeyListener, ActionListener {
Board(){
setBackground(Color.black);
// Set snake starting coordinates.
for(int i = 0; i < snakeSize; i++){
yCoor[i] = 140 - (i * 30);
xCoor[i] = 140;
}
spawnAppleCoor();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (inGame) {
/* Draw apple. */
g.setColor(Color.red);
g.fillRect(apple_x, apple_y, TILE_SIZE, TILE_SIZE);
/* Draw snake. */
for (int i = 0; i < snakeSize; i++) {
if (i == 0) {
g.setColor(Color.yellow); // Snakes head yellow
} else {
g.setColor(Color.green);}
g.fillRect(xCoor[i], yCoor[i], TILE_SIZE, TILE_SIZE);
}
/* Draw score */
g.setFont(new Font("Sans serif", Font.BOLD, 20));
g.drawString(getScore(), 550, 30);
} else {
gameOver(g);
}
}
public void actionPerformed(ActionEvent e) {
checkTile();
moveSnakeCoor();
repaint();
}
/* Saves pressedKeyCode to pressedKey. */
public void keyPressed(KeyEvent e) {
oldPressedKey = pressedKey;
pressedKey = e.getKeyCode();
}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
private void checkTile(){
/* Check if outside of wall. */
if ( xCoor[0] > BOARD_WIDTH || xCoor[0] < 0 || yCoor[0] > BOARD_HEIGHT || yCoor[0] < 0 ) {
inGame = false;
}
/* Check for collisions. */
for(int i = 1; i < xCoor.length; i++){
if (xCoor[0] == xCoor[i] && yCoor[0] == yCoor[i]){
inGame = false;
}
}
/* Check for apples. */
if ((xCoor[0] == apple_x) && (yCoor[0] == apple_y)) {
snakeSize++;
spawnAppleCoor();
}
}
/** Generates random coordinates for apple. */
private void spawnAppleCoor() {
int r = (int) (Math.random() * Math.sqrt(ALL_TILES) - 1);
apple_x = ((r * TILE_SIZE));
r = (int) (Math.random() * Math.sqrt(ALL_TILES) - 1);
apple_y = ((r * TILE_SIZE));
}
/** Simply prints a gameOver-message to screen when called. */
private void gameOver(Graphics g) {
g.setColor(Color.white);
g.setFont(new Font("Sans serif", Font.BOLD, 20));
g.drawString(("Game Over! You ate " + (getScore()) + " apples!"),
BOARD_WIDTH / 4, BOARD_HEIGHT / 2);
g.drawString("Press space to restart",
BOARD_WIDTH / 4 + 20, BOARD_HEIGHT / 2 + 30);
/* Restart game if space is pressed. */
if (pressedKey == KeyEvent.VK_SPACE){
inGame = true;
pressedKey = KeyEvent.VK_DOWN;
setVisible(false);
dispose();
Snake s = new Snake();
}
}
private void moveSnakeCoor(){
/* Move coordinates up one in the matrix.*/
for (int i = snakeSize; i > 0; i--) {
xCoor[i] = xCoor[(i - 1)];
yCoor[i] = yCoor[(i - 1)];
}
/* Depending on what key was pressed, change coordinates
* accordingly. */
switch (pressedKey) {
case KeyEvent.VK_DOWN:
yCoor[0] += TILE_SIZE;
break;
case KeyEvent.VK_UP:
yCoor[0] -= TILE_SIZE;
break;
case KeyEvent.VK_LEFT:
xCoor[0] -= TILE_SIZE;
break;
case KeyEvent.VK_RIGHT:
xCoor[0] += TILE_SIZE;
break;
}
}
private String getScore(){
return "" + (snakeSize - 3);
}
}
public Snake(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(BOARD_WIDTH, BOARD_HEIGHT);
setResizable(false);
setLocation(50, 50);
Board b = new Board();
addKeyListener(b);
add(b);
setVisible(true);
Timer t = new Timer(DELAY, b);
t.start();
}
public static void main (String[] args) {
Snake s = new Snake();
}
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
1 Answer 1
\$\begingroup\$
\$\endgroup\$
Pros
- almost consistent Naming following the Java Naming Guideline
- constants instead of "magic numbers"
cons
Code srtucture
- constructor
Snake()
is last method, should be the first.
inheritance
- Main class extends
JFrame
instead of just using it. (it does not add new behavior toJFrame
, just configures it.) - class
Board
implements Listeners directly. Listeners should be implemented as anonymous inner classes or (if bigger) as top level classes of their own.
comments
- almost all comment repeat what the code already does. Comments should explain why the code is like it is. otherwise chose better names considering a comment.
- in
checkTile()
the comments separate the method into logical blocks. This logical blocks should be methods of their own with names derived from the comments
data structures
- Coordinates of snake elements are stored in two primitive arrays for x and y separately. You constantly must copy these arrays synchronously when changing the snakes position and/or length. Keeping them in a list of custom
Coordinate
objects could simplify this.
Naming
- still some "magic numbers" left in
answered Nov 20, 2016 at 21:10
lang-java