Game using OOP

Initially, I wanted to create an art piece because that is what I feel more comfortable coding. However, I also wanted to try something new and outside of my comfort level, so I chose to re-create a game that I knew. I wanted to re-create Flappy Bird, however, I found it extremely challenging to implement logic into my code. Especially when it came to making the ball not go below or above the pillars if it touches the pillars. I wasn’t able to solve this problem on time, so I decided to make the ball bounce on the racket. In addition, in the instructions, I asked a friend to keep track of the score, which also allows for a friendlier, interactive match.

I didn’t have a solid understanding of classes or OOP. After talked to Aaron an hour before class started, I realized that I created my code using functions, and not classes.

Here is my code for the project, using functions:

int gameScreen = 0;
float ballX, ballY;
float ballSize = 20;
int ballColor = color(255,255,0);
float gravity = 1;
float ballSpeedVert = 0;
float airfriction = 0.0001; //air resistance andfriction is important, ball doesn't just bounce up and down at same level, it reduces height as it bounces more.
float friction = 0.1; //surface friction
color racketColor = color(255,105,180); //platform ball bounces on
float racketWidth = 100;
float racketHeight = 10;
int racketBounceRate = 20;
float ballSpeedHorizon = 10;

//wall
int wallSpeed = 5;
int wallInterval = 1000;
float lastAddTime = 0;
int minGapHeight = 200;
int maxGapHeight = 300;
int wallWidth = 80;
color wallColors = color(0);
ArrayList<int[]> walls = new ArrayList<int[]>(); //list to keep data for gap between two walls. contains gap wall X, gap wall Y, gap wall width, gap wall height)

void setup() {
  size(500, 500);
  ballX=width/4;
  ballY=height/5;
}

void draw() {
  if (gameScreen == 0) {
    initScreen();
  } else if (gameScreen == 1) {
    gameScreen();
  } else if (gameScreen == 2) {
    gameOverScreen();
  }
}

void initScreen() {
  background(0);
  textAlign(CENTER);
 text("Don't let the ball touch the pillars. Make a friend keep track of your score.", height/2, width/2);
}
void gameScreen() {
  background(0,255,255);
  drawBall();
  applyGravity();
  keepInScreen();
  drawRacket();
  watchRacketBounce();
  applyHorizontalSpeed(); //for horizontal movement of ball
  wallAdder(); //adds new walls in every wallInterval millisecond
  wallHandler();
}
  
void gameOverScreen() {
}

public void mousePressed() { //what does public void mean
  // if we are on the initial screen when clicked, start the game
  if (gameScreen==0) {
    startGame();
  }
}

void startGame() { //necessary variable to start the game
  gameScreen=1;
}

void drawBall() {
  fill(ballColor);
  ellipse(ballX, ballY, ballSize, ballSize);
}

void applyGravity() {
  ballSpeedVert += gravity; //ballSpeedVert is -1. adding gravity to ballSpeedVert = it starts to get close to 0, becomes 0, then will start increasing again.
  ballY += ballSpeedVert; //vertical speed of ball added to Y coordinate of ball
  ballSpeedVert -= (ballSpeedVert * airfriction);
}

void makeBounceBottom(float surface) { //why is surface incorporated here? what is surface?
  ballY = surface-(ballSize/2);
  ballSpeedVert*=-1; //to bounce ball we move the ball to exact location where it had to bounce and multiply vertical speed with use of -1
  ballSpeedVert -= (ballSpeedVert * friction);
}

void makeBounceTop(float surface) { //why is surface incorporated here?
  ballY = surface+(ballSize/2);
  ballSpeedVert*=-1;
  ballSpeedVert -= (ballSpeedVert * friction);
}

void makeBounceLeft(float surface) {
  ballX = surface+(ballSize/2);
  ballSpeedHorizon*=-1;
  ballSpeedHorizon -= (ballSpeedHorizon * friction);
}
void makeBounceRight(float surface) {
  ballX = surface-(ballSize/2);
  ballSpeedHorizon*=-1;
  ballSpeedHorizon -= (ballSpeedHorizon * friction);
}

// keep ball in the screen
void keepInScreen() {
  // ball hits floor
  if (ballY+(ballSize/2) > width) {  //checking if ballY+radius less than height
    makeBounceBottom(width);
  }
  // ball hits ceiling
  if (ballY-(ballSize/2) < 0) { //checking if ballY-radius is more than 0
    makeBounceTop(0);
}
    if (ballX-(ballSize/2) < 0) {
      makeBounceLeft(0);
    }
    if (ballX+(ballSize/2) > width) {
      makeBounceRight(width);     
    }
}

void drawRacket() {
  fill(racketColor);
  rectMode(CENTER);
  rect(mouseX, mouseY, racketWidth, racketHeight);
}

void watchRacketBounce() { //makes sure racket and ball collide LOOK AT TUTORIALA GAIN
  float overhead = mouseY - pmouseY;
  if ((ballX+(ballSize/2) > mouseX-(racketWidth/2)) && (ballX-(ballSize/2) < mouseX+(racketWidth/2))) { //x coord. of right side of ball is greater than x coord. of left side of racket and other way around
    if (dist(ballX, ballY, ballX, mouseY)<=(ballSize/2)+abs(overhead)) { //distance between ball and racket is smaller than or equal to radius of ball (hence colliding)
      makeBounceBottom(mouseY); //hence this bounce method is called
      // racket moving up
      if (overhead<0) { //stores coordinates of the mouse at the previous time frame. Sometimes ball moves so fast that distance between ball and racket cant be correctly calculated between frames. so we take overhead value in between frames to detect difference. overhead value also detects negative value --stimulates racket effect.
        ballY+=overhead; //less than 0 means mouse is below in previous frame and racket is moving up
        ballSpeedVert+=overhead; //adds extra speed to ball to stimulate effect of hitting ball w racket
        if ((ballX+(ballSize/2) > mouseX-(racketWidth/2)) && (ballX-(ballSize/2) < mouseX+(racketWidth/2))) {  //edges of rack should give ball a more horizontal speed & middle should have no effect
          if (dist(ballX, ballY, ballX, mouseY)<=(ballSize/2)+abs(overhead)) { 
            ballSpeedHorizon = (ballX - mouseX)/5;
          }
        }
      }
    }
  }
}

void applyHorizontalSpeed() {
  ballX += ballSpeedHorizon;
  ballSpeedHorizon -= (ballSpeedHorizon * airfriction);
}

void wallAdder() {
  if (millis()-lastAddTime > wallInterval) { //if millis minus last added millisecond is larger than interval value, it is time to add new wall
    int randHeight = round(random(minGapHeight, maxGapHeight));
    int randY = round(random(0, height-randHeight));
    // {gapWallX, gapWallY, gapWallWidth, gapWallHeight}
    int[] randWall = {width, randY, wallWidth, randHeight}; 
    walls.add(randWall);
    lastAddTime = millis();
  }
}

void wallHandler() { //loops though each item. it removes each wall
  for (int i = 0; i < walls.size(); i++) {
    wallRemover(i);
    wallMover(i);
    wallDrawer(i);
    watchWallCollision(i);
  }
}
void wallDrawer(int index) {
  int[] wall = walls.get(index);
  // get gap wall settings 
  int gapWallX = wall[0];
  int gapWallY = wall[1];
  int gapWallWidth = wall[2];
  int gapWallHeight = wall[3];
  // draw actual walls
  rectMode(CORNER);
  fill(wallColors);
  rect(gapWallX, 0, gapWallWidth, gapWallY);
  rect(gapWallX, gapWallY+gapWallHeight, gapWallWidth, height-(gapWallY+gapWallHeight));
}

void wallMover(int index) {
  int[] wall = walls.get(index);
  wall[0] -= wallSpeed;
}
void wallRemover(int index) {
  int[] wall = walls.get(index);
  if (wall[0]+wall[2] <= 0) {
    walls.remove(index);
  }
}

void watchWallCollision(int index) { //gets called for each wall on each loop. take coordinates of wall (top and bottom) and check if coordinates of balls collifes w walls
  int[] wall = walls.get(index);
  // get gap wall settings 
  int gapWallX = wall[0];
  int gapWallY = wall[1];
  int gapWallWidth = wall[2];
  int gapWallHeight = wall[3];
  int wallTopX = gapWallX;
  int wallTopY = 0;
  int wallTopWidth = gapWallWidth;
  int wallTopHeight = gapWallY;
  int wallBottomX = gapWallX;
  int wallBottomY = gapWallY+gapWallHeight;
  int wallBottomWidth = gapWallWidth;
  int wallBottomHeight = height-(gapWallY+gapWallHeight);

  if (
    (ballX+(ballSize/2)>wallTopX) &&
    (ballX-(ballSize/2)<wallTopX+wallTopWidth) &&
    (ballY+(ballSize/2)>wallTopY) &&
    (ballY-(ballSize/2)<wallTopY+wallTopHeight)
    ) {
    // collides with upper wall
  }
  
  if (
    (ballX+(ballSize/2)>wallBottomX) &&
    (ballX-(ballSize/2)<wallBottomX+wallBottomWidth) &&
    (ballY+(ballSize/2)>wallBottomY) &&
    (ballY-(ballSize/2)<wallBottomY+wallBottomHeight)
    ) {
    // collides with lower wall
  }
}

By the middle of this week, I will convert this code to be structured with OOP and paste it below.

Flappy Bird is a happy bird

I wanted to make a game so I did. My version of flappy bird is really similar to the original one and I am happy with the final version. It is very playable and fun. However, there are a few potential improvements I could have made but simply did not have time.

  1. I did not add a replay function to my game. Ideally, a button is clicked after each death and the player is able to restart the game.
  2. In my code, I should have made a Game class, where initializing and terminating the game takes place. This makes my main file a lot longer than it needs to be.

My full code/images/sounds can be found on

https://github.com/ross67/IntroToIm/tree/master/flappyBird

//main 
import processing.sound.*;
SoundFile hit;
SoundFile die;
SoundFile point;
SoundFile wing;

PImage backgroundImg;
PImage img1;
PImage img2;
PImage img3;
PImage img;
PImage tube1;
PImage tube2;
int background =0;
boolean state = false;
boolean gameOver = false;
float speed = 0;
float gravity = 0.1;
int score = 0;
int hSpeed = 2;


float x = 50;
float y = 200;

int tubeLength;

Bird bird;
Tube tube;

ArrayList<Tube> tubeListTop;
ArrayList<Tube> tubeListBot;

void setup(){
 size(600,600);
 //size(1440,900);
 backgroundImg = loadImage("bg.png");
 img1 = loadImage("upflap.png");
 img2 = loadImage("midflap.png");
 img3 = loadImage("downflap.png");  
 tube1 = loadImage("tube1.png"); 
 tube2 =loadImage("tube2.png");
 tubeListTop = new ArrayList<Tube>();
 tubeListBot = new ArrayList<Tube>();
 img = img3;
 
 hit = new SoundFile(this, "hit.wav");
 die = new SoundFile(this, "die.wav");
 point = new SoundFile(this,"point.wav");
 wing = new SoundFile(this, "wing.wav");
 

 
 for (int i=0; i<4;i++){
  tubeLength =int(random(120,225));
  tubeListTop.add(new Tube(660+180*i,0,60,tubeLength, hSpeed)); 
}

for (int i=0; i<4;i++){
  tubeLength =int(random(120,225));
  tubeListBot.add(new Tube(660+180*i,505-tubeLength,60,tubeLength,hSpeed));   
}

}


  void draw(){ 
    
  if(!gameOver){
    image(backgroundImg,0,0);
    
    bird = new Bird(x, y);
    textSize(20);
    fill(0, 102, 153);
    text("PRESS SPACEBAR TO FLY", 80,580);
    fill(255,0,0);
    text("Socre: " + score, 450, 580);

  
    //if(keyPressed==true){ // use keyboard to move bird
    //  if(key == 'w'){
    //     y--; 
    //  }else if(key== 'a'){
    //     x--; 
    //  }else if(key=='d'){
    //   x++; 
    //  }else if(key=='s'){
    //   y++; 
    //  }
    //}
   for(Tube tube:tubeListTop){
     
     if(tube.locx<-60){
      tube.setX(680); 
     }
     
     tube.draw();
     
   }
    

   for(Tube tube:tubeListBot){
     
     if(tube.locx<-60){
      tube.setX(680); 
     }
     
     if (bird.locx == tube.locx){
      score++; 
      point.play();
     }

     tube.drawInverse();
     
   }
   
   
  }else{
     
    textSize(38);
    text("GAME OVER",180,270);
    textSize(16);
    text("restart the program to try again",170,290);
   }
   
    // Add speed to location.
      y = y + speed;

  // Add gravity to speed.
     speed = speed + gravity;
     
    if (y > height-123) {
    // Multiplying by -0.40 instead of -1 slows the object 
    // down each time it bounces (by decreasing speed).  
    // This is known as a "dampening" effect and is a more 
    // realistic simulation of the real world (without it, 
    // a ball would bounce forever).
    speed = speed * -0.40;
    y = height-123;
  }
  
   bird.draw(img);
   
   for(Tube tube:tubeListTop){
            
        if(bird.onCollision(tube)&&!gameOver){
            gameOver = true;
               hit.play();
               delay(100);
               die.play();
           }
      
    }  
    
     for(Tube tube:tubeListBot){
            
        if(bird.onCollision(tube)&&!gameOver){
            gameOver = true;
               hit.play();
               delay(100);
               die.play();
           }
      
    }  

  }
  
void keyPressed(){
  
  img = img1;

  wing.play();
}
 
 
 
void keyReleased(){  
    y = y-30;
    speed = speed *0.05;
    img = img3;
  }
//classes

class Bird{
  
  float locx, locy;

  
  Bird(float x,float y){
    locx = x;
    locy = y;    
  }
    
  void draw(PImage img ){
    
    image(img,locx,locy);
    
  }
    
  boolean onCollision(Tube a) {

  // are the sides of one rectangle touching the other?

  if (locx + 36 >= a.locx &&    // r1 right edge past r2 left
      locx <= a.locx + a.xlen &&    // r1 left edge past r2 right
      locy + 26 >= a.locy &&    // r1 top edge past r2 bottom
      locy <= a.locy + a.ylen) {    // r1 bottom edge past r2 top
        return true;
  }
  return false;
}
  
//http://www.jeffreythompson.org/collision-detection/rect-rect.php
  
}

class Tube{
 int locx, locy, xlen, ylen, hSpeed;
 
 Tube(int x,int y, int xl, int yl, int hs){
   locx = x;
   locy = y;
   xlen = xl;  
   ylen = yl;
   hSpeed = hs;
 }
 
   void draw(){   
    image(tube1,locx,locy,xlen,ylen);
    locx -= hSpeed;
  }
  

  void drawInverse(){
    image(tube2,locx,locy,xlen, ylen);
    locx -= hSpeed;

  }
  
  void setX(int x){
    locx =x;
  }
      
}

 

Art Piece(Edited; Read New Version After Asterisk)

When I started this assignment, I knew I really wanted to make an interactive art piece for a website I am making for another class.(CommLab)

Examples of these can be found on Pierre or Aaron’s websites:

Aaron’s: http://aaron-sherwood.com/

Pierre’s: https://pierredepaz.net/

 

This led me to bite off waay more than I could chew.

I was inspired by this image:

I wanted to make something like this that would happen when a mouse rolled/hovered over certain points. I also wanted to make it in a rectangular shape similar to the one found on Pierre’s website, as it would work as a header for my site.

Boy did I pick the wrong thing.

Let me tell you what was so hard about this:

1) I had trouble randomizing dots that would appear in a circular form as in the gif above. I could get them to appear at random, but not contained in a certain area.

2) It was actually pretty hard just to get the dots to be visible actually, so I ended up making the points into crosses.

3)I couldn’t get the image to change when the mouse hovers over certain points in the code, only a general area around and above the image.

4) I couldn’t get multiple random line segments at points, only a 1:1 ratio.

5) I also didn’t know how to show the movement of the line, rather than to just have it drawn and connected to the points.(ie, show it actually moving and connecting to the other point.)

And so, here is the finished (sad) product:

DotRect rect1;

void setup (){
  fullScreen();
  //size(640, 480);
  int rectX = 450;
  int rectY= 600;
  int amount = 50;
  rect1 = new DotRect(width/25 +rectX,height-rectY, amount);
 
}
void draw (){
  background(#35465c);
  rect1.draw();
}

void mouseMoved(){
  rect1.check(mouseX,mouseY);
}
class DotRect {
  int locX, locY, amount, seed;
  //consructor
  DotRect(int x, int y, int a) {

    locX = x; 
    locY = y;
    amount = a;
    seed=0;
  }
  void draw() {
    pushMatrix();
    translate(locX, locY);
    for (int i=0; i<50; i++)
    {


      stroke(255);
      float x = random(locX);
      float y = random(locY);
      float x2 = random(locX);
      float y2 = random(locY);
      for(int m =0; m<4; m++)
      {
      point(x+m, y);
      point(x2+m, y2);
      }
      for(int m =0; m<4; m++)
      {
      point(x, y+m);
      point(x2, y2+m);
      }
      for(int m =0; m<4; m++)
      {
      point(x-m, y);
      point(x2-m, y2);
      }
      for(int m =0; m<4; m++)
      {
      point(x, y-m);
      point(x2, y2-m);
      }
      line(x,y, x2, y2);
    
    }
    delay(100);
    popMatrix();
  }
  void check(int x, int y) {
    if ((dist(x, y, locX, locY) < x) && (dist(x, y, locX, locY)<y) )
    {
      seed = millis();
    }

}

}

So what did I learn?

This was not as easy as I believed it to be, and I am sorely disappointed with my outcome.

 

**********************************************************

PLEASE READ: EDITED

So I went back and fixed my code. (After a lot of time and help from Mateo; credit to him where it is due.)

ArrayList<Dot> dots;

void setup() {
  size(1200, 200); //screen size

  dots = new ArrayList<Dot>();
  for (int i = 0; i < 50; ++i) {
    dots.add(new Dot(random(width), random(height), 5));//adds and instantiates new Dot object into the array list
  }
}

void draw() {
  background(0);
  stroke(255);
  connect();
  for (int i = 0; i < dots.size(); ++i) {
    dots.get(i).move();//makes the Dots move
    dots.get(i).render();//draws the  the Dots
  }
}

void connect() {
  int count =0; //used to limit the connecting lines between Dots
  for (int i = 0; i < dots.size(); ++i) {
    for (int j = 0; j < dots.size(); ++j) {
      if (count<=5) // limits the lines
      {
        if (dist(dots.get(i).x, dots.get(i).y, dots.get(j).x, dots.get(j).y) < 100
          && dist(dots.get(i).x, dots.get(i).y, mouseX, mouseY) < 40) {
          line(dots.get(i).x, dots.get(i).y, dots.get(j).x, dots.get(j).y);
          count ++;
//the ifs work to check if the mouse is above the area around the dots and then draws the line
        }
      }
    }
  }
}



class Dot {
  float x, y, r;
  float seedX, seedY; //needed to vary frameCount

  Dot(float _x, float _y, float _r) {
    x = _x;
    y = _y;
    r = _r;
//takes the x,y,and r values from the main program and brings them into this obj

    seedX = random(10);
    seedY = random(10);
  }

  void render() { 
    fill(255);
    ellipse(x, y, r, r);
  }

  void move() {
    x += map(noise(seedX + frameCount*0.029), 0, 1, -1, 1); //changes the x
    y += map(noise(seedY + frameCount*0.012), 0, 1, -1, 1); //changes the y such that they will move in a nice, random pattern
    //the ifs below allow for the dots to loop around if they exit the screen
    if (x < 0) {
      x = width;
    } else if (x > width) {
      x = 0;
    }
    
    if (y < 0) {
      y = height;
    } else if (y > height) {
      y = 0;
    }
  }
}

And finally, the working product!

The next step is to turn it into javascript for my commlab website!

 

The Language of New Media – Response

The amount of jargon in the text intimidated me and I found it difficult to focus on the text. However, the ideas it presents, such as the different types of automation and the connection between social changes and the media were very interesting. I wish the text had a little more context to help someone who is new to the field feel less overwhelmed.

Eyeo2012 – Response

The works that Casey Reas show during his talk made me say “whoa” the whole time. It was interesting to look at such projects and listen to the artist talk about his work as I am still very foreign to the field of digital art. The idea of letting the program do its thing without the artist manipulating things was very interesting as the kind of art I am used to doesn’t happen unless the artist works.

But doesn’t the artist have to write some code in this case?

I meant it in the sense that analogue art stops when and where the artist leaves the work. However, digital art as such continues to progress after the artist stops making changes to the code.

Music Art Visualizer using Object Oriented Programming

So for my project this week I wanted to recreate some of the music videos for electronic music on youtube such as this one:

I was interested in doing this a few months back and when I searched for tutorials they all had to do with getting some video editing software(Sony Vegas Pro) and putting in some scripts. However, now with my knowledge of processing I felt I could do it from scratch with code only and no video editing software, which is what I attempted. It isn’t as seamless as the one above but the general concept is there and it can be improved.

I also added some small features such as click to move the circle, added some text on the very right hand side so you can only see it when you move the circle and like the trapNation video has a logo in the circle, I added a logo that can be triggered by clicking the space bar.

The Code

I created a, ‘circleThing’ class which is the circle in the middle that increases its size depending on the Amplitude (note:not frequency).

I got the snow effect code from a website online that had a ‘Particle’ class and the rest of that snow code was procedural code. I enhanced it by making a ‘Snow’ class that created ‘Particle’ objects and was generalized so it was customizable. The speed of the snow fall depended on the Amplitude and when it was low I made it reverse the ‘gravity’ with a negative value.

import processing.sound.*;

Amplitude amp2;
AudioIn in2;
CircleThing mainCircle;
Snow snowfall;
float ears= 0;
boolean movable=false;
PImage bg,nyu;
boolean logoDisplay=false;

class CircleThing {
  public int circleX, circleY,defColor;
  CircleThing(int cX, int cY,int defaultColor) {
    circleX=cX;
    circleY=cY;
    defColor=defaultColor;
  }

  void draw(int cX, int cY, float soundVal,int scaling,PImage nyuImage,boolean displayImage) {
    if(soundVal>0.025) {
    fill(random(255), random(255), random(255));
    } else {
      //fill(random(255), random(255), random(255));
    fill(defColor);
    }
    strokeWeight(10);
    ellipse(cX, cY,(200+ soundVal*scaling), (200+soundVal*scaling));
    imageMode(CENTER);
    //rotate(45);
if(displayImage) {
    pushMatrix();
imageMode(CENTER);
translate(cX,cY);
rotate(-PI/8);
image(nyuImage,0,0);
popMatrix();
}

String s = "Made by Romeno Wenogk Fernando. wenogk@nyu.edu";
fill(255);
textSize(16);
text(s, cX+500, cY, 200, 150);
  }
}

class Particle {

  float x;          // adds x position property
  float y;          // adds y position property
  float xVel;       // adds xvel property
  float yVel;       // adds yvel property
  float partsize;   // adds a size property


  //Constructor = function// float says where it is xpos/ypos
  Particle(float xpos, float ypos) {
    // assigning the values
    x = xpos = random (0,600);
    y = ypos;
    xVel = random (-2, 2);   // random,(the length of the random)
    yVel = random (0, 5);    // controls the speed that the snow falls
    partsize = random (5, 10);
  }
  
}

class Snow {
Particle[] particles = new Particle[0];
int maxParticles =100;

Snow() {
}
void setMax(int val) {
maxParticles=val;
}
void draw(float ears) {
particles = (Particle[]) append(particles, new Particle(300, 0));
  if (particles.length>maxParticles) {
    particles = (Particle[]) subset(particles, 1);
  }
  for (int i=0; i<particles.length; i++) {
      particles[i].partsize *=0.975;  //make the snow stay reduce size
      particles[i].x += particles[i].xVel;
      particles[i].y += particles[i].yVel;
     if(ears>0.03) {
      particles[i].yVel +=0.2;   
     } else if(ears>0.05) {
       particles[i].yVel +=0.4;
     }
     else if(ears>0.07) {
       particles[i].yVel +=0.6;
     } else if(ears>0.09) {
       particles[i].yVel +=0.8;
     } else {
       particles[i].yVel-=0.1; //reverse gravity
       
     }
    ellipse(particles[i].x, particles[i].y, particles[i].partsize, particles[i].partsize);
  }
}
}

void setup() {
  size(640, 440);
  background(90);
  amp2 = new Amplitude(this);
  in2 = new AudioIn(this, 0);
  in2.start();
  amp2.input(in2);  
  mainCircle= new CircleThing(width/2,height/2,45);
  snowfall= new Snow();
  //bg = loadImage("bg.jpg");
  //bg.resize(width,height);
  //nyu=loadImage("nyu.png");
  //nyu.resize(int(nyu.width*0.5),int(nyu.height*0.5));
}      

void draw() {
  background(0);
  ears=amp2.analyze();
   stroke(255);
  strokeWeight(1);
  println(ears);
  fill(255);
  snowfall.draw(ears);
  stroke(75); 
  if(!movable) {
    
  mainCircle.draw(width/2,height/2,ears,190,nyu,false);  
  } else {
  mainCircle.draw(mouseX,mouseY,ears,190,nyu,false); 
  }
 

}

void mousePressed() {
movable=!movable;
}

void keyPressed() {
logoDisplay=!logoDisplay;
}

 

Mehnopoly

Disclaimer: The frustrations in the post are overblown for comedic purposes. Also I’m pretty sick and it’s 2:40 am.

For this week’s weekly assignment, the devil haunted me and told me to recreate monopoly. Kids, never listen to the devil. I only started realizing my mistake after it was too late.

So half way through this project that ended up being 350 lines of code by the way, while coding in bed blowing my nose every 5 seconds, I decided to compile a short list of other things I could’ve been doing with my life, and here it is, in no particular order:

  • Work on my social life
  • Work on my paper on the strong force
  • Procrastinate the paper on the strong force
  • Netflix

But, I digress. Perhaps my extreme unwillingness to write the paper on the strong force pushed me to write 350 lines of code for a weekly assignment. Back to the topic at hand:

Mehnopoly:

It’s mehnopoly because it’s like monopoly, but meh. Let’s go ahead and get what this game is missing out of the way first:

  • No jail system, jail currently acts like free parking
  • no houses and hotels
  • it’s limited to two players
  • chance and community chests only have 2 cards, +100 and -100.

You perform actions using the keyboard, and the game will direct you.

anyways, without further ado, Mehnopoly:

and the code that is so messy that god himself has given up on it:

//0 name, 1 type, 2 owner, 3 cost, 4 rent, 5 xcoordinate, 6 ycoordinate
// types: 0 = income tax, 1 = normal, 2 = railroad, 3 = utilities, 4 = community chest and chance, 5 = jail and free parking, 6 = go,7 = supertax
String[][] places = {
  {"Go", "6", "Bank", " ", "-200", "750", "750"}, // 0
  {"Old kent road", "1", "Bank", "60", "6", "660", "750"}, // 1
  {"Community chest", "4", "Bank", " ", "0", "595", "750"}, // 2
  {"White chapel road", "1", "Bank", "60", "6", "530", "750"}, //3
  {"Income tax", "0", "Bank", " ", "200", "465", "750"}, // 4
  {"Kings cross station", "2", "Bank", "200", "25", "400", "750"}, // 5
  {"The angel islington", "1", "Bank", "100", "10", "335", "750"}, // 6
  {"Chance", "4", "Bank", " ", "0", "270", "750"}, // 7
  {"Euston Road", "1", "Bank", "100", "10", "205", "750"}, // 8
  {"Pentonville Road", "1", "Bank", "120", "12", "140", "750"}, // 9
  {"Jail", "5", "Bank", " ", "0", "50", "750"}, // 10
  {"Pall Mall", "1", "Bank", "140", "14", "50", "660"}, // 11
  {"Electric Company", "3", "Bank", "150", "15", "50", "595"}, // 12
  {"Whitehall", "1", "Bank", "140", "14", "50", "530"}, // 13
  {"Northumberland Avenue", "1", "Bank", "160", "16", "50", "465"}, // 14
  {"Marylebone station", "2", "Bank", "200", "25", "50", "400"}, // 15
  {"Bow street", "1", "Bank", "180", "18", "50", "335"}, // 16
  {"Community chest", "4", "Bank", " ", "0", "50", "270"}, // 17
  {"Marlborough street", "1", "Bank", "180", "18", "50", "205"}, // 18
  {"Vine street", "1", "Bank", "200", "20", "50", "130"}, // 19
  {"Free Parking", "5", "Bank", " ", "0", "50", "50"}, // 20
  {"Strand", "1", "Bank", "220", "22", "140", "50"}, // 21
  {"chance", "4", "Bank", " ", "0", "205", "50"}, // 22
  {"Fleet street", "1", "Bank", "220", "22", "270", "50"}, // 23
  {"Trafalgar square", "1", "Bank", "240", "24", "335", "50"}, // 24
  {"Fenchurch st station", "2", "Bank", "200", "25", "400", "50"}, // 25
  {"Leicester square", "1", "Bank", "260", "26", "465", "50"}, // 26
  {"Coventry street", "1", "Bank", "260", "26", "530", "50"}, // 27
  {"Waterworks", "3", "Bank", "150", "15", "595", "50"}, // 28
  {"Piccadilly", "1", "Bank", "280", "28", "660", "50"}, // 29
  {"Jail", "5", "Bank", " ", "0", "750", "50"}, // 30
  {"Regent street", "1", "Bank", "300", "30", "750", "130"}, // 31
  {"Oxford street", "1", "Bank", "300", "30", "750", "205"}, // 32
  {"Community chest", "4", "Bank", " ", "0", "750", "270"}, // 34
  {"Bond street", "1", "Bank", "320", "32", "750", "335"}, // 35
  {"Marylebone station", "2", "Bank", "200", "25", "750", "400"}, // 36
  {"Chance", "4", "Bank", " ", "0", "750", "465"}, // 37
  {"Park lane", "1", "Bank", "350", "32", "750", "530"}, // 38
  {"Supertax", "7", "Bank", " ", "200", "750", "595"}, //39
  {"Mayfair", "1", "Bank", "400", "40", "750", "660"}, //40

};

boolean allowRoll = true;
int circlesize = 10;
int turn = 0;
int diceroll;
PImage bg;
boolean first = true;

// colors: red or blue
Player p1 = new Player("red", int(places[0][5]), int(places[0][6]), 10);
Player p2 = new Player("blue", int(places[0][5]), int(places[0][6]), -10);


void setup() {
  first = false;
  size(800, 800);
  bg = loadImage("board.jpg");
  background(0);
  fill(255);
  textSize(16);
  text("Welcome to mehnopoly. It's almost monopoly, but seriously lower your expectations.", 20, 50);
  text("The game is for two players. or You can play against yourself if you can't find friends. I dont judge.", 20, 100);
  text("You win by making your opponent go bankrupt. Go nuts!", 20, 150);
  text("Press S to start the game", 20, 200);
  textSize(12);
  text("Fun Fact: Monopoly was originally created as a statement against capitalism.", 20, 250);
  
}

void draw() {
  if (first) {
    textSize(24);
    fill(255, 127, 0);
    text("Player 1 has "+p1.money+" left", 150, 200);
    text("Player 2 has "+p2.money+" left", 150, 250);
    text("Player 1's turn",150,300);
    text("Press R to roll dice",150,350);
  }
}
int keycounter = 0;
void keyPressed() {
  keycounter++;
  if (keycounter == 1) first = true;
  if (keycounter == 2) first = false;
  refresh();
  // Roll dice phase
  if ((key == 'r' || key == 'R')&&allowRoll) {
    allowRoll = false;
    diceroll = rollDice();
    if (turn == 0) {
      if (p1.placecount + diceroll >= 40) {
        p1.placecount = p1.placecount+diceroll - 40;
        p1.money += 200;
      } else {
        p1.placecount+= diceroll;
      }
      p1.updatePos();
      refresh();
      checkLanded(p1);
    } else {
      if (p2.placecount + diceroll >= 40) {
        p2.placecount = p2.placecount+diceroll - 40;
        p2.money += 200;
      } else {
        p2.placecount+= diceroll;
      }
      p2.updatePos();
      refresh();
      checkLanded(p2);
    }
  }
  if ((key == 'b' || key =='B')&& !allowRoll) {
    refresh();
    if (turn == 0) {
      buy(p1);
    } else {
      buy(p2);
    }
  }

  if ((key == 'e' || key == 'E')&& !allowRoll) {
    refresh();
    endTurn();
  }

  if ((key == 'i' || key == 'I') && allowRoll) {
    fill(255, 127, 0);
    if (turn == 0) { 
      int ycounter = 200;
      for (int i = 0; i<p1.propertyamount; i++, ycounter+=50) {
        text(places[p1.properties[i]][0], 150, ycounter);
      }
    }
    if (turn == 1) {
      int ycounter = 200;
      for (int i = 0; i<p2.propertyamount; i++, ycounter+=50) {
        text(places[p2.properties[i]][0], 150, ycounter);
      }
    }
  }

  
}



class Player {
  int money, xpos, ypos, rails, utilities, offset, placecount, propertyamount;
  int[] properties = new int[50];
  String col;
  Player (String n, int xp, int yp, int off) {
    col = n;
    placecount = 0;
    money = 1500;
    offset = off;
    xpos = xp;
    ypos = yp;
    rails = 0;
    utilities = 0;
    propertyamount = 0;
  }

  void display() {
    strokeWeight(2);
    stroke(255, 255, 255);
    if (col == "red")fill(255, 0, 0);
    if (col == "blue")fill(0, 0, 255);
    ellipse(xpos+offset, ypos, circlesize, circlesize);
  }
  void updatePos() {
    xpos = int(places[placecount][5]);
    ypos = int(places[placecount][6]);
  }
}

int rollDice() {
  return round(random(1, 12));
  //return 7;
}

void checkLanded(Player x) {
  textSize(24);
  fill(255, 127, 0);
  text("You rolled "+diceroll+" and landed on: "+places[x.placecount][0], 150, 200);
  if (int(places[x.placecount][1]) == 5 || int(places[x.placecount][1]) == 6)text("Press E to end turn", 150, 250);
  // if income tax
  if (int(places[x.placecount][1]) == 0) {
    fill(255, 127, 0);
    text("You pay 200 for income tax", 150, 250);
    x.money-=200;
    text("You now have: "+str(x.money)+" left", 150, 300);
    text("Press E to end turn", 150, 350);

    // if purchasable
  } else if (int(places[x.placecount][1]) == 1 || int(places[x.placecount][1]) == 2 || int(places[x.placecount][1]) == 3) {
    // if owner is bank
    if (places[x.placecount][2] == "Bank") {
      fill(255, 127, 0);
      text("Property isn't owned, what would you like to do?", 150, 250);
      text("Press B to buy for "+places[x.placecount][3]+" or press E to end turn", 150, 300);
      // if owner is not bank
    } else {
      // if it's a normal purchasable
      if (int(places[x.placecount][1]) == 1) {
        if (turn == 0 && places[x.placecount][2] == "Player2")handleRent(p1, p2, int(places[x.placecount][4]));
        if (turn == 1 && places[x.placecount][2] == "Player1")handleRent(p2, p1, int(places[x.placecount][4]));
        // if railroad
      } else if (int(places[x.placecount][1]) == 2) {
        int rent;
        if (turn == 1 && places[x.placecount][2] == "Player1") {
          rent = checkRailRent(p1);
          handleRent(p2, p1, rent);
        } else if (turn == 0 && places[x.placecount][2] == "Player2") {
          rent = checkRailRent(p2);
          handleRent(p1, p2, rent);
        }
        // if utilities
      } else if (int(places[x.placecount][1]) == 3) {
        int rent = 0;
        if (turn == 0 && places[x.placecount][2] == "Player2") {
          if (p2.utilities == 1)rent= 7*diceroll;
          if (p2.utilities == 2)rent= 15*diceroll;
          handleRent(p1, p2, rent);
        } else if (turn == 1 && places[x.placecount][2] == "Player1") {
          if (p1.utilities == 1)rent= 7*diceroll;
          if (p1.utilities == 2)rent= 15*diceroll;
          handleRent(p2, p1, rent);
        }
      }
    }
    // super tax
  } else if (int(places[x.placecount][1]) == 7) {
    fill(255, 127, 0);
    text("You pay 100 for super tax", 150, 250);
    x.money-=200;
    text("You now have: "+str(x.money)+" left", 150, 300);
    text("Press E to end turn", 150, 350);
    //community chest and chance
  } else if (int(places[x.placecount][1]) == 4){
    int r = round(random(1,3));
    if (!(r == 2)){
      text("Jeff Bezos felt generous today, he gave you 100!",150,250);
      text("Assuming 1 = $100,000 , this amounts to",150,300);
      text("a whooping 0.0001% of his net worth",150,350);
      text("press E to end turn",150,400);
      x.money += 100;
    } else {
      text("You did some contractual work on one of",150,250);
      text("Trump's properties! He paid you a 1000!",150,300);
      text("Just kidding, he didn't pay you at all.",150,350);
      text("In fact you paid a 100 for materials.",150,400);
      text("press E to end turn",150,450);
      x.money -= 100;
    }
  }
  checkWin();
}

void checkWin() {
  if (p1.money < 0) {
    refresh();
    fill(255, 127, 0);
    text("P2 has won", 150, 200);
    noLoop();
  }
  if (p2.money < 0) {
    refresh();
    fill(255, 127, 0);
    text("P1 has won", 150, 200);
    noLoop();
  }
}

void endTurn() {
  refresh();
  fill(255, 127, 0);
  text("Player 1 has "+p1.money+" left", 150, 200);
  text("Player 2 has "+p2.money+" left", 150, 250);
  if (turn == 0) {
    fill(255, 127, 0);
    text("Player 1's turn has ended. Player 2's turn", 150, 300);
    turn = 1;
  } else {
    fill(255, 127, 0);
    text("Player 2's turn has ended. Player 1's turn", 150, 300);
    turn = 0;
  }
  text("Press R to roll or I for a list of your properties,", 150, 350);
  allowRoll = true;
  checkWin();
}


void refresh() {
  background(bg);
  p1.display();
  p2.display();
  fill(0);
  rect(100, 100,600,600);
}

void buy(Player x) {
  fill(255, 127, 0);
  if (places[x.placecount][2] == "Bank") {
    x.money -= int(places[x.placecount][3]);
    x.properties[p1.propertyamount] = x.placecount;
    x.propertyamount++;
    text(places[x.placecount][0]+" has been purchased", 150, 200);

    if (turn == 0) places[x.placecount][2] = "Player1";
    if (turn == 1) places[x.placecount][2] = "Player2";
    if (int(places[x.placecount][1]) == 2) {
      x.rails += 1;
      text("You now have "+x.rails+" railroads", 150, 250);
      text("Press E to end turn", 150, 300);
    } else if (int(places[x.placecount][1]) == 3) {
      x.utilities += 1;
      text("You now have "+x.utilities+" utilities", 150, 250);
      text("Press E to end turn", 150, 300);
    } else {
      text("Press E to end turn", 150, 250);
    }
  }
  checkWin();
}

int checkRailRent(Player x) {
  if (x.rails == 1) return x.rails*25;
  if (x.rails == 2) return x.rails*25;
  if (x.rails == 3) return 100;
  if (x.rails == 4) return 200;
  return 0;
}

void handleRent(Player renter, Player rentee, int rent) {
  renter.money -= rent;
  rentee.money += rent;
  fill(255, 127, 0);
  text("Property is owned, you have paid "+rent+" in rent", 150, 250);
  text("You have "+renter.money+" left", 150, 300);
  text("Press E to end turn", 150, 350);
  checkWin();
}

and if you, for god knows why, want to play this game, download the files from here:

https://drive.google.com/drive/folders/1DT1VFHHmSjgRkDnd0ARSmf6qXTmpuHpj?usp=sharing

Note: I haven’t rigorously tested the game, proceed at your own risk .

 

Object Orientated Game Documentation

This week I decided to make a game as per recommendation of some peers. Mid-way through I realized I had a horrible mistake. However, I got a lot of help from Ross and the following is the process and final product.

First I brainstormed out loud and understood the logic of making a game. The initial idea was to make a clock like structure, much like a wheel of fortune, that would contain a spinning dial. Once the player mouse clicked the screen, the dial would stop. If the dial stopped between an area, the player would win, otherwise they would lose.

I used a class for the dial and the code is as follows:

class Dial {
  float locX, locY;
  float angle;
  

  //constructor
  Dial(float x, float y) {
    locX = x;
    locY = y;
  }

  void draw () {
    if (!clicked) {
      strokeWeight(5);
      stroke(#E50C0C);
      float t = millis()/1000.0f;
      locX = (locX+100*cos(t));
      locY = (locY+100*sin(t));
      line(300, 300, locX, locY);
    }
    else{
      if(clicked){
        image(img,17,25);
    
    }
  }
  }
}

The spinning was found online and it created a sort of 3D rotation of what looked like a cone shape. The line wouldn’t rotate exactly around the diameter of the circle. Therefore, to fix this I made the background have the same color as the dial. It was a slight ratchet solution, but it works.

I don’t really understand why, but near the designated ‘win’ area, the dial seems to move faster. I didn’t do it on purpose but it works so I kept it.

As for the ‘win’ and ‘lose’ results, I decided to implement a sadistic ending and added a jigsaw photo. No matter whether the player won or not, the results would just show the photo of jigsaw from the movie Saw. Recently I watched ‘Ready Player One’ and in the movie they talked a lot about Easter eggs. I was inspired to put an Easter egg of the combination of Saw and Rick & Morty. (side tracking: the new episode of my favorite series ‘Rick & Morty’  is maybe coming out today, so I was thinking about it a lot). The little Easter egg is at the top right hand corner of the screen.

Here is the code of the game sketch:

Dial dial1;
boolean clicked = false;
float stopX;
float stopY;
PImage img;

void setup() {
  size (600, 600);
  dial1 = new Dial(300, 100);
img = loadImage("jigsaw.jpg");
}

void draw() {
  background (#E50C0C);
  fill(255);
  ellipse(300, 300, 400, 400);
  fill(0, 0, 0);
  arc(300, 300, 400, 400, 0, QUARTER_PI, PIE); 
  dial1.draw();

  textSize(8);
  text("Rick is...is this a 'Saw' thing? Are you Sawing the Vindicators -Morty", 8, 10); 
  fill(0, 102, 153);
  

}

Here is a photo of what the game screen looks like: