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();
 } 
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Nov 20, 2016 at 20:27
\$\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
answered Nov 20, 2016 at 21:10
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.