2
\$\begingroup\$

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();
  }      
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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 to JFrame, 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.
  • incheckTile() 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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.