Survival of the fittest

***current works in progress.

Inspired by evolution, my object oriented programming sketch is centered around different colored circles that represent different species, emerging at random and when clicked on duplicate exponentially. However, one circle from each species “dies off ” (removed) at random. Once one full row of circles fill up the top of the window, they “die off” by having the whole row disappear , this represents the death of older generations in rise of newer ones, and the cycle continues.

// still work in progress
Bubble b; 
void setup() {
  size(640, 360);
  b = new Bubble(64); // b is a new instance a bubble object, Bubble() is a constructor.
};
void draw() {
  background(255);
    //backdrop();
  b.top();
  b.display();
  b.ascend();//dot syntax, calling a function on that object.

};

//__________________
class Bubble {
  float x;
  float y;
  float diameter;

  Bubble(float tempD) { 
    x=width/2;
    y=height/2;
    diameter=tempD;
  };

  void display() {
    stroke(0);
    fill(127);
    ellipse(x, y, diameter, diameter);
  };

  void top() {
    if (y<diameter/2) {
      y=diameter/2;
    };
  };
  void ascend() {
    y--;
    x=x+random(-2, 2);
  };
};

______________________________________

Updated version: Box Game 🙂

float x = width/6;
float y = height/6;
// Click within the image to change 
// the value of the rectangle
void setup() {
  background(#FFA500);
  size(600, 600);
  ellipseMode(CENTER);
};
void draw() {
   keyPressed() ;

  if (mousePressed == true) {
    //background(100);
    fill(0);
    x+=1;

    //} else {
    //  fill(255);
  }
  //rect(25, 25, 50, 50);
  rect(x, y, 100, 100); //rect(x+random(-1, 1), y, 100, 100);
  if (keyPressed == true) {
    //background(100);
    fill(255);
    y+=1;
  };

};



  void keyPressed() {
    if(key == 's'){ 
    rect(x+100, y+100, 100, 100);
    
  };
   if(key == 's'){ 
    rect(x+200, y+200, 100, 100);
    
  };

  };

OOP Version: I lost some of the serendipity in the OOP version of this box interaction, versus in the one above. This assignment was harder the last but taught me a lot in code organization.

Box b;
Box b2;
void setup() {
  size(600, 600);
  b= new Box();
  b2= new Box();//change color and xy position.
};
void draw() {
  background(#FFA500);
  b.display();
  b.moveRight();
  b.moveLeft();
  b.leftWall();
  b.move();
  b.duplicate();
  //b.mirror();
  //b.addNewObjToArray();
  //b.exponentialGrowth();
  //b.rightWall():
  //b.bounceEdge();
  //b.bottom
  //b.top
}
//_____________
class Box {
  float x = width/2;
  float y = height/2;
  float xpos = random(100, 100);
  float ypos =random(200, 200);

  float xspeed=5;


  void  display() {

    rect(x, y, 100, 100);
    rectMode(CORNER);
  };
  void moveRight() {
    if (keyPressed == true) {
      fill(255);
      x+=1;
    };
  };
  void moveLeft() {
    if (keyPressed == false) {
      fill(255);

      x-=1;
    };
  };
  void leftWall() { //will rest at the edge
    if (x>width||x<0) {
      x=x*-0.1;
    };
  };
  //void rightWall() {
  //    if (y>width||x<0) {
  //    y=y*0.1;
  //  };
  void move() {
    if (keyPressed == true) {
      //background(100);
      fill(255);
      y+=1;
    };
  }
  void duplicate() {

    if (key == 's') { 
      rect(x+100, y+100, 100, 100);
    };
    if (key == 's') {
    };
  };
 
}

 

 

OOP Asteroids Game

For this week’s assignment I decided to make an arcade game. The goal of the game is to avoid all the falling mysterious asteroids and be the LAST SURVIVING SQUARE on the surface of the earth! The game is definitely not the final version and I am planning on adding some more features to it. But this could be considered the prototype of what I have imagined first. Below is the logo of the game I got inspired by initially.

Here is the video of the prototype of the game:

Below is the code:

// Asteroids Game

int i;
float x, y;
float velocity;
float acceleration;
int startTime = 0;
int time = 0;
Asteroid[] a = new Asteroid[20];

public void settings() {
  size(640, 640);
}

void setup(){
  //player position
  x = width/2;
  y = height-32;
  velocity = 0;
  acceleration = random(8,24);
  
  for (int i=0; i<a.length; i++){
    a[i] = new Asteroid();
  }
}

void draw(){
  background(0);
  
  pushMatrix();
  i = 0;
  while (i<a.length){
    a[i].display();
    a[i].update();
    if (a[i].posy > 12){
      i++;
    }
  }
  popMatrix();
  
  pushMatrix();
  player();
  popMatrix();
  
  textSize(25);
  fill(255);
  text("Level 1", width-100, 50);
  time = (millis() - startTime) / 1000;
  textSize(15);
  text("Time alive : " + time, width-115, 75);
}

void player(){
  stroke(255);
  strokeWeight(2);
  fill(127);
  rect(x, y, 30, 30);
}

void keyPressed() {
    if (keyCode == LEFT && x-15>= 0){
      velocity += acceleration;
      x -= velocity;
      acceleration *=0;
    }
    if (keyCode == RIGHT && x+15 <= width ){
      velocity += acceleration;
      x += velocity;
      acceleration *=0;
    }
}

class Asteroid {

  float posx, posy;
  float speed;

  Asteroid () {
    smooth();
    //asteroid position
    posx = random(width);
    posy = -15;
    speed = random(6);
  }

  void update() {
    posy += speed;

    if (posy > height+6) {
      posy = -6*2;
      posx = random(width);
    }
  }


  void display() {
    pushMatrix();
    stroke(255);
    strokeWeight(2);
    fill(127);
    ellipse(posx, posy, 24, 24);
    popMatrix();
  }
}


 

One More Time: Rolly Vortex (the Addictive Game) – Beethoven

Still hooked up by the mobile app game Rolly Vortex since last week’s assignment, I decided to take a shot at creating the game.

The mobile app game

I started out by trying to create the grey hoops which give the feeling of you being inside a vortex. I struggled with making them because I wanted to create white spaces between each of them, and because I wanted each hoop to restart from the middle after it expands more than the height of the screen. I wanted to do 3D where the z-dimension increases but I wasn’t comfortable enough at the start.

This was how they looked before fixing the distances between each of them, their thickness, and how they restart.

picture of the improved hoops

This is the better version where the hoops actually look like a vortex and are quite similar to the game.

I then started to create the ball and I wanted it to be 3D so a sphere instead of an ellipse. But I struggled at first with making sure the ball doesn’t enter the center of the vortex and did it manually, which was still unsuccessful.

I then did the blocks, where I started out by creating them using rectangles and moving their z-coordinate towards the screen to give the feeling of a vortex. However, after so many trial and error, I realized that the pushMatrix() and popMatrix() are quite dangerous if not used properly and that I had so many issues because of them. or example, I couldn’t move the blocks properly while moving the ball as in the video.

After many attempts I was finally able to create 3D boxes which get closer to the screen and to successfully move the ball without touching the center and to properly make a collide function that checks if the ball touches any block. I was able to end and restart the game without errors and to keep score while playing and at the end of the game.

The code for the overall game:

Hoop[] hoops;    //list of grey vortex circles
float x, y, z;
Ball ball;       // ball of the player
ArrayList<Block> blocks;    //array list of obstacle blocks
boolean gameOn;      //condition under which the game operates
PFont f;         //text for ending game
int score;        //score of user, increases with each block block they


void setup () {
  
  size(1280, 720, P3D);
  
  hoops = new Hoop[200];    //instances of the three main classes
  ball = new Ball();
  blocks = new ArrayList<Block>();
  
  blocks.add(new Block(60));    //initial theta in argument
  
  gameOn = true;
  score = 0;
  
  f = createFont("Arial",72,true);
  
  for (int i =0; i < hoops.length; i++) {      //creates the continuous hoops
    hoops[i] = new Hoop();
  }
  
  
}

void draw () {
  
  background(255);
  
  if (gameOn == true) {
    
    for (int i = 0; i < hoops.length; i+= 20) {      //draws the hoops and calls the related functions
      hoops[i].drawHoop(i*10);
      hoops[i].update();
      hoops[i].checkEdge();
    }
    
    ball.drawBall();          // draws the ball
    
    for (int i = blocks.size()-1; i >= 0; i--) {       //draws block for each element in the array list
      Block block = blocks.get(i);
      block.drawBlock();
      
    }
    
    if (frameCount % 60 == 0){                      //creates instances of the blocks of number between 1 and 6 randomly
      for(int i = 0; i < int(random(1,6)); i++) {
        blocks.add(new Block(int(random(1,12)*30)));
        
        if (gameOn == false) 
          {break;}
        
      }
    }
    score = blocks.size();          //updates the value of score to be number of elements in array list
    
    for (int i = blocks.size()-1; i >= 0; i--) {            //checks if the ball collided with any block, if true the game stops
      if (ball.checkCollide(blocks.get(i).posX, blocks.get(i).posY) == true) {
          gameOn = false;
       };
    }
    
    textAlign(CORNER);
    textFont(f,24);
    fill(0);
    text("Score: "+ score,width -120,height -30);        //score text bottom right
    
    
  }
  
  else {
    textFont(f,72);               
    fill(#000080);
    textAlign(CENTER);
    text("GAME OVER!",width/2,height/2 - 30);
    textFont(f,24);
    fill(0);
    text("CLICK ANYWHERE TO RESTART",width/2,height/2 +30);      //game over text
    
    textAlign(CORNER);
    textFont(f,24);
    fill(0);
    text("Score: "+ score,width -120,height -30);      //final score text
    
    
    
  }
}

void mouseClicked() {
  if (gameOn == false) {
    score = 0;
    gameOn = true;
    for (int i = blocks.size()-1; i >= 0; i--) { 
      Block block = blocks.remove(i);
      block.drawBlock(); 
    }
  }
}

Code for the Ball() class:

class Ball {
  float ballWidth, ballHeight;
  float locX, locY;
  color ballColor;
  float speed;
  int radius;
  PVector m;
  PVector circle;
  float z;
  float easing = 0.95;

  
  Ball() {
  
    locX = width/2;
    locY = height/2;

    ballWidth = 100;
    ballHeight = ballWidth;
    
    speed = 15;
  
    ballColor = color(random(255), random(255), random(255)); 
    
    radius = 150;
    
    z= 0;
  
  }
  
  void drawBall() {
     //idea inspired from ellipse constraint code from https://forum.processing.org/one/topic/ellipse-constrain-shape.html
   
    fill(#F5F5F5);
    noStroke();
    m = new PVector(mouseX, mouseY, z);      //vector of movement of ball
    circle = new PVector(width/2, height/2, z); //vector circle around which ball is constrained
    ellipse(circle.x, circle.y, radius, radius);     //circle of cosnstrain
    

    if (dist(m.x, m.y, circle.x, circle.y) < radius) {
      m.sub(circle);
      m.normalize();
      m.mult(radius);
      m.add(circle);      //constrains movement of ball to be everywhere except at a distance from teh center of the vortex
    }
    locX = locX + (m.x - locX) * easing;
    locY = locY + (m.y - locY) * easing;     //sets the x and y coordinates such that the ball is updated properly and doesn't disappear or enter middle 
    
    noStroke();
    lights();
    pushMatrix();
      translate(locX, locY - 30, z);
      fill(ballColor);
      sphereDetail(36, 36);
      sphere(30);
    popMatrix();      //draws the 3D sphere at the updated location
    //z+= 0.5;
  }
  
  boolean checkCollide(float posX, float posY) {

    if (dist(locX, locY - 30, posX - 30, posY + 25) < 55) {    //if ball touches the x,y coordinates of the block it collides and returns true to end game
      gameOn = false;
      return true;
    }
    
    else {
      return false;
    }
  }
}

Code for the Block() class:

class Block {
  float blockWidth, blockHeight, blockDepth;
  float locXB, locYB, locZ;
  color a, g, b;
  float posX, posY;
  float theta;
  float speed;

  Block(int _theta ) {
    
    locXB = width/2;
    locYB = height/2;
    locZ = 0;
  
    blockWidth = 60;
    blockHeight = 50;
    blockDepth = 30;
    
    a = int(random(255));
    g = int(random(255));
    b = int(random(255));    //randomized color
    
     posX = width/2;
     posY = height/2;
     theta = _theta;
    
    speed = 6;    //speed of shift
  
  }
  
  void drawBlock() {
   fill(a, g, b);
   noStroke();
   pushMatrix();
     
     translate(posX, posY, locZ);
     rotate(radians(theta));      //rotates blocks before moving
     posX += speed*sin(theta);    // horizontal shift
     posY += speed*cos(theta);    //vertical shift
     box(blockWidth, blockHeight, blockDepth);
     
     locZ+= 8;      //z-dimension shift towards the screen

   popMatrix();
   
  }
}

Code for the Hoop() class:

class Hoop {
  float outerHoopWidth, outerHoopHeight;
  float innerHoopWidth, innerHoopHeight;
  float locXH, locYH;
  float speed, acceleration;

  Hoop () {

    locXH = width/2;
    locYH = height/2;

    outerHoopWidth = 100;      //width of circle
    outerHoopHeight = outerHoopWidth;

    speed = 5;

  }

  void update() {
    
    if (outerHoopHeight + 400 == height) {
      speed = 10;
    }
    
    outerHoopWidth += speed;
    outerHoopHeight += speed;
    
  }

  void checkEdge() {
    if (outerHoopHeight + 300 == height) {    //if hoop is out of screen then restart it at the middle of the screen
      outerHoopWidth = 200;
      outerHoopHeight = 200;
    }

  }

  void drawHoop(int xFactor) {

    float circle1w = outerHoopWidth + xFactor;    //xFactor is to space out the different hoops

    float circle1h = outerHoopHeight + xFactor;

    noFill(); 
    stroke(#F5F5F5);
    strokeWeight(55);
    ellipse(locXH, locYH, circle1w, circle1h);
    
    
    
  }
}

 

 

Ryan’s Failed Brick Breaker Game

So, initially for this week’s assignment, I wanted to replicate my childhood game, which was called the Brick Breaker, as I really loved this game and played it almost everyday since I was small with my mom’s old Nokia phone.

Arkadroid Brick Breaker - Apps on Google Play

Initially, I sort of drew a sketch for myself to better follow along and code, as shown below. (Excuse the poor quality)

At first, I had no difficulty creating my user bar, the bouncing balls, and the blocks at the top. However, the main obstacle for me was being able to make the balls to be able to bounce off my user bar and also the rectangles (and causing them to disappear upon contact). I tried searching up tutorials, videos, websites, and even other online projects made before in order to help me understand collision detection and how to code it. However, in the end, I still wasn’t able to code the collision detection for my ellipses because I could not quite grasp and fully understand the mechanics behind coding for interactions between two different classes, which in this case would be the ellipses with the user bar and the rectangles. Furthermore, you will notice a lot of hardcoding because I wasn’t quite sure how to use arrays yet and I did not want to mess with something I wasn’t familiar with yet.

So, in the end, I decided to just add a bit more ellipses to make it look less boring as it did.

/***************MAIN SKETCH **************/
int x;
int y;
int blockx;
int blocky;
int rectWidth=50;
int rectHeight=50;


Bar userbar; 
RandomBlocks blocks;
RandomBlocks blocks2;
RandomBlocks blocks3;
RandomBlocks blocks4;
BouncingBall ball;
BouncingBall ball2;
BouncingBall ball3;
BouncingBall ball4;
BouncingBall ball5;
void setup() {
  size(1280, 720); 
  userbar= new Bar(); //calling for a constructor 
  blocks= new RandomBlocks();//constructor always needs two paranthesis ()
  ball= new BouncingBall(random(width), random(height), 50);
  ball2= new BouncingBall(random(width),random(height),50);
  ball3= new BouncingBall(random(width),random(height),50);//ALL OF THIS IS HARDCODING SORRY
  ball4= new BouncingBall(random(width),random(height),50);
  ball5= new BouncingBall(random(width),random(height),50);
  blocks2= new RandomBlocks();  blocks3= new RandomBlocks();
  blocks4= new RandomBlocks();
}



void draw() { 
  background(255);

  userbar.drawbar(); //using dot syntax, it calls a function for the object to do sth built by constructor 
  //Random blocks at the top
  blocks.drawblock();
  blocks2.drawblock2();
  blocks3.drawblock3();
  blocks4.drawblock4();
  //All the five balls 
  ball.bounceBall();
  ball2.bounceBall();
  ball3.bounceBall();
  ball4.bounceBall();
  ball5.bounceBall();
}

/***********Code for the controllable user blue bar***********/ 
class Bar {
  

  Bar() { //this is a constructor with paranthesis ()
  // in a constructor, it doesn't necessarily have to contain anything inside it, it just represents an object
    
  }
    void drawbar(){
    stroke(255, 0, 0);
    fill(0, 0, 255);
    rect(mouseX-250, height-50, 300, 20);
    }
}

/************Code for the five ellipses***************/
class BouncingBall {
  //float ballx=random(width);
  //float bally=random(height);
  float diameter;
  float xspeed;
  float yspeed;
  float x;
  float y;
  color c;

  BouncingBall(float tempX, float tempY, float tempDiameter) {//constructor
    x=tempX;
    y=tempY;    diameter=tempDiameter;
    xspeed=10;
    yspeed=10;
  }
  void bounceBall() {
    stroke(0);
    fill(211, 123, 231);
    ellipse(x, y, 50,50);

    if (x>=width || x<=0) {
      xspeed*=-1;
    }


    if (y>=height || y<=0) {
      yspeed*=-1;
    }

    x=x+xspeed;
    y=y+yspeed;
  }
 
}

/************Code for the rows of shiny blocks at the top**********/ 

class RandomBlocks {//for a class, the first letter has to be capitalized 

  RandomBlocks() {//a constructor
  }
  void drawblock() {

    for (x=0; x<width; x+=rectWidth+50) {
      stroke(0);
      fill(random(255), random(255), random(255));
      rect(x, y, rectWidth, rectHeight);
    }
  }

  void drawblock2() {
    for (x=0; x<width; x+=rectWidth+50) {
      stroke(0);
      fill(random(255), random(255), random(255));
      rect(x+50, y+60, rectWidth, rectHeight);
    }
  }

  void drawblock3() {
    for (x=0; x<width; x+=rectWidth+50) {
      stroke(0);
      fill(random(255), random(255), random(255));
      rect(x+100, y+120, rectWidth, rectHeight);
    }
  }

  void drawblock4() {    for (x=0; x<width; x+=rectWidth+50) {
      stroke(0);
      fill(random(255), random(255), random(255));
      rect(x+50, y+180, rectWidth, rectHeight);
    }
  }
}

 

Pixel Art Using a Square Class

This was a challenging assignment! Mainly because I had a game I wanted to do in mind, and after spending a lot of time on getting the basics to work I realized it might need more practice and time than what I have now, so I changed the direction of my assignment and decided to go with a more “artwork” focused approach.

Recently I’ve been thinking about the ‘paint by numbers notebooks’ I used to have as a child and how accessible they made creating artwork that is above my artistic skills. This made me want to buy a ‘paint by numbers’ set, but also I asked if I could use the same approach to create artwork on processing.

example is taken from https://tomyumtumweb.com/ 

I realized I can do a similar approach but with pixels! I made a class called “square” which represents each square in a grid, and then used a 2D array list that contains different combinations of numbers of squares to be filled.

My class has a display function, and a fill function that relies on a boolean variable.

For the drawing, I decided to go for a heart that is filling gradually with every number the user inputs from their keyboard. At the final level, when the heart is full, it goes from black to a mix of random shades of red and pink which is controlled by the mouseX movement to a certain extent (to avoid the colors being too random).

Inspiration Image

After finalizing the logic, which depends on creating an array of square objects and then displaying and referencing them as a grid. I went to figure out the square numbers needed in my 2D array for each heart stage. For this part, I used pixilart.com  and created a grid of the same size as mine then compared the square values.

 

Taking values from sketch to my code
Trying different grid sizes 

I settled on bigger pixels, but since the code contains, row, column, and square number variables, it is easy to change the grid appearance and square size.

I think the program has the potential to be more complex or contain more user interaction, I would love any suggestions!

Have a look at my main code:

Square[] allSquares; //declaring an array of objects that consists of the squares that will be in the grid

// 2D Array of the different heart level drawings, each inner list contains the number of the pixel that should be filled
int[][] heartLevels = { {2,3,4,11,15,21,26,32,37,43,48,53,58,62,67,71,76,81,85,92,93,94}, //empty heart
                   {2,3,4,11,15,21,26,32,37,43,47,48,53,57,58,62,67,71,76,81,85,92,93,94}, //initially filled heart (Level 1)
                   {2,3,4,11,15,21,25,26,32,35,36,37,43,45,46,47,48,53,55,56,57,58,62,65,66,67,71,75,76,81,85,92,93,94}, // medium full heart (Level 2) 
                   {2,3,4,11,13,14,15,21,23,24,25,26,32,33,34,35,36,37,43,44,45,46,47,48,53,54,55,56,57,58,62,63,64,65,66,67,71,73,74,75,76,81,83,84,85,92,93,94}, 
// almost full heart (Level 3)
                   {2,3,4,11,12,13,14,15,21,22,23,24,25,26,32,33,34,35,36,37,43,44,45,46,47,48,53,54,55,56,57,58,62,63,64,65,66,67,71,72,73,74,75,76,81,82,83,84,85,92,93,94}}; // full heart
                   
// a boolean to create the color effect for the full heart
boolean fullHeart; 
                   
 // declaring and initializing the column and row number for the grid                  
int cols = 10; 
int rows = 10;



void setup(){
 size(500,500);
 background(255);
 //creating the grid array, the array size corresponds to the dimension of the grid
 allSquares = new Square[cols*rows]; 
 //initializing and declaring an index variable to create different objects every time the  nested loop runs
 int index = 0; 
 //a nested loop that goes through each column and row to create a grid of objects
 for (int c = 0; c < cols; c++){
  for (int r = 0; r < rows; r++){
    // creating the objects, the arguments of the class are X location, Y location, Width, Height, and index

//we multiply c and r by 50 because it corresponds to the square dimension, so if my x is 2 and y is 2, the square will be at 100,100.
   allSquares[index] = new Square(c*50,r*50,50,50,index); 


   index+=1;
   
  }
 }
 fullHeart = false; //initializing the color effect variable with false
}



void draw(){
  //a loop that displays the grid
  for(int i = 0; i < cols*rows; i++){
   allSquares[i].display();
   
   //an if statement that checks which heart we are creating by checking if the fullHeart bool is true, it is changed to true below, when the key is pressed.
   if (fullHeart == true){
   for (int j = 0; j < heartLevels[4].length; j++){

     //accessing the heart color variable defined in the square class, and altering it for the color effect

//using random within a small range to generate the different shades of red, and applying interaction through mouseX
    allSquares[heartLevels[4][j]].heartColor = color(random(mouseX,255), random(0,90),random(90,100));  //interacting with user through changing the R random bottom range using mouseX. 
 
                                             
                                             
   //filling the squares, it keeps changing because it is in the draw function
    allSquares[heartLevels[4][j]].fillingSquare(true); 
   
  }
   }
  }
}
  
  
  
  void keyPressed(){
  //key pressed function that displays different heart shapes based on the number pressed  
    
  if (key == '0'){ //zero gives an empty screen
      for(int i = 0; i < cols*rows; i++){
        fullHeart = false; //this boolean is set to false for every key that does not correspond to a full heart

   allSquares[i].fillingSquare(false); //First loop goes through all the squares in the object list and unfills them to remove the effect of other shapes, this loop is repeated for all the other keys
   
      }
  }
  if (key == '1'){
      for(int i = 0; i < cols*rows; i++){ //same loop
   allSquares[i].fillingSquare(false); 
  }
      for (int i = 0; i < heartLevels[0].length; i++){ 
        fullHeart = false;
       allSquares[heartLevels[0][i]].heartColor = color(0); //sets the color variable from the class to black

       allSquares[heartLevels[0][i]].fillingSquare(true); ////fills every pixel that corresponds to values in the first heart shape list with black
       
  }
  }
  
  //the same repeats for the next if conditions
  else if (key == '2'){
    for(int i = 0; i < cols*rows; i++){
   allSquares[i].fillingSquare(false);
  }
    for (int i = 0; i < heartLevels[1].length; i++){
      fullHeart = false;
     allSquares[heartLevels[1][i]].heartColor = color(0);
     allSquares[heartLevels[1][i]].fillingSquare(true); 
  }
 

  
 
  }
  else if(key=='3'){
   for(int i = 0; i < cols*rows; i++){
   allSquares[i].fillingSquare(false); 
  }
    for (int i = 0; i < heartLevels[2].length; i++){
      fullHeart = false;
     allSquares[heartLevels[2][i]].heartColor = color(0);
     allSquares[heartLevels[2][i]].fillingSquare(true);
   
  }
  }
  else if(key=='4'){
     for(int i = 0; i < cols*rows; i++){
   allSquares[i].fillingSquare(false);
  }
     for (int i = 0; i < heartLevels[3].length; i++){
       fullHeart = false;
     allSquares[heartLevels[3][i]].heartColor = color(0); 
     allSquares[heartLevels[3][i]].fillingSquare(true);
   
  }
  }
  else if(key=='5'){
    for(int i = 0; i < cols*rows; i++){
  allSquares[i].fillingSquare(false);
  }
    for (int i = 0; i < heartLevels[4].length; i++){
     fullHeart = true; //this turns on the random color fill in the draw function
    allSquares[heartLevels[4][i]].fillingSquare(true); //and based on those colors fills the squares
    
    
    }
  }
  }

and my Square Class:

class Square{
//initializing variables that will be used throughout the class  
int squareX , squareY;  //square x and y location
int squareW , squareH; 
int squareNo; //the number of the pixel on the grid
boolean filled; //the boolean that determines which pixels on the screen are filled
color heartColor; //a color variable to control the color of the pixel
color gridStroke = color(203,197,197); // color of grid lines

Square(int tempX, int tempY, int tempW, int tempH, int tempSquareNoMinus1){ //constructor, takes X location, Y location, Width, Height, and the index as arguments
 //setting the constructor arguments to permanent variables
 squareX = tempX;
 squareY = tempY;
 squareW = tempW;
 squareH = tempH;
 squareNo = tempSquareNoMinus1 + 1; // 1 is added to the index as the counting of squares starts at 1, not zero. 
 
}



void display(){
 //function that displays the square on the screen
 stroke(gridStroke);
 strokeWeight(0.25);
 noFill();
 rect(squareX , squareY , squareW , squareH);
 
 
}


void fillingSquare(boolean filled){
  //a function that fills the pixels based on a filled? boolean
  if (filled == true){
    
   fill(heartColor); 
  }
  else{
  //if the boolean is false the square is filled with white and redrawn  
   fill(255); 
  }
  rect(squareX,squareY,squareW,squareH);
  }
}

 

 

Object Oriented Programming Game – Survival Pong

For this project, I wanted to create a simple two-player game. Even though I don’t really have anyone to play it with. 🙁

The game gives each player a ball, player 1 with a red ball and player 2 with a blue ball. On the sides of the map, there are four purple lines that move in a random fashion along their axis. Player 1 controls the red ball with WASD and player 2 controls the blue ball with the direction keys. The goal of each player is to collide with the purple lines as much as possible. Each collision gives the player 1 point and resets them at the center of the screen. Each purple line gets shorter every time it is collided with, making it harder to collide with next time.

To win, collide with more lines than the opponent before all the lines disappear. Going out of bounds also automatically gives the win to the other player, so be careful.

As I was coding this project, I bumped into a few problems, some that still exists.

    • I originally wanted the balls to move by themselves in a smooth fashion around the map, and the players would have to react with their movement keys in order to stop themselves from dying. Ultimately I wasn’t able to make it look smooth, I was using frameCount as my method of timing the balls’ speed and it wasn’t working.
    • The balls would move upon pressing the direction keys nicely. However, if I do something this, there is a bug:
        1. Press left
        2. Press down while not releasing left
        3. Release down while not releasing left
        4. The ball would still be moving down, even though I’m holding left.

Overall, this was a useful project in helping me get a basic understanding of how to do Object-Oriented Programming with Java. I used three tabs for this assignment, one for the main game, one for the Ball class, and one for the Wall class. I actually feel like it’s easier than doing it with Python, and I look forward to doing more of this with Java. The logic just seems more clear.

Below is the video of my gameplay with myself, showing both the death-win scenario and the point-win scenario.

Here is my main game code:

Ball b1;
Ball b2;

Wall w1;
Wall w2;
Wall w3;
Wall w4;

void setup() {
  size(640, 640);
  b1 = new Ball(width/3, height/2, 1);          // player 1 ball
  b2 = new Ball(width/1.5, height/2, 2);        //player 2 ball
  w1 = new Wall(0, height/2, 10, 200, 1);
  w2 = new Wall(width/2, height, 200, 10, 0);
  w3 = new Wall(width, height/2, 10, 200, 1);
  w4 = new Wall(width/2, 0, 200, 10, 0);        //four walls
}

void draw() {
  background(255);
  textSize(24);
  text(b1.score, width/3, height/2 - b1.diameter);
  text(b2.score, width/1.5, height/2 - b2.diameter);

  b1.display();
  b1.move();
  b2.display();
  b2.move();

  
  w1.display();
  w1.move();
  w2.display();
  w2.move();
  w3.display();
  w3.move();
  w4.display();
  w4.move();
  b1.collision();
  b2.collision();
  checkwin();
}

void checkwin(){
  if (b1.score + b2.score >= 16){                  //it is only possible to bump the walls 16 times in total
    stop();
    if (b1.score > b2.score){
      fill(255, 0, 0);
      rect(width/2, height/2, 640, 640);
      fill(255, 255, 255);
      textSize(32);
      text("Player 1 Wins!", width/2, height/2); 
    }
    else if (b2.score > b1.score){
      fill(0, 0, 255);
      rect(width/2, height/2, 640, 640);
      fill(255, 255, 255);
      textSize(32);
      text("Player 2 Wins!", width/2, height/2);
    }
  }
}

Ball class code:

class Ball {

  float x;
  float y;
  float diameter;
  int score;
  int player;

  Ball(float tempX, float tempY, int tempPlayer) {
    x = tempX;
    y = tempY;
    diameter = 40;
    score = 0;
    player = tempPlayer;
  }

  void display() {
    if (player == 1){
      stroke(0);
      fill(255, 0, 0);
      ellipse(x, y, diameter, diameter);
    }
    if (player == 2){
      stroke(0);
      fill(0, 0, 255);
      ellipse(x, y, diameter, diameter);
    }
  }
  
  void move() {  
    if (player == 1){
      if (keyPressed) {
        if (key == 'w' || key == 'W') {
          y = y - 5;
        }
        if (key == 'a' || key == 'A') {
          x = x - 5;
        }
        if (key == 's' || key == 'S') {
          y = y + 5;
        }
        if (key == 'd' || key == 'D') {
          x = x + 5;
        }
      }
    }
    
    if (player == 2){
      if (keyPressed) {
        if (keyCode == UP) {
          y = y - 5;
        }
        if (keyCode == LEFT) {
          x = x - 5;
        }
        if (keyCode == DOWN) {
          y = y + 5;
        }
        if (keyCode == RIGHT) {
          x = x + 5;
        }
      }
    }
  }
  
  void collision() {
    //actions after bumping into each of the four walls
    if (x < 0 || x > width || y < 0 || y > height) {
      if ((x <= (w1.x + (w1.w))) & ((w1.y - (w1.h)/2) <= y && y <= (w1.y + (w1.h)/2))) { //hitting the left wall
        x = width/2;
        y = height/2;
        score = score + 1;
        w1.h = w1.h - 50;
      }
      else if ((y >= (w2.y - (w2.h))) & ((w2.x - (w2.w)/2) <= x && x <= (w2.x + (w2.w)/2))) { //hitting the bot wall
        x = width/2;
        y = height/2;
        score = score + 1;
        w2.w = w2.w - 50;
      }
      else if ((x >= (w3.x - (w3.w))) & ((w3.y - (w3.h)/2) <= y && y <= (w3.y + (w3.h)/2))) { //hitting the right wall
        x = width/2;
        y = height/2;
        score = score + 1;
        w3.h = w3.h - 50;
      }
      else if ((y <= (w4.y + (w4.h))) & ((w4.x - (w4.w)/2) <= x && x <= (w4.x + (w4.w)/2))) { //hitting the top wall
        x = width/2;
        y = height/2;
        score = score + 1;
        w4.w = w4.w - 50;
      }
      
      //going out of bounds
      
      else {
        if (player == 1){
          stop();
          fill(0, 0, 255);
          rect(width/2, height/2, 640, 640);
          fill(255, 255, 255);
          textSize(32);
          text("Player 2 Wins!", width/2, height/2); 

        }
        else if (player == 2){
          stop();
          fill(255, 0, 0);
          rect(width/2, height/2, 640, 640);
          fill(255, 255, 255);
          textSize(32);
          text("Player 1 Wins!", width/2, height/2); 

        }
      }
    }
    
  }

}

Wall class code:

class Wall {

  float x;
  float y;
  float w;
  float h;
  int dir;

  Wall(float tempX, float tempY, float tempW, float tempH, int tempDir) {
    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    dir = tempDir;
  }

  void display() {
    rectMode(CENTER);
    stroke(0);
    fill(165,0,255);
    rect(x, y, w, h);
  }
  
  void move() {
    if (dir == 1){ //vertical walls
      int center = height/2;
      float amplitude = 400;
      float speed = .004;
      float granular = .001;
      float freq = frameCount*speed + x * granular;
      float adjustedHeight = noise(freq);
      adjustedHeight -= .5;
      adjustedHeight *= amplitude;
      y = center + adjustedHeight;
    }
    if (dir == 0){ //horizontal walls
      int center = width/2;
      float amplitude = 600;
      float speed = .002;
      float granular = .001;
      float freq = frameCount*speed + x * granular;
      float adjustedWidth = noise(freq);
      adjustedWidth -= .5;
      adjustedWidth *= amplitude;
      x = center + adjustedWidth;
    }
  }
}

 

Snake

For this weeks assignment I decided to create the popular Snake game. In the creative process I tried to optimize it and I am quite happy with the results. I created a simple class for a snake element and then reused it while creating food items.

To make the game even more optimized I decided to draw the snake in a specific fashion. When the snake eats their food, the food is not “added” to it. Rather than that, the last part of the snake is not removed from it a single time, as it would usually be. That makes the transition a lot smoother and also makes the code cleaner.

With regard to the hit boxes I made them simple as the game was designed on a 10px grid. As a result the snake elements are 10px/10px. Due to that, I could simply compare the X and Y dimensions of the Snake’s leading tile against food’s location, rather than comparing whole ranges, which would be much less efficient.

class snakeRect {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

score = 0;
food = new snakeRect(-10,-10);
vx = -10;
vy = 0;

snake = [new snakeRect(200, 200),
         new snakeRect(210, 200),
         new snakeRect(220, 200),
         new snakeRect(230, 200),
        ];

function setup() {
  createCanvas(400, 400);
  textSize(50);
  food.x = round(random(0, (width-10)/10))*10;
  food.y = round(random(0, (height-10)/10))*10;
}

function draw() {
  background(220);
  fill(255);
  textAlign(LEFT);
  text(score, 20, 50);
  if (isGameOver()){   
    textAlign(CENTER);
    translate(width/2, height/2);
    fill(255);
    text('Game Over', 0, 0);
    return;
  }
  
  drawSnake();
  drawFood();

  if (frameCount%5==0) {
    moveSnake();
  }
}

function getFood() {
  randX = round(random(0, (width-10)/10))*10;
  randY = round(random(0, (height-10)/10))*10;
  
  for(i=0; i<snake.length; i++) {
    if (snake[i].x==randX && snake[i].y==randY) {
      getFood();
    }
  }
  
  food.x = randX;
  food.y = randY;
}

function drawFood() {
  fill(255, 255, 0);
  rect(food.x, food.y, 10, 10);
}

function drawSnake() { 
  fill(200,200,0);
  for (i=0; i<snake.length; i++) {
      rect(snake[i].x, snake[i].y, 10, 10);  
  }
}

function moveSnake() { 
  newElem = new snakeRect(snake[0].x+vx, snake[0].y+vy);
  snake.unshift(newElem);

  if (snake[0].x === food.x && snake[0].y === food.y) {
    score+=10;
    getFood();
  }
  else {
    snake.pop();
  }
}

function keyPressed() {
  if (keyCode===LEFT_ARROW && vx!=10) {
    vx=-10;
    vy=0;
  }
  else if (keyCode === RIGHT_ARROW && vx!=-10) {
    vx=10;
    vy=0;
  }
  else if (keyCode === UP_ARROW && vy!=10) {
    vx=0;
    vy=-10;
  }
  else if (keyCode === DOWN_ARROW && vy!=-10) {
    vx=0;
    vy=10;
  }
}

function isGameOver() {  
  for (i=4; i<snake.length; i++)
  {    
    if (snake[i].x === snake[0].x && snake[i].y === snake[0].y) {
      return true;
    }
  }
  return snake[0].x<0 ||  snake[0].x>width-10 || snake[0].y<0 || snake[0].y>height-10;
}

 

I Ran Out of Creative Titles – Amina’s Game

After watching some of the Coding Train’s (Dan Shiffman) YouTube tutorials on OOP, I took my inspiration for the game from this purple rain. Except that instead of the falling droplets I decided to make falling balls of random colors, and the whole trick of the game is to catch all of them with a net.

I started by creating a class for the ball object, along with the functions to initialize the objects, make them fall, create a net, and check if the ball is caught by the net.

One of the things that I was not too sure about is whether I should have had my net as a separate class or a part of the Ball class. I chose to go with the latter, because it allowed me to have functions inside of one class that checked the position and the catch:

void makeNet() {
    fill(0);
    rectMode(CENTER);
    rect(posX, posY, netWidth, radiusX);
  }
  
  void checkNet() {
    if (locX + radiusX >= posX 
    && locX + radiusX <= posX + netWidth 
    && locY + radiusY == posY) {
      locX = -200;
      score++;
    }
  }

My second challenge was to connect the keyPressed() function to the class for the net to move. I was a bit confused about whether to make it a part of the class functions or let it be a function outside the class, so I started to experiment. Being a part of the Ball class, the function did not work properly when I pressed the necessary keys, so I let it be outside the class. However, that chunk of code still seems a bit inefficient to me so far:

void keyPressed() {
   if (keyPressed) {
     
    for(int i = 0; i < balls.length; i++){
      if (key == 'a'){
        balls[i].posX -= 100;
      }
      
      if (key == 'd'){
        balls[i].posX += 100;
      }
     }
   }
}

One of my main intentions for this game was to display the score, which is calculated based on the number of balls caught, on the console. However, I still could not figure out the best way to do it:

print(balls[i].score);

There is room for improvement in this code, so I hope to figure out by the end of the week!

// Declare the object class
class Ball {
  float radiusX, radiusY, locX, locY;
  color ballColor;
  int score;
  float posX, posY;
  float netWidth = 250;
  
  // Constructor 
  Ball () {
    radiusX = 50;
    radiusY = 50;
    locX = random(10, width-10);
    locY = random(height);
    ballColor = color(random(255), random(255), random(255));
    posX = width/2;
    posY = height-10;
  }
  
  // Make the object
  void makeBall() {
    fill(ballColor);
    stroke(1);
    ellipse(locX, locY, radiusX, radiusY);
  }
  
  // Updating location of the object
  void falling() {
    locY += 1;
    
    if (locY > height+radiusY/2) {
      locY = -radiusY*2;
    }
  }
  
  // Make the net
   void makeNet() {
    fill(0);
    rectMode(CENTER);
    rect(posX, posY, netWidth, radiusX);
  }
  
  // Check if the object is in the net
  void checkNet() {
    if (locX + radiusX >= posX 
    && locX + radiusX <= posX + netWidth 
    && locY + radiusY == posY) {
      locX = -200;
      score++;
    }
  }  
}


// Initialize an array of objects
Ball[] balls;



void setup(){
  size(1280, 720);
  // Put objects in the array
  balls = new Ball[10];
  for(int i = 0; i < balls.length; i++){
    balls[i] = new Ball();
  }
}

// Display and run the game
void draw(){
  background(255);
  for(int i = 0; i < balls.length; i++){
     balls[i].makeBall();
     balls[i].falling();
     balls[i].makeNet();
     balls[i].checkNet();
     print(balls[i].score);
  }
}

// Move the net if the keys are pressed
void keyPressed() {
   if (keyPressed) {
     
    for(int i = 0; i < balls.length; i++){
      if (key == 'a'){
        balls[i].posX -= 100;
      }
      
      if (key == 'd'){
        balls[i].posX += 100;
      }
     }
   }
}

You can watch the demo here:

Skippy the Stickman – Meera.

I believe that the toughest part of my process was trying to create something with the tools I have. I thought  to myself” what is the most convenient game anyone would ever want to play?”, and thought of just pressing the mouse in a repetitive way came to my mind. Since my game requires little effort from its user, it will have little effort done to it. Yet nevertheless, something will be done to it. The most prominent action that could occur on the scree is maybe a bouncing object or a jumping man. I took the harder one, the jumping man. I created his little plain world and made small boxes for him to jump over, but making him jump was so frustrating. I didn’t know how to make “mousePressed” create a jump for my poor stickman, so I decided to make him skip. Finally this was what I came up with:

 

float x = 56;
float a = 48;
float c = 46;
float v = 64;
float b = 66;
float y = 690;
float o = 750;
float u = 705;
float t = 725;
float r = 710;
float p = 762;



void setup(){
  size (800,800);
}

void draw(){

  // game background  


 //cement
  fill (108,107,107);
  rect(0,0,width,height);
 
  // boxes to jump over 
 fill( 172,102,22);
  square(10,741,50);
  square(200,741,50);
  square(380,741,50);
  square(560,741,50);
  square(745,741,50);
   
   //sky
  fill(135,206,250);
  rect(0,0,width,740);

//clouds
   // level one clouds 
    stroke(255);
    fill(255, 255, 255);
    // left cloud
    ellipse(45, 120, 126, 97);
    ellipse(107, 120, 70, 60);
    ellipse(-23, 120, 70, 60);
    
    // middle cloud
    ellipse(370, 100, 126, 97);
    ellipse(432, 100, 70, 60);
    ellipse(308, 100, 70, 60);
    //right cloud
    ellipse(670, 150, 126, 97);
    ellipse(740, 150, 70, 60);
    ellipse(606, 150, 70, 60);
    
// level two clouds 


  stroke(255);
    fill(255, 255, 255);
    // left cloud
    ellipse(80, 300, 126, 97);
    ellipse(150, 300, 70, 60);
    ellipse(10, 300, 70, 60);
    
    // middle cloud
    ellipse(370, 250, 126, 97);
    ellipse(432, 250, 70, 60);
    ellipse(308, 250, 70, 60);
    //right cloud
    ellipse(670, 300, 126, 97);
    ellipse(740, 300, 70, 60);
    ellipse(606, 300, 70, 60);
    
    
   //trees along the road 
   stroke(0);
   fill(51,102,0);
   triangle(30,740,57,640,85,740);
   triangle(107,740,134,640,162,740);
   triangle(184,740,211,640,239,740);
   triangle(539,740,566,640,594,740);
   triangle(616,740,643,640,671,740);
   triangle(693,740,720,640,748,740);

// stick man 
stroke(0);
fill(255, 255, 255);
//head
circle(x,690, 30);
//body
line(x,u,x,o);
//arms
//right
line(x,t,v,r);
//left 
line(x,t,a,r);
//legs
//right
line(x,o,b,p);
//left
line(x,o,c,p);

 x+=1; 
 v+=1; 
 c+=1;
 b+=1;
 a+=1;
}
 void mousePressed (){
 x+=100; 
 v+=100; 
 c+=100;
 b+=100;
 a+=100;
 }

:).

Piano – OOP

Control a “you” and release your “touch” to play some notes.
For this week’s assignment,  I used Object Oriented Programming to create a simple representation of a piano.

I was inspired by a similar concept I saw on Pinterest and I wanted to include the picture for inspiration credits but I couldn’t find it again!

Nevertheless, to do this, I  started off by making 3 classes in three different tabs. One for the piano, one for the person moving around (or “you”), and lastly one for the “touch” released by the person.

General Information

The Piano class is quite simple. It has a constructor and two functions.
The first function is just to draw the piano on the screen. While the second one is used when a piano key is pressed to make it grey and give it the illusion to have actually been pressed.
Here is the code for this:

class Piano{
  float pianoTop, pianoSide, keyWidth;
  
  //constructor
  Piano(){ 
  pianoTop = height/1.7;
  pianoSide = width/7;
  keyWidth = (width-(2*pianoSide))/13; //13 is the number of keys
  }
  
  //displaying the piano
  void drawPiano(){
    for (int i=0; i<13; i++){
      if (i==1 || i==3 || i==6 || i==8 || i==10){
        fill(0);
        stroke(0);
        strokeWeight(2);
        rect(pianoSide+i*keyWidth, pianoTop, keyWidth, (height-pianoTop)/1.4);
      }
      else{
        fill(255);
        stroke(0);
        strokeWeight(2);
        rect(pianoSide+ i*keyWidth, pianoTop, keyWidth, height-pianoTop);
      }
    }
  }
  //function that makes a pressed key grey 
  void pianoKeyPressed(int a){
    if (a==1 || a==3 || a==6 || a==8 || a==10){
      stroke(0);
      strokeWeight(2);
      fill(100);
      rect(pianoSide+a*keyWidth, pianoTop, keyWidth, (height-pianoTop)/1.4);
    }
    else{
      stroke(0);
      strokeWeight(2);
      fill(100);
      rect(pianoSide+ a*keyWidth, pianoTop, keyWidth, height-pianoTop);
    }
  
  }
  
}

Next, there is the You class. Here as well, there is a constructor along with three functions. The first one just displays an image/draws the “you”. The second one is to move it with the Left and Right arrow keys. And the last one is to return the x position of the You at a specific moment. This last function is needed for the touch. Since the touch is represented by a small circle that appears at the position of the person.
Here is the code for this class:

class You{
  float x, y, speed;
  int youWidth;
  float r, g, b;
  PImage img;
  
  //constructor
  You(){
    speed= 5;
    x= width/2;
    y= height/9;
    youWidth = 100;
    img = loadImage("square.png");
  }
  
  void displayYou(){
    image(img, x-youWidth/2, y, youWidth, youWidth);
    //rect(x-youWidth/2,y,youWidth,youWidth);
  }
  
  void controlYou(){
    if (keyPressed && keyCode == RIGHT){
      if(x < width - (piano.pianoSide)){
        x += speed;
      }
    }
    else if (keyPressed && keyCode == LEFT){
      if (x > piano.pianoSide){
        x -= speed;
      }
    }
  }
  
  float getYouPos(){
    return x;
  }


}

The final class is the Touch class. It has a constructor and two functions. The first function is used to display the touch at the position of the person when it is between the bottom of the person and the top border of the piano. And it also makes it disappear into the piano when it reaches the top border along with a small visual effect representing a touch.
(Note: each “touch” gets a random color.)
The second function is used to update the y-position of the touch.
This is the code for this class:

class Touch{
  float y, speed;
  int touchWidth;
  float r, g, b;
  boolean touchArrived;
  
  //constructor
  Touch(){
    speed = 5;
    y = height/9 + you.youWidth + touchWidth/2;
    touchWidth = 15;
    r = random(255);
    g = random(255);
    b = random(255);
    touchArrived = false;
    
  }
  
  void displayTouch(float pos){
    if (y <= piano.pianoTop){
      fill(r,g,b); //fill the touch with a random color
      noStroke();
      ellipse(pos,y,touchWidth,touchWidth);
    }
    //visual effect when the touch reaches the pressed key
    if (touchArrived){
      stroke(0);
      strokeWeight(3);
      line(pos, piano.pianoTop - 5, pos, piano.pianoTop-17);
      line(pos - 10, piano.pianoTop - 5, pos-20, piano.pianoTop-15);
      line(pos + 10, piano.pianoTop - 5, pos+20, piano.pianoTop-15);
    }
  }
  
  void moveTouch(){
    y += speed;
    touchArrived = y>= piano.pianoTop && y<(height-piano.pianoTop/2);
  }
  
}

In the main tab, instances of all of these classes were created. One for the piano, one for “you” and an ArrayList for all the “touches” that will be created throughout the program.
In draw() there is an if statement that will either display the Start Screen or the Piano Screen (the latter will be triggered when the mouse is clicked. This is done by a mouseClicked() function and a boolean variable.)
A keyPressed() function is also found in this main tab and it is responsible for creating a new Touch object every time the spacebar is pressed.
Finally, there is a function that checks no sound files overlap.
Here is the code for that:

//declaring global variables
import processing.sound.*;
SoundFile[] notes; //an array contaning all the sound files
boolean start;

Piano piano;
You you;
int touchCounter; 
ArrayList<Touch> touches; //an array for all the touches created
FloatList touchPositions; //an array for the x-position of each touch
float pos, temp1, temp2;



void setup(){
  size(1000,700);
  start=false;
  notes = new SoundFile[13];
  for(int i=0; i<13; i++){
    notes[i]= new SoundFile(this,"note"+str(i)+".mp3"); //adding all sound files to an array
  }
  piano= new Piano();
  you= new You();
  touches = new ArrayList<Touch>();
  touchPositions = new FloatList();
}


void draw(){
  background(255,243,249);
   
  //start screen
  if (!start){
    fill(0);
    textSize(20);
    textAlign(CENTER);
    text("Use the left and right arrow keys to move.",width/2 ,height/3);
    text("Press space to release your \"touch\" :)",width/2 ,height/2.7);
    text("Click to start playing!", width/2, height/1.8);
    textAlign(LEFT);
    textSize(15);
    text("(the piano.)", width/2, height/1.7);  
  }
  //when the mouse is clicked, the "game"(?) starts
  else{
    //draw piano
    piano.drawPiano();
    
    //drawing "you" and controlling it
    you.displayYou();
    you.controlYou();
    
    //drawing the touch and controlling it when the spacebar is pressed
    for (int i=0; i<touchCounter; i++){
      touches.get(i).displayTouch(touchPositions.get(i));
      touches.get(i).moveTouch();
      //adding the visual and sound effects when a note is played
      for (int j=0; j<13; j++){
          temp1 = piano.pianoSide+j*piano.keyWidth; //temporary value to find the start border of the pressed key
          temp2 = temp1 + piano.keyWidth; //temporary value to find the end border of the pressed key
          if (touchPositions.get(i)>temp1 && touchPositions.get(i)<temp2 && touches.get(i).touchArrived){
            piano.pianoKeyPressed(j);
            checkSilence(j);
            break;
          }
      }
    }
  }
}

//This is to check when the spacebar is pressed
//and add a new touch to the touches-array everytime
void keyPressed(){
  if (key==' '){
    touches.add(new Touch());
    pos = you.getYouPos(); //SAVE the value of the you position at the time the key is pressed
    //and add it to the positions FloatList
    touchPositions.append(pos);
    touchCounter+=1; //increasing the touchCounter to be ready for next value
  }
}

void mouseClicked(){
  start = true;
}

//function that makes sure no sounds are playing before playing the pressed one
void checkSilence(int index){
  for (int i=0; i<13; i++){
    if (notes[i].isPlaying()){
      notes[i].stop();
    }
  }
  notes[index].play();
}

Difficulties

While trying to get the program to work. I ran into three main difficulties.

  • The first one was that every time I press the space bar to create a new Touch, the previous one would disappear. To fix this, I used an ArrayList and stored every created Touch object there.
  • The second one was that, after pressing the spacebar and making a touch appear, moving the person moves the Touch objects along with it (because they use the x-position of the person as the parameter). So to fix this, every time the spacebar is pressed, I stored the x-position of the person in a temporary value and appended it to a FloatList (It ends up containing all Touch objects’ positions that can easily be accessed by indices.)
  • The third and final one was that the sounds made by pressing a piano key were overlapping, thus creating a lot of noise. To stop this, I included a function that lets a note be played only after it has stopped the previous one from playing.

All of these failed attempts can be visualized, respectively, in this video:

Final Outcome

Here is how it turned out in the end 🙂