Lunch Under the Sea!

It’s a fish-eat-fish world out there, and you start out on the bottom of the food chain in this game.. As a tiny white fish (controlled by your mouse), gobble your prey and if you eat enough, you grow in size. Just make sure to avoid your predators!

Can you make it to the top? 

Level 1

Here’s the entire setup (I include pictures and a certain font type so they’ll be necessary for running it successfully)

Download: Lunch Under the Sea!

 Here is my main code: 

//Fish Objects: 
Fish self;
Fish test;
Fish[] prey_array = new Fish[10];
Fish[] predator_array = new Fish[7];

int number_of_predator; //Uses to manipulate predator array length for each level
int number_of_prey_eaten; //Uses to manipulate prey array lengths for interactions
int temp_num_prey_eaten; //Changes inside the prey collision for loop and will be set to the prey_eaten after the for loop (without dynamically changing the for loop)
int[] temporary_array_shift = new int[10]; //stores the indexes of all the prey objects that have been eaten

int actual_prey_eaten_per_level; 
/*Will be set to the difference between temporary prey eaten and regular prey eaten and will be used to set the for loop parameters
 Will be use "see" how many fish were consumed per draw loop (not per level)
 */

int index_of_new_array; // 

//Setting level booleans: used to "start" the each level once without it looping and constantly restarting
boolean level_1, level_2, level_3, level_4, level_5;

//Counter that sets parameters of each level:
int total_eat_count;

//Used to control lose screen:
boolean lose;

//Used for controlling special self and prey object (surprise!)
boolean self_surprise; boolean prey_surprise;

PImage sea_win;
PImage diver;
PImage bone;
 PFont font;

void setup() {
  size(900, 700);
  //Set all the booleans true to start each level. They will be used once to intialize the start of each level ONCE 
  level_1=true;
  level_2=true;
  level_3=true;
  level_4=true;
  level_5=true;

  total_eat_count = 0;

  number_of_predator = 0;
  initializePrey(247, 77, 214, 25);
  initializePredator(60, 245, 60, 75);
  index_of_new_array=0;
  number_of_prey_eaten = 0;
  temp_num_prey_eaten = 0;
  self = new Fish(0, 0, 0, 40, 1, 1, 0, 0);

  lose = false;
  diver = loadImage("Diver.png");
  sea_win = loadImage("Merman.png");
  bone = loadImage("bone.jpg");
   //Set up font:
  font = loadFont("ACaslonPro-Semibold-48.vlw");
  self_surprise = false;

}

void draw() {

  if (lose==false){
  background(00, 00, 200);
  //moving self

  if (self_surprise == false){
  self.move_Self();
  }
  else if(self_surprise){
      self.changetoMerman();
  }
  //PREDATOR: 
  for (int i=0;i<predator_array.length - number_of_predator;i++) {
    predator_array[i].moveFish();
    if (predator_array[i].checkBoundaries()) {
      predator_array[i].move_back_Fish();
    }
    if (predator_array[i].check_Collision(self)){
      lose = true;
    }
  }

  //PREY:
  index_of_new_array =0;
  //Moving Fish:
  for (int i=0;i<prey_array.length- number_of_prey_eaten;i++) { 

    //Use boolean for surprise!
    if (prey_surprise == false){

    //Moving fish (and accomodating when it goes out of bounds) 
    prey_array[i].moveFish();
  }
  else if(prey_surprise)
  {
        prey_array[0].draw_diver();
  }
    if (prey_array[i].checkBoundaries()) {
      prey_array[i].move_back_Fish();
    }
    if (prey_array[i].check_Collision(self)) {
      total_eat_count++;
      temp_num_prey_eaten++;
      temporary_array_shift[index_of_new_array]=i;
      index_of_new_array++;
    }
  }
  actual_prey_eaten_per_level = temp_num_prey_eaten - number_of_prey_eaten;
  number_of_prey_eaten = temp_num_prey_eaten;
  for (int i=0;i<actual_prey_eaten_per_level;i++) {
    shifting_index(temporary_array_shift[i]); //For EACH fish that is eaten (for loop), the index of the prey_array will be shifted over
  }

  nextLevel();

 }

 else if(lose == true){
   background (255,0,0);
   image(bone, 300, 400, 200, 150);
   textFont(font, 48); 
    fill(0,0,0);       
    text ( "You've been eaten!" ,200,300); 
 }

}
//END OF DRAW

//Other Methods: 

//Initializing Prey/Predator:
void initializePrey(int red, int green, int blue, int size) {
  Fish[] temp = new Fish[10];
  for (int i=0;i<prey_array.length;i++) {
    temp[i] = new Fish(red, green, blue, size, (int)random(0, width), (int)random(0, height), random(-3, 3), random(-3, 3));
  }
  for (int i=0;i<prey_array.length;i++) {
    prey_array[i] = temp[i];
  }
}

void initializePredator(int red, int green, int blue, int size) {
  for (int i=0;i<predator_array.length;i++) {
    predator_array[i] = new Fish(red, green, blue, size, (int)random(0, width), (int)random(0, height), random(-3, 3), random(-3, 3));
  }
}

//"Shifting" remaining uneaten fish over one index to the left
void shifting_index(int index) {
  for (int j = index; j<prey_array.length-1;j++) {
    prey_array[index] = prey_array[index+1];
  }
}
//Next Level functions: 
void nextLevel() {
  int level = 0;
  //Convert number of prey eaten to level amounts: 
  if (total_eat_count <= 9) {
    level = 1;
    if (level_1) {
      initializePrey(247, 77, 214, 25);
      initializePredator(60, 245, 60, 75 );
      self.change_fish_color(255, 255, 255);
      self.change_fish_size(50);
      number_of_prey_eaten=0;
      number_of_predator = 0;
      temp_num_prey_eaten =0;
      level_1=false;
    }
  }
  if (total_eat_count <= 18 && total_eat_count > 9) {
    level = 2;
    if (level_2) {
      initializePrey(255, 255, 255, 50);
      initializePredator(153, 76, 0, 100);
      number_of_prey_eaten=1;
      temp_num_prey_eaten=1;
      number_of_predator = 3;
      self.change_fish_color(60, 245, 60);
      self.change_fish_size(75);
      level_2=false;
    }

  }
  if (total_eat_count <= 23 && total_eat_count > 18 ) {
    level = 3;
    if (level_3) {
      initializePrey(60, 245, 60, 75);    
      initializePredator(135, 31, 166, 175);
      self.change_fish_color(153, 76, 0);
      self.change_fish_size(100);
       number_of_predator = 4;
      number_of_prey_eaten=5;
      temp_num_prey_eaten=5;
      level_3=false;
    }

  }
  if (total_eat_count == 24) {
    level = 4;
    if (level_4) {
      initializePrey(255, 255, 255, 75);
      prey_array[0].draw_diver();
      initializePredator(0, 0, 0, 250);
      self.change_fish_color(132, 224, 247);
      self.change_fish_size(175);
      number_of_prey_eaten=9;
      temp_num_prey_eaten=9;
      number_of_predator = 6;
      prey_surprise = true;
      level_4=false;
    }
    total_eat_count=24;
  }
  if (total_eat_count == 25) {
    level = 5;
    if (level_5) {
      number_of_prey_eaten=10;
      temp_num_prey_eaten=10;
      number_of_predator = 7;
      level_5=false;
    }
    self_surprise = true;
    textFont(font, 36); 
    fill(255,255,255);       
    text ( "You're the king of the sea!" ,250,300); 
  }

}//End of next_level function  INSERT PIC OF HUMAN SWIMMING  case 4: initializePrey

//Level reset function: 
void level_reset(){
  //Set all level booleans back so that levels can re-initialize again & reset level_progression variable back to 0
  level_1=true;
  level_2=true;
  level_3=true;
  level_4=true;
  level_5=true;
  total_eat_count = 0;
  self_surprise= false;
  prey_surprise = false;
}

void keyPressed(){
  lose = false;
  level_reset();
}

 And here is my separate fish class file: 

class Fish {
  //Fish color: 
  int r;
  int g;
  int b;

  //Fish size
  int fish_width;
  int fish_height;
  int fish_size;

  //Fish position
  int x;
  int y; 

  //Fish speed
  float velocity_x;
  float velocity_y;

  //For when fish is eaten --> variable
  boolean eaten = false;

  //Constructor
  Fish(int _r, int _g, int _b, int _fish_size, int _x, int _y, float _velocity_x, float _velocity_y) {
    r = _r;
    g = _g;
    b = _b;
    fish_size = _fish_size;
    fish_width = 2 * _fish_size;
    fish_height = _fish_size;
    x = _x;
    y = _y;
    velocity_x = _velocity_x;
    velocity_y = _velocity_y;
  }

  void drawFish() {
    stroke(r, g, b);
    fill(r, g, b);
    triangle(x, y, x, y+fish_height, x+ (fish_width/3), y+(fish_height/ 2));
    ellipse((x+((10*fish_width/18))), y+(fish_height/2), ((2*fish_width)/3), (15*fish_height/16));
  }
  void moveFish() {
    x+=velocity_x;
    y+=velocity_y;
    this.drawFish();
  }

  boolean checkBoundaries() {
    boolean out_of_bounds = false;
    //Out of screen (horizontal)
    if (x>(width+(1.5* fish_width))|| x < (0 - (1.5*fish_width))) {
      out_of_bounds = true;
    }

    //Out of screen (vertical)
    if (y>(height+(1.5*fish_height)) || y < (0 - (1.5* fish_height))) {
      out_of_bounds = true;
    }
    return out_of_bounds;
  }

  void move_Self() {
    x = mouseX -(fish_width / 2);
    y = mouseY - (fish_height / 2);
    this.drawFish();
  }

  void move_back_Fish() {
    //Will randomize the side from which the fish returns
    //Will maintain the same magnitude of velocity
    /* Must figure out magnitude from original x and y velocities
     Then use magnitude to determine the new velocities 
     Use random to find new angle of reentry (radians)
     magintude SIN (theta) = y
     magnitude COS (theta) = X
     */

    float theta = random(.1*PI, .9*PI);

    float magnitude = 0;
    magnitude = sqrt((float)(Math.pow(velocity_x, 2))+(float)(Math.pow(velocity_y, 2)));
    int side = (int) random(1, 5);
    switch (side) {
      //Top
    case 1: 
      y = 0 - fish_height; 
      x = width/2;
      velocity_y = (magnitude * sin(theta)); 
      velocity_x = (magnitude * cos(theta)); 
      break;

      //Bottom
    case 2:
      y = height + fish_height;
      x = 450;
      velocity_y = -(magnitude * sin(theta)); 
      velocity_x = (magnitude * cos(theta));
      break;

      //Left
    case 3:
      y = 375;
      x = 0 - fish_width;
      velocity_y = (magnitude * sin(theta)); 
      velocity_x = (magnitude * cos(theta));
      break;
      //Right
    case 4:
      y = 375;
      x = width + fish_width;
      velocity_y = (magnitude * sin(theta)); 
      velocity_x = -(magnitude * cos(theta));
      break;
    }
  }

  //Getter Methods for collision detection 
  int get_X_Position() {
    return x;
  }
  int get_Y_Position() {
    return y;
  }
  int get_fish_Height() {
    return fish_height;
  }

  int get_fish_Width() {
    return fish_width;
  }
  //COLLISION
  boolean check_Collision(Fish temporary) {
    boolean signal = false;
    int temp_x = temporary.get_X_Position();
    int temp_y = temporary.get_Y_Position();
    int temp_fish_height = temporary.get_fish_Height();
    int temp_fish_width = temporary.get_fish_Width();

    if (x < (temp_x + temp_fish_width) && (x+fish_width) > (temp_x )) {   
      if (y < (temp_y + temp_fish_height) && (y+fish_height) > (temp_y )) {
        signal = true;
      }
      else {
        signal = false;
      }
    }
    return signal;
  }

//If prey and  self have collided, sets collided prey to eaten
void set_to_Eaten() {
  eaten = true;
}
  //Getter method to check if fish have been eaten
  boolean get_if_Eaten() {
    return eaten;
  }

//Change fish color:
void change_fish_color(int _r, int _g, int _b){
  r = _r;
  g = _g;
  b = _b;
}

void change_fish_size(int _size){
  fish_size = _size;
  fish_width = 2 * _size;
  fish_height = _size;
}

void draw_diver(){
  float temp_x = x;
  float temp_y = y;
  image (diver, temp_x, temp_y, 150, 75);
  x+=velocity_x;
  y+=velocity_y;
}

void changetoMerman(){
  image(sea_win,mouseX,mouseY,250,400);
    x = mouseX -(fish_width / 2);
    y = mouseY - (fish_height / 2);

}

  //End of Fish Class
}

PS. Make it to level 4 and you’ll see a surprise.  Can you conquer the sea?

 

Potential improvement:

-I think I’d like to to make a smoother transition from game over to the reset level 1. I’ve had the displeasure of the pressing a key to reset the level but then automatically dying again because my fish is placed over where the predators are drawn..

– Fix this weird glitch where sometimes two fish are “eaten”

-Fix “stuck” moments

Leave a Reply