Java: Processing problem with snake game


#1

I’m trying to make snake game. Everything works fine so far but the snake doesn’t eat the food. The program yields error ArrayIndexOutOfBoundsException which I think is because of eatFood(), because when I commented out the eatFood() in the draw(), the program works normally.

//20x20 
boolean kPressed = false;
boolean alive = true;
int len = 6;
Segment[] arr = new Segment[len];
Food[] fArr = new Food[1];


String popUp = "GAME OVER";
int score = len - 6;
String scoreTxt = "Score: " + score;

void keyPressed() {
  kPressed = true;
}

void move() {
  if (kPressed == true) {
    if (keyCode == UP) {
      arr[0].y -= 20;
    }
    if (keyCode == LEFT) {
      arr[0].x -= 20;
    }
    if (keyCode == RIGHT) {
      arr[0].x += 20;
    }
    if (keyCode == DOWN) {
      arr[0].y += 20;
    }
  }
}

void eatFood() { //<------------------ tell the snake to eat
  if ((arr[0].x == fArr[0].fX) & (arr[0].y == fArr[0].fY)) { //<------------------ check if snake head position is at food's position
    len += 1; //<------------------ add 1 segment
    fArr[0].fX = int(random(29))*20; //<------------------ replace the eaten food and  add new location for the next food spawn
    fArr[0].fY = int(random(29))*20;
  }
}

void popScore() {
  textSize(20);
  textAlign(CENTER, CENTER);
  text(scoreTxt, 300, 0);
}

void pop() {
  alive = false;
  textSize(50);
  textAlign(CENTER, CENTER);
  text(popUp, 300, 300);
}

void gameOver() {
  for (int u = 2; u < len; u++) {
    if (arr[0].x == arr[u].x & arr[0].y == arr[u].y) {
      pop();
    }
  }
  if (arr[0].x < 0 || arr[0].x + 20 > 600 || arr[0].y < 0 || arr[0].y > 600) {
    pop();
  }
}

void setup() {
  size(600, 600);
  frameRate(3);
  for (int i = 0; i < len; i++) {
    Segment seg = new Segment();
    seg.y += i*20;
    arr[i] = seg;
  }
  Food sF = new Food();
  fArr[0] = sF;
} 

void draw() {
  background(45);
  //starting food
  fArr[0].spawnFood(); //<------------------ first display the food object from setup(), after that display the ones generated by the eatFood()
  
  eatFood(); //<------------------ causes error
  
  if (alive == true) {
    move();
  }
  
  if (kPressed == true) {
    for (int i = len-1; i >= 1; i--) {
      arr[i-1].display();
      arr[len-1].display();
      arr[i].x = arr[i-1].x;
      arr[i].y = arr[i-1].y;
    }
  }
  else if (kPressed == false) {
    for (int i = 0; i < len; i++) {
      arr[i].display();
    }
  }
  popScore();
  gameOver();
}

class Segment {
  int x = 300;
  int y = 300;
  void display() {
    rect(x, y, 20, 20);
  }
}

class Food {
  int fX, fY;
  void spawnFood() {
    fX = 300;
    fY = 200;
    ellipse(fX+10, fY+10, 10, 10);
  }
} 

#2

You’re going to have to debug your code to find out exactly where your code behaves differently from what you expected.

You should be asking yourself question like: What line is the error happening? What is the value of every variable on that line?

One thing that jumps out to me is: why is fArr an array? You only ever seem to use a single index in that array. Why not just use a simple variable?


#3

Well, I actually intended to make multiple food spawns but just trying to test it out with 1. Anyway, I’m gonna try again. Thanks.


#4

I have modified your code. Pay attention to the changes. Few things still to do. Notice you need rectMode as center… it is easier

Watch for & in conditionals. That is not proper, you need && instead.

Check the reference for the dist() function. I provided an example in your code.

I disabled you array length increase. As it is, you are using an array to store your object. You need to “grow”/expand your array before you add an element. You need to use a Segment object. However, as it is, your segment object can only take one x and y position during construction which is not what you want. You need to fix that. To expand the rray, check append or concat in the reference. However, you probly need another structure like ArrayList. Never mind, just this will do for now.

Check for key pressed. It should execute only if the arrow keys are pressed.

Kf

final int RAD=10;
final int SQ_LEN=2*RAD;


boolean kPressed = false;
boolean alive = true;
int len = 6;
Segment[] arr = new Segment[len];
Food[] fArr = new Food[1];


String popUp = "GAME OVER";
int score = len - 6;
String scoreTxt = "Score: " + score;





void setup() {
  size(600, 600);
  frameRate(15);

  rectMode(CENTER);

  for (int i = 0; i < len; i++) {
    Segment seg = new Segment();
    seg.y += i*SQ_LEN;
    arr[i] = seg;
  }


  Food sF = new Food();
  fArr[0] = sF;
} 

void draw() {
  background(45);
  //starting food
  fArr[0].spawnFood(); //<------------------ first display the food object from setup(), after that display the ones generated by the eatFood()

  eatFood(); //<------------------ causes error


  for (int i = 0; i < len; i++) 
    arr[i].display();


  popScore();
  gameOver();
}

class Segment {
  int x = 300;
  int y = 300;
  void display() {
    rect(x, y, SQ_LEN, SQ_LEN);
  }
}

class Food {
  int fX, fY;
  void spawnFood() {
    fX = 300;
    fY = 200;
    ellipse(fX, fY, RAD, RAD);
  }
} 


void keyPressed() {
  kPressed = true;

  if (keyCode == UP) {
    arr[0].y -= SQ_LEN;
  }
  if (keyCode == LEFT) {
    arr[0].x -= SQ_LEN;
  }
  if (keyCode == RIGHT) {
    arr[0].x += SQ_LEN;
  }
  if (keyCode == DOWN) {
    arr[0].y += SQ_LEN;
  }

  for (int i = len-1; i >= 1; i--) {  //REMARK: Begins at 1
    arr[i].x = arr[i-1].x;
    arr[i].y = arr[i-1].y;
  }
}

void keyReleased() {
  kPressed = false;
}



void eatFood() { //<------------------ tell the snake to eat
  if ((arr[0].x == fArr[0].fX) && (arr[0].y == fArr[0].fY)) {   //HERE use better if(dist(arr[0].x,arr[0].y,fArr[0].fX,fArr[0].fY)>RAD)  ----> true when they intercept
    //len += 1; //<------------------ FIX
    fArr[0].fX = int(random(29))*SQ_LEN; //<------------------ replace the eaten food and  add new location for the next food spawn
    fArr[0].fY = int(random(29))*SQ_LEN;
  }
}

void popScore() {
  textSize(20);
  textAlign(CENTER, CENTER);
  text(scoreTxt, 300, 0);
}

void pop() {
  alive = false;
  textSize(50);
  textAlign(CENTER, CENTER);
  text(popUp, 300, 300);
}

void gameOver() {
  for (int u = 2; u < len; u++) {
    if (arr[0].x == arr[u].x &  arr[0].y == arr[u].y) {   //<------------------ FIX  This conditiona is wrong: & is not the same as &&. The latter is correct for java
      pop();
    }
  }
  if (arr[0].x < 0 || arr[0].x + 20 > 600 || arr[0].y < 0 || arr[0].y > 600) {
    pop();
  }
}