The Centipedes Game

Hello all,

For school i have to make a kind of snake game. The game has the following rules:

Rules of game:

  • 1 player needs to make as many points before all particles of body dissapeared.
  • game should be a field of 16 by 8 blocks.
  • 20 bananas are hidden in the game and are invisible. when snake eats them player gains 10 points.
  • game has 10 animals on random location in the field. if snake goes over them it loses a part of the body.
  • when only the head is left it should be Game Over and show score.
  • no classes in the coding.

I have made a start but it is difficult to get out. I have the feeling that my base is not good either. Hopefully someone can help me on my way… Here below is the code i made so far.

int rups, fruit, score1 = 0, score2 = 0, scherm = 0, i;
int radius = 30, richtingX = 1, richtingY = 0;
float rupsX = 30, rupsY = 40;
float snelheid = 2.5;
boolean bananen = false;
boolean kersen = false;


void setup() {
  size(1000, 800);
  smooth();
  ellipseMode(RADIUS);
}

void draw() {
  background(250); 

  if (scherm == 0) {
    scherm();
  } else if (scherm == 1) {
    scherm1();
  } else if (scherm == 2) { 
    scherm2();
  }
}


void fruit() {

  //  if (rupsX > 170 && rupsX <230 && rupsY > 480 && rupsY < 520) {  
  // for loop maken for fruit
bananen = !bananen;

  if (rupsX > 193 && rupsX <206 && rupsY > 493 && rupsY < 506) {  
    fill(150, 50, 11);
    noStroke();
    //kers 5 punten
    ellipse(200, 500, radius, radius);
    textAlign(CENTER);
    //    score1++;
    text("Score = "+score1, 450, 40);
    score1++;
    text("Score = "+score1, 450, 40);
  } else if (rupsX > 684 && rupsX < 710 && rupsY > 184 && rupsY < 210) {
    fill(255, 250, 2);
    noStroke();
    //banaan 10 punten
    ellipse(700, 200, radius, radius);
    score1++;

  }

}

void keyPressed() {
  if (key == CODED) {
    if (keyCode == LEFT) {
      richtingX = -1;
      richtingY = 0;
    } else if (keyCode == RIGHT){
      richtingX = 1;
      richtingY = 0;
    } else if (keyCode == DOWN){
      richtingX = 0;
      richtingY = 1;
    } else if (keyCode == UP){
     richtingX = 0;
     richtingY = -1;
    }
  }
}

void rups() {

  //bepaling x,y rups
  rupsX = rupsX + snelheid * richtingX; 
  rupsY = rupsY + snelheid * richtingY;

  //rups mag niet uit het spel kruipen
  if (rupsX > width-radius) {
    richtingX = richtingX * -1;
  } else if (rupsX < 30) {
    richtingX = richtingX * -1;
  } else if (rupsY > height-radius) {
    richtingY = richtingY * -1;
  } else if (rupsY < 30) {
    richtingY = richtingY * -1;
  }

  fill(50, 168, 111);
  noStroke();
  ellipse(rupsX, rupsY, radius, radius);
  fill(250);
  ellipse(rupsX+10, rupsY-5, 5, 2);
  ellipse(rupsX-10, rupsY-5, 2, 3);
  fill(50, 168, 111);
  

}

void scherm() {
  fill(0); 
  textAlign(CENTER);
  textSize(30);
  text("THE CENTIPEDES GAME", width/2, height/2-195);

  rectMode(CENTER);
  fill(0); 
  rect(width/2, height/2-100, 300, 30);
  fill(255); 
  textAlign(CENTER);
  textSize(20);
  text("1 SPELER", width/2, height/2-95);

  fill(0); 
  rect(width/2, height/2, 300, 30);
  fill(255); 
  textAlign(CENTER);
  text("20 BANANEN", width/2, height/2+5);

  fill(0); 
  rect(width/2, height/2+100, 300, 30);
  fill(255); 
  textAlign(CENTER);
  text("16 x 8 SPEELVELD", width/2, height/2+105);


  fill(0); 
  rect(width/2, height/2+200, 200, 30);
  fill(255); 
  textAlign(CENTER);
  text("START SPEL", width/2, height/2+205);
  if (mouseX > width/2-100 && mouseX < width/2+100 && mouseY > height/2+190 && mouseY < height/2+220) {
    fill(80, 20, 20); 
    rect(width/2, height/2+200, 200, 30);
    fill(255); 
    textAlign(CENTER);
    text("START SPEL", width/2, height/2+205);
  }
}

void mousePressed() {
  if (mouseX > width/2-100 && mouseX < width/2+100 && mouseY > height/2+190 && mouseY < height/2+220) {
    scherm = 1;
  }
}

void scherm1() {
  textSize(12);
  fruit();
  rups();
  println(richtingX, richtingY, rupsX, rupsY);
  score();
  //score eenmalig maken
}


void scherm2() {
// GAME OVER
}

void score() {
 
  textAlign(CENTER);
  fill(50, 168, 111);
  text("SPELER 1", 380, 40);

  text("Score = "+score1, 450, 40);

}

Hi @GijsfromAmsterdam ,

Welcome to the forum! :wink:

Can you explain why they specify that? Using classes and object oriented programming is the most obvious way to code this king of game!

Thanks Joseph!

cause this is a part of structured programming still. That is also one of the reasons i find it difficult because most examples of simular games are indeed with classes…

But that’s the whole point of using classes! :thinking:

How are you going to store your 20 bananas, 16 by 8 blocks, 10 animals, points?

Of course you can use separate variables and arrays but this is going to be annoying.

Let’s suppose you want to store an animal. Basically it has a location (the row and the column numbers of its location on the grid) and possibly a type since there can be different animals. Then you would do :

int animalCol = 5;
int animalRow = 2;
int animalType = 1; // Let's suppose that 1 is a frog for example

That’s fine when you want to draw a single animal (you could improve it still) but what if you have 10 animals?

Naively :

// Animal 1
int animalCol1 = 5;
int animalRow1 = 2;
int animalType1 = 1;

// Animal 2
int animalCol2 = 1;
int animalRow2 = 3;
int animalType2 = 0;

// ...

// Animal 10
int animalCol10 = 4;
int animalRow10 = 2;
int animalType10 = 2;

As you can see this makes a lot of variables and it’s impossible to read!

So you say : let’s use arrays!

int[] animalCols = {0, 2, 1, /*...*/, 2, 3, 1};
int[] animalRows = {5, 2, 3, /*...*/, 1, 4, 6};
int[] animalTypes = {1, 0, 2, /*...*/, 2, 2, 0};

This is an improvement because now your data is only accessible by three different variables and can then be accessible parametrically :

for (int i = 0; i < animalCols.length; i++) {
  circle(animalCols[i] * cellSize, animalRows[i] * cellSize, cellSize);
}

But this is still strange because to access one coherent piece of data that is an animal, you need to use three sources that are the three arrays. And they can be different in size which can lead to bugs…

That’s why classes are really useful because they pack data associated to an instance of that class. So it’s much more logical to refer as an Animal as an object that contains different properties and behaviors (as methods).

For me it makes no sense not to use classes for this exercise :yum:

1 Like

I understand but unfortunately thats a rule… for me it also makes no sense tho.

How about the following code that i found online, is it possible to addapt this code maybe? Cause now the snake start with 1 part and when getting ‘fruits’ it gains a body part. Lets say we want this the opposite.

ArrayList<Integer> x = new ArrayList<Integer>(), y = new ArrayList<Integer>();
int w=30, h=30, blocks=20, direction=2, foodx=15, foody=15, speed = 8, fc1 = 255, fc2 = 255, fc3 = 255; 
int[]x_direction={0, 0, 1, -1}, y_direction={1, -1, 0, 0}; //direction for x and y
boolean gameover=false;

void setup() { 
  size(600, 600); 
  x.add(0); //snake start position
  y.add(15);
}   
void draw() {  
  background(0);
  fill(0, 255, 0); //snake color green
  for (int i = 0; i < x.size(); i++) rect(x.get(i)*blocks, y.get(i)*blocks, blocks, blocks); //snake
  if (!gameover) {  
    fill(fc1, fc2, fc3); //food color red
    ellipse(foodx*blocks+10, foody*blocks+10, blocks, blocks); //food
    textAlign(LEFT); //score
    textSize(25);
    fill(255);
    text("Score: " + x.size(), 10, 10, width - 20, 50);
    if (frameCount%speed==0) { 
      x.add(0, x.get(0) + x_direction[direction]); //make snake longer
      y.add(0, y.get(0) + y_direction[direction]);
      if (x.get(0) < 0 || y.get(0) < 0 || x.get(0) >= w || y.get(0) >= h) gameover = true; 
      for (int i=1; i<x.size(); i++) 
        if (x.get(0)==x.get(i)&&y.get(0)==y.get(i)) gameover=true; 
      if (x.get(0)==foodx && y.get(0)==foody) { //new food if we touch
         if (x.size() %5==0 && speed>=2) speed-=1;  // every 5 points speed increase
        foodx = (int)random(0, w); //new food
        foody = (int)random(0, h);
        fc1 = (int)random(255); fc2 = (int)random(255); fc3 = (int)random(255); //new food color
      } else { 
        x.remove(x.size()-1); 
        y.remove(y.size()-1);
      }
    }
  } else {
    fill(200, 200, 0); 
    textSize(30); 
    textAlign(CENTER); 
    text("GAME OVER \n Your Score is: "+ x.size() +"\n Press ENTER", width/2, height/3);
    if (keyCode == ENTER) { 
      x.clear(); 
      y.clear(); 
      x.add(0);  
      y.add(15);
      direction = 2;
      speed = 8;
      gameover = false;
    }
  }
}
void keyPressed() { 
  int newdir=keyCode == DOWN? 0:(keyCode == UP?1:(keyCode == RIGHT?2:(keyCode == LEFT?3:-1)));
  if (newdir != -1) direction = newdir;
}

Ok so if you are new to programming, I encourage you to see the tutorials on the Processing page :

processing.org/tutorials/

They are very well explained and easy to follow.

Also you can familiarize with the functions in the reference.

If you already know that, then it’s just a matter of reading and understanding the code. The user gently put some comments for you to understand it! :wink:

Try to break it into parts and understand them all and then you should be able to modify this code to do what you want it to do.

PS : also you can tell your teachers that it makes no sense not to use classes :grinning:

1 Like

Thank you for your advice Joseph, i appreciate.

1 Like

So this is the part of my gaming screen. Only part i really find a problem with is to remove 1 ellipse from the centipede if i go kopX (head centipede) over kameleonX…

So all the way down in the code at the void tekenCentipedeX and tekenCentipedeY there is the for loop the make 10 ellipses…

Hope somebody can help me with this part! :+1:

void scherm1() {
  textSize(12);
  centipede();
  println(centipedeX, centipedeY, bananenX, bananenY);
  score();
  //score eenmalig maken

  fill(0, 128, 0);
  moveSnake();
  tekenKameleon();



  if (kopX >= banaanX + centipedeGrootte && kopX <= banaanX + centipedeGrootte || kopY >= banaanY + centipedeGrootte && kopY <= banaanY + centipedeGrootte) {
    score1++;
    banaan = true;
    tekenBanaan();
  }

  if (banaan == true) {
  }

  if (kopX >= kameleonX + centipedeGrootte && kopX <= kameleonX + centipedeGrootte || kopY >= kameleonY + centipedeGrootte && kopY <= kameleonY + centipedeGrootte) {
    tekenBanaan();
  }
}


void moveSnake() {
  if (keyCode == RIGHT)
  {
    tekenCentipedeX();
    kopX += snelheidX;
  } else if (keyCode == LEFT)
  {
    tekenCentipedeX();
    kopX -= snelheidX;
  } else if (keyCode == UP)
  {
    tekenCentipedeY();
    kopY -= snelheidY;
  } else if (keyCode == DOWN)
  {
    tekenCentipedeY();
    kopY += snelheidY;
  }
  if (kopX >= 1000 || kopX <= 0) { 
    snelheidX = snelheidX * -1;
  }
  if (kopY >= 800 || kopY <= 0) { 
    snelheidY = snelheidY * -1;
  }
}

void tekenCentipedeX()
{
  for (int i = 0; i < 10; i++)
  {
    if (keyCode == RIGHT)
    {
      noStroke();
      ellipse(kopX - i*centipedeGrootte, kopY, centipedeGrootte, centipedeGrootte);
    } else if (keyCode == LEFT)
    {
      noStroke();
      ellipse(kopX + i*centipedeGrootte, kopY, centipedeGrootte, centipedeGrootte);
    }
  }
}

void tekenCentipedeY()
{
  for (int i = 0; i < 10; i++)
  {
    if (keyCode == UP)
    {
      noStroke();
      ellipse(kopX, kopY + i*centipedeGrootte, centipedeGrootte, centipedeGrootte);
    } else if (keyCode == DOWN)
    {
      noStroke();
      ellipse(kopX, kopY - i*centipedeGrootte, centipedeGrootte, centipedeGrootte);
    }
  }
}


In other order of things, in the old ZX Spectrum days, there was a 3d centipede/snake/tron deathcycle/nibbles game, I can’t recall the name. But doing a clone with processing should be easy and impressive!

1 Like