-1

I am trying to create a snake clone just as a practice. ive drawn the snake and added the movement patterns but the snake eats on it self when I press any key to move. but its not moving. the array retracts the reactacles on the starting point and does nothing.

here is my snake class I have removed my comments as they where more than the code and the posting system was not allowing me to post

Edit

If you need anything from the other classes please let me know. but I think my error is somewhere in here

EDIT 2

Added the entire code, you can just copy paste in inside a new project and you will reproduce my error.

public class Snake {

    List<Point> sPoints;
    int xDir,yDir;
    boolean isMoving,addTail;
    final int sSize = 20, startX = 150 , startY = 150;
    public Snake(){

        sPoints = new ArrayList<Point>();

        xDir = 0;
        yDir = 0;

        isMoving = false;

        addTail = false;
        sPoints.add(new Point(startX,startY));

        for(int i=1; i<sSize; i++) {


            sPoints.add(new Point(startX - i * 4,startY));
        }
    }

    public void draw(Graphics g){

        g.setColor(Color.white);

        for(Point p : sPoints) {

            g.fillRect(p.getX(),p.getY(),4,4);
        }
    }

    public void move(){
        if (isMoving) {
            Point temp = sPoints.get(0);
            Point last = sPoints.get(sPoints.size() - 1);

            Point newstart = new Point(temp.getX() + xDir * 4, temp.getY() + yDir * 4);


            for (int i = sPoints.size() - 1; i >= 1; i--) {

                sPoints.set(i, sPoints.get(i - 1));
            }

            sPoints.set(0, newstart);
        }
    }

    public int getxDir() {
        return xDir;
    }

    public void setxDir(int x) {
        this.xDir = xDir;
    }

    public int getyDir() {
        return yDir;
    }

    public void setyDir(int y) {
        this.yDir = yDir;
    }

    public  int getX(){
        return sPoints.get(0).getX();
    }

    public int getY(){
        return sPoints.get(0).getY();
    }

    public boolean isMoving() {
        return isMoving;
    }

    public void setIsMoving(boolean b) {
        isMoving = b;
    }
}

The following is the point class. just some getters setters for the points ,for those i used the IntelliJ to auto generate them.. (again i removed comments )

public class Point {

    private  int x,y;

    public Point() {

        x = 0;
        y = 0;
    }


      public Point(int x, int y) {

          this.x =x;
          this.y =y;
      }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }


}

and finally my main class called game. in here what I do is create my applet give it background color. create my threat for the runnable. and also add the movement patterns for up/right/down/left... and use several classes to update my drawing patterns so it can simulate movement by updating each of state of my rect list.

import java.applet.Applet;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Game extends Applet implements Runnable, KeyListener {

    //setting up double buffering.
    Graphics graphics;
    Image img;
    Thread thread;
    Snake snake;
    public void init() {
        //setting the size of our Applet
        this.resize(400,400);
        //we gonna create the image just the same size as our applet.
        img = createImage(400,400);
        //this represents our offscreen image that we will draw
        graphics = img.getGraphics();
       this.addKeyListener(this);
        snake = new Snake();
        thread = new Thread(this);
        thread.start();
    }

    public void paint(Graphics g) {
        //Setting the background of our applet to black
        graphics.setColor(Color.black);
        //Fill rectangle 0 , 0 (starts from) for top left corner and then 400,400 to fill our entire background to black
        graphics.fillRect(0,0,400,400);
        snake.draw(graphics);
        //painting the entire image
        g.drawImage(img,0,0,null);
    }

    //Update will call on Paint(g)
    public void update(Graphics g){
        paint(g);
    }
    //Repaint will call on Paint(g)
    public  void repaint(Graphics g){
        paint(g);
    }


    public void run() {
        //infinite loop
        for(;;) {
            snake.move();
            //drawing snake
            this.repaint();
        //Creating a time delay
            try {
                Thread.sleep(40);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }


    public void keyTyped(KeyEvent keyEvent) {


    }

    public void keyPressed(KeyEvent keyEvent) {
        if(!snake.isMoving()){ //this will allow the snake to start moving, but will disable LEFT for just the 1st move
            if(keyEvent.getKeyCode() == KeyEvent.VK_UP || keyEvent.getKeyCode() == KeyEvent.VK_RIGHT ||
                    keyEvent.getKeyCode() == KeyEvent.VK_DOWN ) {
                snake.setIsMoving(true);
            }
        }

        //setting up Key mapping so when the user presses UP,RIGHT,DOWN,LEFT. the Snake will move accordingly
        if(keyEvent.getKeyCode() == KeyEvent.VK_UP) {
            if (snake.getyDir() != 1) {
                snake.setyDir(-1);
                snake.setxDir(0);
            }
        }
        if(keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
            if (snake.getxDir() != -1) {
                snake.setxDir(1);
                snake.setyDir(0);
            }
        }
        if(keyEvent.getKeyCode() == KeyEvent.VK_DOWN) {
            if (snake.getyDir() != -1) {
                snake.setyDir(1);
                snake.setxDir(0);
            }
        }
        if(keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
            if (snake.getxDir() != 1) {
                snake.setxDir(-1);
                snake.setyDir(0);
            }
        }

    }

    public void keyReleased(KeyEvent keyEvent) {

    }
}
Demeteor
  • 1,193
  • 2
  • 17
  • 33

2 Answers2

1

Here is some opinion I have reading your code.

  1. The reason your snake won't move is because your snake.setyDir() and snake.setxDir() didn't take the input to overwrite xDir and yDir. They are assigning to itself.
  2. There is a Point2D class ready for you in JDK
  3. When moving the snake, you just need to remove the tail and add one more block before the head. You can keep the body tight (according to my common knowledge to snake). enter image description here Consider a L shape snake on the left, the bottom end is the head and it is currently heading right. To move the snake, remove the tail (green block) and add one more to the head according to its direction (red block). It final state become the snake on the right. LinkedList suit the needs.
  4. If using two int (xDir and yDir) to control the snake direction is confusing, you can help your self by creating a enum. Those -1, 0, 1 with x and y may confuse you.
  5. Declare constant instead of magic number. e.g. the width of block 4, image size 400
  6. Is Snake.addTail unnecessary?
  7. Attribute should has accessibility modifier

End result:

enter image description here

Game.java

import java.applet.Applet;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;

public class Game extends Applet implements Runnable, KeyListener {

    private final int GAMEBOARD_WIDTH = 400;

    // setting up double buffering.
    private Graphics graphics;
    private Image img;
    private Thread thread;
    private Snake snake;

    public void init() {
        // setting the size of our Applet
        this.resize(GAMEBOARD_WIDTH, GAMEBOARD_WIDTH);
        // we gonna create the image just the same size as our applet.
        img = createImage(GAMEBOARD_WIDTH, GAMEBOARD_WIDTH);
        // this represents our offscreen image that we will draw
        graphics = img.getGraphics();
        this.addKeyListener(this);
        snake = new Snake();
        thread = new Thread(this);
        thread.start();
    }

    public void paint(Graphics g) {
        // Setting the background of our applet to black
        graphics.setColor(Color.BLACK);
        // Fill rectangle 0 , 0 (starts from) for top left corner and then 400,400 to
        // fill our entire background to black
        graphics.fillRect(0, 0, GAMEBOARD_WIDTH, GAMEBOARD_WIDTH);
        snake.draw(graphics);
        // painting the entire image
        g.drawImage(img, 0, 0, null);
    }

    // Update will call on Paint(g)
    public void update(Graphics g) {
        paint(g);
    }

    // Repaint will call on Paint(g)
    public void repaint(Graphics g) {
        paint(g);
    }

    public void run() {
        // infinite loop
        for (;;) {
            snake.move();
            // drawing snake
            this.repaint();
            // Creating a time delay
            try {
                Thread.sleep(40);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public void keyTyped(KeyEvent keyEvent) {

    }

    public void keyPressed(KeyEvent keyEvent) {

        int keyCode = keyEvent.getKeyCode();

        if (!snake.isMoving()) {
            // this will allow the snake to start moving, but will disable LEFT for just the
            // 1st move
            if (matchKey(keyCode, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN)) {
                snake.setIsMoving(true);
            }
        }

        // setting up Key mapping so when the user presses UP,RIGHT,DOWN,LEFT. the Snake
        // will move accordingly
        if (matchKey(keyCode, KeyEvent.VK_UP)) {
            snake.setDirection(Direction.UP);
        }
        if (matchKey(keyCode, KeyEvent.VK_RIGHT)) {
            snake.setDirection(Direction.RIGHT);
        }
        if (matchKey(keyCode, KeyEvent.VK_DOWN)) {
            snake.setDirection(Direction.DOWN);
        }
        if (matchKey(keyCode, KeyEvent.VK_LEFT)) {
            snake.setDirection(Direction.LEFT);
        }

    }

    // return true if targetKey contains the provided keyCode
    private boolean matchKey(int keyCode, int... targetKey) {
        return Arrays.stream(targetKey).anyMatch(i -> i == keyCode);
    }

    public void keyReleased(KeyEvent keyEvent) {

    }
}

Snake.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
import java.util.LinkedList;

public class Snake {

    private final int sSize = 20, startX = 150, startY = 150;
    private final int BLOCK_WIDTH = 4;

    private LinkedList<Point2D.Float> sPoints;

    private boolean isMoving;

    private Direction direction;

    public Snake() {

        sPoints = new LinkedList<Point2D.Float>();

        isMoving = false;

        sPoints.add(new Point2D.Float(startX, startY));

        for (int i = 1; i < sSize; i++) {
            sPoints.add(new Point2D.Float(startX - i * BLOCK_WIDTH, startY));
        }
    }

    public void draw(Graphics g) {

        g.setColor(Color.white);
        for (Point2D p : sPoints) {
            g.fillRect((int) p.getX(), (int) p.getY(), BLOCK_WIDTH, BLOCK_WIDTH);
        }
    }

    public void move() {
        if (isMoving) {
            sPoints.removeLast();
            steer(sPoints.getFirst());
        }
    }

    private void steer(Point2D head) {

        Point2D.Float newHead = new Point2D.Float();
        switch (this.getDirection()) {
        case UP:
            newHead.setLocation(head.getX(), head.getY() - BLOCK_WIDTH);
            break;
        case DOWN:
            newHead.setLocation(head.getX(), head.getY() + BLOCK_WIDTH);
            break;
        case LEFT:
            newHead.setLocation(head.getX() - BLOCK_WIDTH, head.getY());
            break;
        case RIGHT:
            newHead.setLocation(head.getX() + BLOCK_WIDTH, head.getY());
            break;
        }

        this.sPoints.addFirst(newHead);

    }

    public int getX() {
        return (int) sPoints.get(0).getX();
    }

    public int getY() {
        return (int) sPoints.get(0).getY();
    }

    public boolean isMoving() {
        return isMoving;
    }

    public void setIsMoving(boolean b) {
        isMoving = b;
    }

    public Direction getDirection() {
        return direction;
    }

    public void setDirection(Direction d) {
        if (this.getDirection() == null) {
            this.direction = d;
        } else if (!this.getDirection().isOpposite(d)) {
            this.direction = d;
        }
    }
}

Direction.java

public enum Direction {
    UP(-1), DOWN(1), LEFT(-2), RIGHT(2);

    int vector;

    Direction(int i) {
        this.vector = i;
    }

    public boolean isOpposite(Direction d) {
        return this.vector + d.vector == 0;
    }

}
Mr. Brickowski
  • 1,134
  • 1
  • 8
  • 20
  • Hello thanks for the solution and the explanation, I dont really get it fully yet. since I started learning using applets and the graphics library yesterday. but ill get to it again. practice makes perfect. Really thanks for your time. Ill save your code but I am going to try and reprogram it from the start to understand clearly what is going on here. have a nice day – Demeteor Jun 25 '19 at 08:15
  • Also what I am going to attempt is to put a small space between each rect to make it look a bit more like the original – Demeteor Jun 25 '19 at 08:18
  • You are welcome. If you have something not clear, we are happy to help. This is a place to learn and share after all. – Mr. Brickowski Jun 26 '19 at 02:07
0

Snack.java

import java.awt.EventQueue;
import javax.swing.JFrame;

public class Snake extends JFrame {

    public Snake() {

        initUI();
    }

    private void initUI() {

        add(new Board());

        setResizable(false);
        pack();

        setTitle("Snake");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {
            JFrame ex = new Snake();
            ex.setVisible(true);
        });
    }
}

Board.java

enter image description here

enter image description here enter image description here enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Board extends JPanel implements ActionListener {

    private final int B_WIDTH = 300;
    private final int B_HEIGHT = 300;
    private final int DOT_SIZE = 10;
    private final int ALL_DOTS = 900;
    private final int RAND_POS = 29;
    private final int DELAY = 140;

    private final int x\[\] = new int\[ALL_DOTS\];
    private final int y\[\] = new int\[ALL_DOTS\];

    private int dots;
    private int apple_x;
    private int apple_y;

    private boolean leftDirection = false;
    private boolean rightDirection = true;
    private boolean upDirection = false;
    private boolean downDirection = false;
    private boolean inGame = true;

    private Timer timer;
    private Image ball;
    private Image apple;
    private Image head;

    public Board() {

        initBoard();
    }

    private void initBoard() {

        addKeyListener(new TAdapter());
        setBackground(Color.black);
        setFocusable(true);

        setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
        loadImages();
        initGame();
    }

    private void loadImages() {

        ImageIcon iid = new ImageIcon("src/resources/dot.png");
        ball = iid.getImage();

        ImageIcon iia = new ImageIcon("src/resources/apple.png");
        apple = iia.getImage();

        ImageIcon iih = new ImageIcon("src/resources/head.png");
        head = iih.getImage();
    }

    private void initGame() {

        dots = 3;

        for (int z = 0; z < dots; z++) {
            x\[z\] = 50 - z * 10;
            y\[z\] = 50;
        }

        locateApple();

        timer = new Timer(DELAY, this);
        timer.start();
    }

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

        doDrawing(g);
    }

    private void doDrawing(Graphics g) {

        if (inGame) {

            g.drawImage(apple, apple_x, apple_y, this);

            for (int z = 0; z < dots; z++) {
                if (z == 0) {
                    g.drawImage(head, x\[z\], y\[z\], this);
                } else {
                    g.drawImage(ball, x\[z\], y\[z\], this);
                }
            }

            Toolkit.getDefaultToolkit().sync();

        } else {

            gameOver(g);
        }        
    }

    private void gameOver(Graphics g) {

        String msg = "Game Over";
        Font small = new Font("Helvetica", Font.BOLD, 14);
        FontMetrics metr = getFontMetrics(small);

        g.setColor(Color.white);
        g.setFont(small);
        g.drawString(msg, (B_WIDTH - metr.stringWidth(msg)) / 2, B_HEIGHT / 2);
    }

    private void checkApple() {

        if ((x\[0\] == apple_x) && (y\[0\] == apple_y)) {

            dots++;
            locateApple();
        }
    }

    private void move() {

        for (int z = dots; z > 0; z--) {
            x\[z\] = x\[(z - 1)\];
            y\[z\] = y\[(z - 1)\];
        }

        if (leftDirection) {
            x\[0\] -= DOT_SIZE;
        }

        if (rightDirection) {
            x\[0\] += DOT_SIZE;
        }

        if (upDirection) {
            y\[0\] -= DOT_SIZE;
        }

        if (downDirection) {
            y\[0\] += DOT_SIZE;
        }
    }

    private void checkCollision() {

        for (int z = dots; z > 0; z--) {

            if ((z > 4) && (x\[0\] == x\[z\]) && (y\[0\] == y\[z\])) {
                inGame = false;
            }
        }

        if (y\[0\] >= B_HEIGHT) {
            inGame = false;
        }

        if (y\[0\] < 0) {
            inGame = false;
        }

        if (x\[0\] >= B_WIDTH) {
            inGame = false;
        }

        if (x\[0\] < 0) {
            inGame = false;
        }

        if (!inGame) {
            timer.stop();
        }
    }

    private void locateApple() {

        int r = (int) (Math.random() * RAND_POS);
        apple_x = ((r * DOT_SIZE));

        r = (int) (Math.random() * RAND_POS);
        apple_y = ((r * DOT_SIZE));
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (inGame) {

            checkApple();
            checkCollision();
            move();
        }

        repaint();
    }

    private class TAdapter extends KeyAdapter {

        @Override
        public void keyPressed(KeyEvent e) {

            int key = e.getKeyCode();

            if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
                leftDirection = true;
                upDirection = false;
                downDirection = false;
            }

            if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
                rightDirection = true;
                upDirection = false;
                downDirection = false;
            }

            if ((key == KeyEvent.VK_UP) && (!downDirection)) {
                upDirection = true;
                rightDirection = false;
                leftDirection = false;
            }

            if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
                downDirection = true;
                rightDirection = false;
                leftDirection = false;
            }
        }
    }
}

enter image description here

Govind Sharma
  • 127
  • 1
  • 4
  • It looks like a competently different approach than mine, how can this help me exactly? I cant tell by raw code alone – Demeteor Jun 24 '19 at 10:59
  • To make your code easier to run use you could use images that are publicly available. In fact you already loaded those images to the web, so all you need to do is use them: `ImageIcon iid = new ImageIcon(new URL("https://i.stack.imgur.com/KRER8.png")); ImageIcon iia = new ImageIcon(new URL("https://i.stack.imgur.com/S3LYA.png")); ImageIcon iih = new ImageIcon(new URL("https://i.stack.imgur.com/Kj1C3.png"));` – c0der Jun 25 '19 at 05:54
  • @c0der excuse me,but how I was rude here? I pointed out that the code he copy/pasted is a different approach that what I was having trouble with. why did you get offended by it? I never said it was a bad approach. I only said I cant see how this can help me with just row code and no explanation of what he posted. – Demeteor Jun 25 '19 at 08:06
  • I was not offended. The comment was not meant for me but for the poster. From my standpoint, if someone voluntarily spends time to help me, I first say thank you, before claiming that the help is no good. It might be just language or culture related differences. I am sorry if I misunderstood your comment. – c0der Jun 25 '19 at 10:53
  • @c0der all on good will my friend , no need to apologize, have a good day – Demeteor Jun 26 '19 at 07:53