I am trying to make a snake program

The code I currently have looks like this

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;

public class SnakeG extends JPanel implements KeyListener, Runnable{

	private Vector<Point> snake = new Vector<Point> (5,2);
	
	private Vector<Rectangle> snakeRectangle = new Vector<Rectangle> (5,2);
	
	public void startGraphics (){
		
		this.addKeyListener(this);
		Thread thread = new Thread (this);
		
		repaint();
		grabFocus();
		snake.add (new Point (250,250));
		snake.add(new Point (250,240));
		snake.add(new Point (250,230));
		addBall();
		thread.start();
	}
	
	private void addBall() {
		// TODO Auto-generated method stub
		
	}

	
	
	public void paintComponent (Graphics g){
		//TODO GRAPHICS AREA
		super.paintComponent (g);
		
		for (Point x : snake){
			g.fillOval((int)x.getX(),(int)x.getY(),10, 10);
			
		}
	}

	
	
	
	private boolean pressed = false;
	private boolean up,down,left,right;
	@Override
	public void keyPressed(KeyEvent e) {
		System.out.println ("KeyListener");
		int key = e.getKeyCode();
		
		up = false;
		down = false;
		left = false;
		right = false;
		if (key == KeyEvent.VK_UP && pressed == false){
			up = true;
		}
		else if (key == KeyEvent.VK_DOWN && pressed == false){
			down = true;
		}
		else if (key == KeyEvent.VK_LEFT && pressed == false){
			left = true;
		}
		else if (key == KeyEvent.VK_RIGHT && pressed == false){
			right = true;
		}
		pressed = true;
	}

	@Override
	public void keyReleased(KeyEvent e) {
		pressed = false;
	}

	@Override
	public void keyTyped(KeyEvent e){}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println ("Started Thread");
		while (true){
			if (up == true){
				for (int i = snake.size(); i < 0; i--){
					System.out.println ("Entered loop");
					if (i == 0){
						snake.firstElement().y -= 10;
					}
					else {
						snake.elementAt(i).y = snake.elementAt(i-1).y;
					}
					snake.elementAt(i);
				}

			}
			else if (down == true){
				

			}
			else if (left == true){
				for (int i = snake.size(); i < 0; i--){
					if (i == 0){
						snake.firstElement().x -= 10;
					}
					else {
						snake.elementAt(i).x = snake.elementAt(i-1).x;
					}
				}

			}
			else if (right == true){
				

			}
			
			repaint();
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}

The run method has my animations in it. The snake however does not more. I put the printed just inside the for loop that will reassign the values and will make the snake animate, but it does not print. There are no errors. What is the problem.

Thanks for the help.

Recommended Answers

All 25 Replies

I'm not sure (and i'm against to use Thread.sleep(int)) in Swing code, anyway in your previous thread was suggested somenthig about javax.swing.Timer

1/ look for myTimer.restart(); in your case (KeyListener)

2/ look for KeyBinding, is more confortable than KeyListener

3/ for inspiration, very simple example

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class AnimationBackground {

    public AnimationBackground() {
        Random random = new Random();
        JFrame frame = new JFrame("Animation Background");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        final MyJPanel panel = new MyJPanel();
        panel.setBackground(Color.BLACK);
        for (int i = 0; i < 50; i++) {
            Star star = new Star(new Point(random.nextInt(490), random.nextInt(490)));
            star.setColor(new Color(100 + random.nextInt(155), 100 + random.nextInt(155), 100 + random.nextInt(155)));
            star.setxIncr(-3 + random.nextInt(7));
            star.setyIncr(-3 + random.nextInt(7));
            panel.add(star);
        }
        panel.setLayout(new GridLayout(10, 1));
        JLabel label = new JLabel("This is a Starry background.", JLabel.CENTER);
        label.setForeground(Color.WHITE);
        panel.add(label);
        JPanel stopPanel = new JPanel();
        stopPanel.setOpaque(false);
        stopPanel.add(new JButton(new AbstractAction("Stop this madness!!") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                panel.stopAnimation();
            }
        }));
        panel.add(stopPanel);
        JPanel startPanel = new JPanel();
        startPanel.setOpaque(false);
        startPanel.add(new JButton(new AbstractAction("Start moving...") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                panel.startAnimation();
            }
        }));
        panel.add(startPanel);
        frame.add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                AnimationBackground animationBackground = new AnimationBackground();
            }
        });
    }

    class Star extends Polygon {

        private static final long serialVersionUID = 1L;
        private Point location = null;
        private Color color = Color.YELLOW;
        private int xIncr, yIncr;
        static final int WIDTH = 500, HEIGHT = 500;

        Star(Point location) {
            int x = location.x;
            int y = location.y;
            this.location = location;
            this.addPoint(x, y + 8);
            this.addPoint(x + 8, y + 8);
            this.addPoint(x + 11, y);
            this.addPoint(x + 14, y + 8);
            this.addPoint(x + 22, y + 8);
            this.addPoint(x + 17, y + 12);
            this.addPoint(x + 21, y + 20);
            this.addPoint(x + 11, y + 14);
            this.addPoint(x + 3, y + 20);
            this.addPoint(x + 6, y + 12);
        }

        public void setColor(Color color) {
            this.color = color;
        }

        public void move() {
            if (location.x < 0 || location.x > WIDTH) {
                xIncr = -xIncr;
            }
            if (location.y < 0 || location.y > WIDTH) {
                yIncr = -yIncr;
            }
            translate(xIncr, yIncr);
            location.setLocation(location.x + xIncr, location.y + yIncr);
        }

        public void setxIncr(int xIncr) {
            this.xIncr = xIncr;
        }

        public void setyIncr(int yIncr) {
            this.yIncr = yIncr;
        }

        public Color getColor() {
            return color;
        }
    }

    class MyJPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        private ArrayList<Star> stars = new ArrayList<Star>();
        private Timer timer = new Timer(20, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (Star star : stars) {
                    star.move();
                }
                repaint();
            }
        });

        public void stopAnimation() {
            if (timer.isRunning()) {
                timer.stop();
            }
        }

        public void startAnimation() {
            if (!timer.isRunning()) {
                timer.start();
            }
        }

        @Override
        public void addNotify() {
            super.addNotify();
            timer.start();
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            timer.stop();
        }

        MyJPanel() {
            this.setPreferredSize(new Dimension(512, 512));
        }

        public void add(Star star) {
            stars.add(star);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            for (Star star : stars) {
                g.setColor(star.getColor());
                g.fillPolygon(star);
            }
        }
    }
}

4/ my quesion are you try to code for Android or iOS, if yes then forgot for using Thread.sleep(int) for Graphics on those lowLevel GPU

5/ output from Runnable + Thread to the GUI must be wrapped to the invokelater or invokeAndWait (not your case)

You need more printlns to show the values of the booleans you are using to control the movements.
You need to see where the execution flow is going.

I added this print statement right after the while (true){ line and the booleans are correct. it is the for loop

Print statement

System.out.println ("Up: " + up + "\tDown: " + down + "\tLeft: " + left + "\tRight: " + right);

And what was the results?
Was up == true?
Add another println after the if(up) statement to show the values that control the for loop.

Whenever I clicked one of the arrow keys, the corresponding boolean got set to true. Then it entered the if statement, but it did not enter the loop.

but it did not enter the loop.

What can keep a for loop from starting execution?

Two comments:
1. if (someCondition== true) is a bit silly. What's wrong with if (someCondition)

2. for (int i = somePositiveIntegerValue; i < 0; i--){... // eg your line 86
How many times will this loop execute (when will i<0 be true)?

Thanks. I fixed the problem. a quick other question. How would I be able to update a vector of rectangles x and y coordinates according to a vector of points?

Do the points correspond 1:1 with the rectangles? If so just loop thru the rectangles updating each one's coords with the corresponding point's x and y.

for (int i = 0; i <= vectOfRects.size(); i++) {
  vectOfRects.get(i).setLocation(vectOfPoints.get[i]);
}

Or have I missed the point?

that should work. Now my thread stopped working again. I have it in a while loop and when 2 circles collide it should set to false to stop the animation and prevent the snake from moving. The problem is the thread only executes once.

Here is the thread.

int i = 0;
	private boolean runThread = true;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println ("Started Thread");
		while (runThread){
			System.out.println ("Up: " + up + "\tDown: " + down + "\tLeft: " + left + "\tRight: " + right);
			
			//moving the snake
			if (up == true){
				System.out.println ("entered if");
				for (int i = snake.size() - 1; i > -1; i--){
					System.out.println ("Entered loop");
					if (i == 0){
						snake.firstElement().y -= 10;
						
					}
					else {
						snake.elementAt(i).y = snake.elementAt(i - 1).y;
					}
				}

			}
			else if (down == true){
				for (int i = snake.size() - 1; i > -1; i--){
					System.out.println ("Entered loop");
					if (i == 0){
						snake.firstElement().y += 10;
						
					}
					else {
						snake.elementAt(i).y = snake.elementAt(i - 1).y;
					}
				}

			}
			else if (left == true){
				for (int i = snake.size() - 1; i > -1; i--){
					System.out.println ("Entered loop");
					if (i == 0){
						snake.firstElement().x -= 10;
						
					}
					else {
						snake.elementAt(i).x = snake.elementAt(i - 1).x;
					}
				}

			}
			else if (right == true){
				for (int i = snake.size() - 1; i > -1; i--){
					System.out.println ("Entered loop");
					if (i == 0){
						snake.firstElement().x += 10;
						
					}
					else {
						snake.elementAt(i).x = snake.elementAt(i - 1).x;
					}
					
				}

			}
			System.out.println ("At start of turning");
			//Turning the snake
			if (wasPressed == true){
				if (previous.equals ("up")){
					for (int i = snake.size() - 1; i > 0; i--){
						System.out.println ("Entered loop");
						snake.elementAt(i).x = snake.elementAt(i - 1).x;
					}
				}
				else if (previous.equals("down")){
					for (int i = snake.size() - 1; i > 0; i--){
						System.out.println ("Entered loop");
						snake.elementAt(i).x = snake.elementAt(i - 1).x;
					}
				}
				else if (previous.equals("left")){
					for (int i = snake.size() - 1; i > 0; i--){
						System.out.println ("Entered loop");
						snake.elementAt(i).y = snake.elementAt(i - 1).y;
					}
				}
				else if (previous.equals("right")){
					for (int i = snake.size() - 1; i > 0; i--){
						System.out.println ("Entered loop");
						snake.elementAt(i).y = snake.elementAt(i - 1).y;
					}
				}
			}
			updateRect();
			collisionDetect();
			
			i++;
			System.out.println ("At adding ball");
			if (i % 20 == 0 && previous!= null){
				addBall();
			}
			
			
			repaint();
			System.out.println ("before sleep");
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

also I have this statement to check for collision detection

for (int i = 0; i < snake.size(); i++){
			for (int z = 0; z < snake.size(); z++){
				System.out.println("Z: " + z + " I " + i);
				if (z == i){
					System.out.println("z = i accessed");
				}
				else {
					if (snakeRectangle.elementAt(i).contains((snakeRectangle.elementAt(z).getX()), (snakeRectangle.elementAt(z).getY()))){
						System.out.println("2 elements are the same");
						runThread = false;
					}
				}
			}
		}

it loops through the snake twice and gets the index of the circle, and then it uses the index of the circle to see if the rectangles are on top of each other. Since my thread isn't currently working I am wondering if this would work. Also would there be a more efficient way of doing the same action?

Thanks for the help.

The problem is the thread only executes once

Have you tried debugging your code by adding printlns to show the variables that control the looping in the run() method?
Where is the runThread variable's value changed? How/where does the loop exit?

The runThreads variable is changed here

if (snakeRectangle.elementAt(i).contains((snakeRectangle.elementAt(z).getX()), (snakeRectangle.elementAt(z).getY()))){
						System.out.println("2 elements are the same");
						runThread = false;
					}

line 10 of the collision detection code.

I added a println right before the thread.sleep and it was still true.

This nested if statement is not activated, because first there is only one circle, so it goes into the if statement before which sates that if the same element is being delt with then do nothing, otherwise it would always stop.

This nested if statement is not activated, because first there is only one circle, so it goes into the if statement before which sates that if the same element is being delt with then do nothing, otherwise it would always stop.

That sounds like a logic problem.
You need to find out why that is happening and change your logic to prevent it.


If you want help with your logic you will have to post your code.

That sounds like a logic problem.
You need to find out why that is happening and change your logic to prevent it.

I know the logic is correct, because I put the 2 elements are the same println in before the change. That line is never printed.

it prints out z = i accessed, which is what it is supposed to print out when they are the same.

I found my error. When I have thread.sleep. the boolean value changes for some reason. All I have between the first print and the second print in the thread is this

System.out.println ("before sleep. runThread: " + runThread);
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println ("after sleep. runThread: " + runThread);

The first one output is true and the second one is false. why is this happening. Does the Thread.sleep change the condition of the boolean?

The first one output is true and the second one is false. why is this happening.

Sounds like you need some more debugging printlns added to your code.
Add one right after where the boolean variable's value is changed from true to false.

I know the logic is correct

If the logic for your program was correct, then this thread wouldn't be here.

If the logic for your program was correct, then this thread wouldn't be here.

Why are you against threads in swing applications? Also why does my boolean change after the thread.sleep(200);

why does my boolean change after the thread.sleep(200);

I bet it changes DURING the sleep, not after it.
Did you add the println I suggested where the boolean value was being changed?
Did it print out?

I use Threads all the time.

I put print lines like this

println - true
sleep
println - false

it does change during the sleep, but why?

it does change during the sleep, but why?

Because the statement that sets it false is executed.
Why(under what circumstances) does the code set it false?

I don't understand why this printed:
println - true

If you put the println next to the statement that sets the boolean variable false, why did that print out?

Is there more than one runThread variable and one is masking the other?

I only have one thread. The statement that sets it to false is not printed out.

the

println - true
sleep
println - false

was what it printed right before and after the Thread.sleep. it had nothing to do with the code that changes the boolean.

it had nothing to do with the code that changes the boolean.

BUT that is the MOST important part.
Who/what/where changes the value of the boolean???


Is there more than one runThread variable and one is masking the other?

For example do you create more than one instance of the class containing the boolean?
Then each instance has its own value.

There is only one thread. Even if I comment out the only line that changes the boolean it still changes to false.

My question was about the boolean variable not about a Thread.

Is there more than one runThread variable and one is masking the other?

For example do you create more than one instance of the class containing the boolean?
Then each instance has its own value.

the boolean it still changes to false.

This is very hard to believe. Can you post the code to demonstrate this happening.

I found my error. in the paintComponent method instead of using runThread == false in my if statement I put runThread = false

So much trouble for a missing equal sign. I guess I will need to wach out for that next time XD

Thanks for all the help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.