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 🙂

Week 3 : Object Oriented Programming

Originally, I wanted to make the game ‘Space Invaders,’ but with my own kind of twist. I planned to get all the objects working before i look through my digital art designs to see any recurring themes i could implement into the game.

Starting with the set of ‘aliens,’ I initially created a for loop inside a foor loop to create a grid of ‘aliens’ that randomly moved in a uniform manner. The plan was that the bottom row of the ‘aliens’ would be shooting at the players’ character. The player had to miss all the bullets, and also shoot back at the ‘aliens’ to kill them.

After doing the grid, finally getting them to randomly move in a uniform manner, and also getting the player to move their character left to right, I was at a dead end. I had so many bugs, obstacles, and things that I wasn’t sure about. I believe if I had more time, I could have solved it, but I still wanted a working game, so I decided to change it.

After letting my original plan go, I decided to do the basic pong- game. Where balls are falling in random order, and the goal is to catch it with your slider. It took some time for me to transition from the original code to the new one, but I finally reached a conclusion where my game was working. Ideally I could add a time limit and a score, but I guess it would just have to wait till later.

I still faced some difficulties, especially figuring out how to get the ball to bounce back from only the slider, but managed to do it. My only obstacle now is actually playing the game – It appears I’m really bad at it, so forgive me in the video. !

// Calling the player class
Player player;
 
// calling the shooter class as an array
Shooters [] shooters ;


  void setup(){
    size (1000,1000);
    ellipseMode (CENTER);
    shooters = new Shooters [20];
    player = new Player ();
    
    // creating a for loop to create an array of shooters
    for (int i = 0; i<10; i ++){
      shooters [i] = new   Shooters (); 
  }
  }
  
  void draw (){
    background (0, 0, 0);
    player.drawPlayer ();
    player.checkEdge();
    // creating a for loop for the shooters 
    for (int i = 0; i<10; i ++){
      shooters[i].drawShooters();
      shooters[i].update ();
      shooters[i].checkEdge();
    keyPressed();
  }
  }
  
  // to be able to move the rectangle
  void keyPressed (){
    if (keyPressed && keyCode == LEFT) {
      player.playerSpeed = -3;
      player.update();
    }
    
     if (keyPressed && keyCode == RIGHT) {
      player.playerSpeed =3;
      player.update();
 
    }
 
  }
  //////////////////////////////
// Tab Player
class Player {
  float playerX, playerY, w, h; 
  float playerSpeed;
  
  Player(){
    playerX = width/2;
    playerY = height - (height/6);
    w = 100;
    h = 25;
    
  }
  
  void drawPlayer (){
    noStroke();
    fill (255, 255, 255);
    rect (playerX, playerY, w, h);
  }
  
  void update (){
    playerX += playerSpeed;
  }
  
  
  // Honestly, this didnt work. I tried to make the rectangle stop when it reached the edge. 
    void checkEdge (){
    if (playerX > width - 100){
      print("stop");
      playerSpeed = 0 ;
      update();
    }
    }
  

  }
////////////
//Tab Shooters
class Shooters {
  float shootersRadius;
  float locX, locY;
  float y, x, xspeed, yspeed;
  
  // creating the shooters and having them move at a different speed each time
  Shooters(){
    x = 0;
    y = 0; 
    xspeed = random (3,5); 
    yspeed = random (1,3);

  
  }
  
    void update (){
      x = x + xspeed; 
      y = y + yspeed; 
      }
  
  void checkEdge (){
 
    // setting the dimensions
   if (x > width || x <0 ) {
     xspeed = xspeed* -1;
   }
   if ( y < 0 ) {
     yspeed = yspeed*-1;
  }
// creating the boundaries for the rectangle (if it hits the rectangle it bounces)
  if ( y > player.playerY && y < width){
    if (x > player.playerX && x < player.playerX + player.w) {
      xspeed = xspeed* -1;
    yspeed = yspeed*-1;
    }
  }
  }
  
  void drawShooters(){
    noStroke();
    fill ( 255, 215, 0);
    circle ( x, y, 32 );
  }
    }

 

Back To Childhood: Tic-Tac-Toe

For this weeks assignment I decided to recreate a game that I played alot with my siblings when power was out during hurricanes seasons in a digital. I decided to make the game tic-tac-toe however instead of uses X’s and  O’s I decided that each piece will be a square box that it will be filled in each of the spots. The reason for this was utilize the entire canvas that processing provide.

I utilized a snapping motion to determine where the player was currently

was and the piece would be put should the player click the mouse button.

For the object oriented portion of the game all of the game logic is encapsulated in a game class. The game class uses a 2D-array to store the “pieces” either as a 0 for red, 1 for green or a -1 for empty. This array is used during the entire time that the game is in session to render the pieces as well do various logic work. For instance, if the value is not -1 then the piece should not be played. The game class also used this array to check the winning condition of the game.\\

void setup() {
  size(1000, 1000);
}
//global variables
float boxWidth = 1000/3;
Game myGame = new Game();
int turn = 0; //0 is red, 1 is green
boolean gameRunning = true;
String gameWonBy = "";
int piecesIn = 0;


void draw() {
  background(255, 255, 255);
  if (gameRunning == true)
  {
    cursorHover();
  }

  board();
  myGame.colorPieces();
  myGame.checkWin();
  pushStyle();
  textSize(32);
  textAlign(CENTER);
  //fill(255, 255, 255);
  fill(0, 0, 0);
  if (gameWonBy == "Red") {
    text("This game was won by red", width/2, height/2);
    //println("should display text");
  } else if (gameWonBy == "Green") {
    text("This game was won by green", width/2, height/2);
    //println("should display text");
  } else if (gameWonBy == "Tie") {
    text("This game ended in a tie", width/2, height/2);
    //println("should display text");
  }
  popStyle();
}

//functions
void board() {
  pushStyle();
  strokeWeight(3);
  //first vertical line
  line(width/3, 0, width/3, height);
  //second vertical line
  line(2* width/3, 0, 2*width/3, height);

  //first horizontal line
  line(0, height/3, width, height/3);
  //second horizontal line
  line(0, 2*height/3, width, 2*height/3);
  popStyle();
}

void cursorHover() {
  //make the light green/red box over the position
  if (turn%2==0)
  {
    fill(255, 0, 0, 180);
  } else if (turn%2==1) {
    fill(0, 255, 0, 180);
  }
  //origin of the hover box
  int[] origin = getIndices();
  //draw the position
  rect(origin[1]*boxWidth, origin[0]*boxWidth, boxWidth, boxWidth);
}

void mouseClicked() {
  myGame.updatePosition(getIndices());
  //myGame.printPositions();
}

int[] getIndices() {
  int[] indices = new int[2];
  //x is index 0, y is index 1
  indices[0] = floor(mouseY/boxWidth);
  indices[1] = floor(mouseX/boxWidth);
  return indices;
}




//classes
class Game {
  int[][] positions = new int[3][3];
  Game() {
    for (int i=0; i<positions.length; i++) {
      for (int j=0; j<positions[i].length; j++) {
        positions[i][j]=-1;
      }
    }
  }
  void updatePosition(int[] indices) {
    if (gameRunning)
    {
      if (positions[indices[0]][indices[1]] == -1) {
        positions[indices[0]][indices[1]] = turn%2;
        turn=turn+1;
        piecesIn+=1;
      }
    }
  }

  void printPositions() {
    for (int i=0; i<positions.length; i++) {
      for (int j=0; j<positions[i].length; j++) {
        //print(positions[i][j]+" ");
      }
      //println();
    }
    //println();
  }

  void colorPieces() {
    for (int i=0; i<positions.length; i++) {
      for (int j=0; j<positions[i].length; j++) {
        //if position is 0 then color the position red
        if (positions[j][i]==0) {
          pushStyle();
          fill(255, 0, 0);
          rect(i*boxWidth, j*boxWidth, boxWidth, boxWidth);
          popStyle();
        } 
        //if position is 1 then color the position green
        else if (positions[j][i]==1) {
          pushStyle();
          fill(0, 255, 0);
          rect(i*boxWidth, j*boxWidth, boxWidth, boxWidth);
          popStyle();
        }
      }
    }
  }

  void checkWin() {
    //tie check
    if (piecesIn == 9 && gameRunning==true) {
      gameRunning = false;
      gameWonBy = "Tie";
      //println("Tie");
    }
    //row check
    for (int i=0; i<3; i++) {
      if (positions[i][0]==0 && positions[i][1]==0 && positions[i][2]==0) {
        gameRunning = false;
        gameWonBy = "Red";
        //println("gameWonBy Red");
      } else if (positions[i][0]==1 && positions[i][1]==1 && positions[i][2]==1) {
        gameRunning = false;
        gameWonBy = "Green";
        //println("gameWonBy Green");
      }
    }
    // column check
    for (int i=0; i<3; i++) {
      if (positions[0][i]==0 && positions[1][i]==0 && positions[2][i]==0) {
        gameRunning = false;
        gameWonBy = "Red";
        //println("gameWonBy Red");
      } else if (positions[0][i]==1 && positions[1][i]==1 && positions[2][i]==1) {
        gameRunning = false;
        gameWonBy = "Green";
        //println("gameWonBy Green");
      }
    }

    // diagonal check y=-x
    if (positions[0][0]==0 && positions[1][1]==0 && positions[2][2]==0) {
      gameRunning = false;
      gameWonBy = "Red";
      //println("gameWonBy Red");
    } else if (positions[0][0]==1 && positions[1][1]==1 && positions[2][2]==1) {
      gameRunning = false;
      gameWonBy = "Green";
      //println("gameWonBy Green");
    }

    // diagonal check y=x
    if (positions[0][2]==0 && positions[1][1]==0 && positions[2][0]==0) {
      gameRunning = false;
      gameWonBy = "Red";
      //println("gameWonBy Red");
    } else if (positions[0][2]==1 && positions[1][1]==1 && positions[2][0]==1) {
      gameRunning = false;
      gameWonBy = "Green";
      //println("gameWonBy Green");
    }
  }
}

 

Week 3: Object-oriented Programming

This weeks exercise took a lot of time, or should I rather say, I spend a lot of time playing around and getting to know Processing better? I rewatched and followed along the different video tutorials by The Coding Train which helped a lot but also led to endless possibilities.

I took inspiration from a Ginkgo leaf and the kaleidoscopes I used to like as a child. I wanted to create several layers of ginkgo leaves that rotate in different directions but are layered on top of one another in the center of the screen. However, when I started writing the code, other ideas and possibilities came to my mind so the first challenge was to make decisions. In-between I tried something else and my final version is also not quite what I initially had in mind but I was able to learn along the way.

The second challenge was whether to start with highest part of the code hierarchy that should just look simple and ‘pretty’ at the end or with creating my own objects and functions. As I am still pretty new to processing, I had no ‘best practice’ but after this exercise I think it’s easier to start with the “pretty” part and then build the “background code” depending on how I want the hierarchy to look like.

My code for this exercise is not fully polished and simplified yet because I ran into some difficulties where I will need to check ‘pass by reference’ and ‘pass by copy’ again but enjoy this little Ginkgo leaf inspired kaleidoscope which reacts to the position of the mouse.

This was the first attempt of creating the basic shape.
This is a screenshot from the final effect.

This is the main code, followed by the code on the additional tab for the Leaf class.

float x, y, r;
float a, b;
float angle;

Leaf l1;
Leaf l2;
Leaf l3;

void setup() {
  size(640, 640); //Instagram format
  background(0);
  l1 = new Leaf();
  l2 = new Leaf();
  l3 = new Leaf();
}

void draw() {
  background(0);

  translate(width/2, height/2); //this centers the shape on the screen

  push(); //I am using push() and pop() because otherwise the scale would apply to the previous value. need to solve this.
  
  l1.display(mouseY/250); //this will change the size according to the mouse position
  pop();

  push();
  rotate(angle);
  angle = angle + 0.5;
  l2.display(1.5);
  pop();

  push();
  rotate(-angle);
  angle = angle + 0.3;
  l3.display(mouseX/100); //this will change the size according to the mouse position
  pop();
}
class Leaf {
  float a;
  float r;
  float angle;
  float s;

  Leaf() { //this sets up the parameters that we can later determine when calling the function
  }

  void display(float tempS) { //this is the basic shape of the leaf
    //translate(width/2, height/2);
    

    s = tempS;
    scale(s);


    stroke(255);
    strokeWeight(0.5); //thin stroke weight to make leaf structure finer
    fill(255);
   
    //this is the basic shape of the leaf (somewhat hardcoded still)
    
    //these are the basic two intersecting lines with a stronger strokeWeight than the other lines
    line(-50, -50, +50, +50);
    line(+50, -50, -50, +50);
    
    strokeWeight(0.01); //this makes the extra lines thinner
    line(-50+r, -50, +50-r, +50);
    line(-50, -50+r, +50, +50-r);
    
    line(+50-r, -50, -50+r, +50);
    line(+50, -50+r, -50, +50-r);

    ellipse(-50, -50, r*2, r*2);
    ellipse(+50, +50, r*2, r*2);
    ellipse(+50, -50, r*2, r*2);
    ellipse(-50, +50, r*2, r*2);
    
    //this adds a smaller ellipse into the bigger ellipse
    fill(255);
    
    ellipse(-50, -50, r*1.5, r*1.5);
    ellipse(+50, +50, r*1.5, r*1.5);
    ellipse(+50, -50, r*1.5, r*1.5);
    ellipse(-50, +50, r*1.5, r*1.5);
    
    r=15;
  }
  
  void move() {
    rotate(angle);
    angle = angle + 1;
  }
  
}

 

Links from class today