3 Replies - 6410 Views - Last Post: 07 June 2012 - 07:12 AM Rate Topic: -----

#1 jc310xc  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 15
  • Joined: 14-January 11

Snake in Java

Posted 31 May 2012 - 09:59 AM

Hi all,

I'm currently working on a basic snake game in java. I've got it all pretty much done, save for one problem.

The way my snake works is as follows: the "head" of the snake is the first snakeNode in line, and the next segment of its body is pointed to by the head. The second segment points to the third, etc. When you get to the end, the last segment points to null, and that's how you know that you're at the end of the snake. When the snake eats a pellet, a segment is simply added on at the front and the bottom is not updated.

As for collision detection, i use a 2d array to determine whether the snake has hit its own body parts or the walls.

Here's my problem:

As my snake starts to grow larger, it starts to leave spots behind it where it is still marked as an occupied square. I've looked all around for the problem, but there seems to be no pattern as to why it leaves behind these spots. In the code, I color any spaces that the snake is considered to be "occupying" as green, so as to make identifying these spots easier.

Here's the code:

snakeMain.java

package snake;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.*;

@SuppressWarnings("serial")
public class snakeMain extends JFrame{
	Image DBImage;
	Graphics dbg;
	
	ImageIcon bg; 
	
	int screenWidth = 805;
	int screenHeight = 598;
	
	int keyPressed = 0;
	static int direction = 2;
	static int lastDirection = 2;
	static int nextDirection = 2;
	
	static snakeNode firstNode;
	static snakeNode curNode;
	static snakeNode checkNode;
	static int snakeLength = 100;
	
	static boolean needNewPellet = true;
	static int pelletX = 1000;
	static int pelletY = 1000;
	
	static int[][] board = new int[80][59];
	
	static boolean gameOver = false;
	
	Dimension screenDimension = new Dimension(screenWidth,screenHeight);
	
	public snakeMain(){
		this.setTitle("Snake");
		this.setSize(screenDimension);
		this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.addKeyListener(new keyListener());
        
        firstNode = new snakeNode(2,24,0,0);
        for(int i = 0; i < board.length; i++){
        	for(int j = 0; j < board[i].length; j++){
        		board[i][j] = 0;
        	}
        }
	}
    	
        
	public static void main(String[] args){
		@SuppressWarnings("unused")
		snakeMain main = new snakeMain();
		
		Random r = new Random();
		
		//game loop
		while(!gameOver){
			if(direction == 1){
				if(firstNode.getArrY() == 0){
					//gameOver = true;
				}else if(board[firstNode.getArrX()][firstNode.getArrY()-1] == 1){
					gameOver = true;
				}else{
					firstNode = new snakeNode(firstNode.getX(),
											  firstNode.getY()-10,
											  firstNode.getArrX(),
											  firstNode.getArrY()-1,
											  firstNode);
					board[firstNode.getArrX()][firstNode.getArrY()] = 1;
					lastDirection = 1;
				}
			}else if(direction == 2){
				if(firstNode.getX() >= 792){
				//	gameOver = true;
				}else if(board[firstNode.getArrX()+1][firstNode.getArrY()] == 1){
					gameOver = true;
				}else{
					firstNode = new snakeNode(firstNode.getX() + 10,
											  firstNode.getY(),
											  firstNode.getArrX()+1,
											  firstNode.getArrY(),
											  firstNode);

					board[firstNode.getArrX()][firstNode.getArrY()] = 1;
					lastDirection = 2;
				}
			}else if(direction == 3){
				if(firstNode.getY() >= 575){
					//gameOver = true;
				}else if(board[firstNode.getArrX()][firstNode.getArrY()+1] == 1){
					gameOver = true;
				}else{
					firstNode = new snakeNode(firstNode.getX(),
											  firstNode.getY()+10,
											  firstNode.getArrX(),
											  firstNode.getArrY()+1,
											  firstNode);

					board[firstNode.getArrX()][firstNode.getArrY()] = 1;
					lastDirection = 3;
				}
			}else if(direction == 4){
				if(firstNode.getX() <= 11){
					//gameOver = true;
				}else if(board[firstNode.getArrX()-1][firstNode.getArrY()] == 1){
					gameOver = true;
				}else{
					firstNode = new snakeNode(firstNode.getX()-10,
											  firstNode.getY(),
											  firstNode.getArrX()-1,
											  firstNode.getArrY(),
											  firstNode);

					board[firstNode.getArrX()][firstNode.getArrY()] = 1;
					lastDirection = 4;
				}
			}
			
			
			
			int count = 1;
			curNode = firstNode;
			while(count < snakeLength){
				if(curNode.getNext() != null){
					curNode = curNode.getNext();
				}
				count++;
			}
			checkNode = curNode.getNext();
			if(snakeLength > 2){
				board[checkNode.getArrX()][checkNode.getArrY()] = 0;
			}
			curNode.setNext(null);
			
			
			
			
			direction = nextDirection;
			nextDirection = direction;
			
			while(needNewPellet){
				pelletX = 0;
				int xPos = 0;
				int yPos = 0;
				while(pelletX % 10 % 10 != 2 || pelletX <= 11){
					pelletX = r.nextInt(793);
					xPos = (pelletX-2)/10;
				}
				
				pelletY = 0;
				while(pelletY % 10 % 10 != 4 || pelletY <= 33){
					pelletY = r.nextInt(575);
					yPos = (pelletY-4)/10;
				}
				
				if(board[xPos][yPos] == 1){
					needNewPellet = true;
				}else{
					needNewPellet = false;
				}
			}
			
			if(firstNode.getX() == pelletX && firstNode.getY() == pelletY){
				snakeLength++;
				needNewPellet = true;
			}
			
			try{
				Thread.sleep(25);
			}catch(Exception e){}
		}

	}
	
	public void paint(Graphics g){
		DBImage = createImage(getWidth(), getHeight());
        dbg = DBImage.getGraphics();
        draw(dbg);
        g.drawImage(DBImage, 0, 0, this);
	}
	
	public void draw(Graphics g){
		g.setColor(Color.GREEN);
		for(int i = 0; i < board.length; i++){
        	for(int j = 0; j < board[i].length; j++){
        		if(board[i][j] == 1){
        			g.fillRect((i*10)+2, (j*10)+24, 10, 10);
        		}
        	}
        }
		g.setColor(Color.BLACK);
		int count = 0;
		curNode = firstNode;
		while(count < snakeLength){
			g.fillOval(curNode.getX(), curNode.getY(), 10, 10);
			if(curNode.getNext() != null){
				curNode = curNode.getNext();
			}
			count++;
		}
		g.setColor(Color.RED);
		g.fillOval(pelletX,pelletY,10,10);
		repaint();
	}
	
	class keyListener extends KeyAdapter{
		public void keyPressed(KeyEvent e){
			keyPressed = e.getKeyCode();
			if(keyPressed == e.VK_UP){
				if(direction == 3){
				}else if(lastDirection == 3){
					nextDirection = 1;
				}else{
					nextDirection = 1;
				}
			}else if(keyPressed == e.VK_RIGHT){
				if(direction == 4){}
				else if(lastDirection == 4){
					nextDirection = 2;
				}else{
					nextDirection = 2;
				}
			}else if(keyPressed == e.VK_DOWN){
				if(direction == 1){}
				else if(lastDirection == 1){
					nextDirection = 3;
				}else{
					nextDirection = 3;
				}
			}else if(keyPressed == e.VK_LEFT){
				if(direction == 2){}
				else if(lastDirection == 2){
					nextDirection = 4;
				}else{
					nextDirection = 4;
				}
			}
			
			repaint();
		}
		
		public void keyReleased(KeyEvent e){
		}
	}
}


snakeNode.java:

package snake;

public class snakeNode {
	int snakeX;
	int snakeY;
	snakeNode nextNode;
	int arrX;
	int arrY;
	
	public snakeNode(int snakeX, int snakeY, int arrX, int arrY, snakeNode nextNode){
		this.snakeX = snakeX;
		this.snakeY = snakeY;
		this.nextNode = nextNode;
		this.arrX = arrX;
		this.arrY = arrY;
	}
	
	public snakeNode(int snakeX, int snakeY, int arrX, int arrY){
		this.snakeX = snakeX;
		this.snakeY = snakeY;
		nextNode = null;
		this.arrX = arrX;
		this.arrY = arrY;
	}
	
	public boolean equals(snakeNode node){
		if(this.getX() == node.getX() && this.getY() == node.getY()){
			return true;
		}else{
			return false;
		}
	}
	
	public snakeNode clone(){
		return new snakeNode(getX(), getY(), getArrX(), getArrY());
	}
	
	public int getArrX(){
		return arrX;
	}
	
	public int getArrY(){
		return arrY;
	}
	
	public void setArrX(int arrX){
		this.arrX = arrX;
	}
	
	public void setArrY(int arrY){
		this.arrY = arrY;
	}

	public int getX() {
		return snakeX;
	}

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

	public int getY() {
		return snakeY;
	}

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

	public snakeNode getNext() {
		return nextNode;
	}

	public void setNext(snakeNode nextNode) {
		this.nextNode = nextNode;
	}
}


Any ideas or suggestions are greatly appreciated. Also, I'm wondering, is this the most efficient way of doing this?
As my snake begins to grow larger, the game starts to flicker. I suspect it's because my drawing algorithm is very
inefficient.

Thanks in advance,

-jc-

Is This A Good Question/Topic? 0
  • +

Replies To: Snake in Java

#2 anonymous26  Icon User is offline

  • D.I.C Lover

Reputation: 1
  • View blog
  • Posts: 3,638
  • Joined: 26-November 10

Re: Snake in Java

Posted 02 June 2012 - 08:16 PM

I wrote a game similar to this for my demo in 3D where each node of the snake was able to move around the world freely.

Here are some things that you need to think about for your game:

1. What you have described is a linked list for creating your snake, this is a back idea since each new node for the snake chews up more memory because you are recreating instances of the same object. What you should be doing is referring to a single instance of the object that makes up the snakes segments, since they are all identical, and drawing that single instance across all locations that the snake occupies in the world. I'll leave you to work out how you are going to approach that one.

2. The reason why nodes for the snake's body remain is place is because you are not updating the locations of those nodes. In addition to this, maybe you are not destroying nodes appropriately.

3. The reason for your slowdown as the snakes grow very long is because of what I said in the first point as well as memory fragmentation issues kicking for the life of the game as you create and destroy nodes.

Rethink your approach based on these points.
Was This Post Helpful? 1
  • +
  • -

#3 jc310xc  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 15
  • Joined: 14-January 11

Re: Snake in Java

Posted 07 June 2012 - 07:07 AM

I figured the linked list would cause lagging issues as the snake grew longer, but I wasn't sure how long that would take for the snake's length to become a problem.

In order to work around both problems I'm having, would it be easier to drop the linked list altogether, and use the 2D array I'm already working with to draw and track the snake? My first thought was to use a variable to track the coordinates of the end of the snake, and at each tick of the game to search the four cardinal directions from the endpoint to find the next-to-last segment, but then I realized an issue would come up if there were multiple fragments in at least two of the four directions.

How else would I track the snake, if not a linked list?

Thanks again,

-JC-
Was This Post Helpful? 0
  • +
  • -

#4 DarenR  Icon User is offline

  • D.I.C Lover

Reputation: 483
  • View blog
  • Posts: 3,242
  • Joined: 12-January 10

Re: Snake in Java

Posted 07 June 2012 - 07:12 AM

here is my snake in c# which is close to java-- maybe this will help you fix your bugs.


my snake
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1