Index / 2017 / Assignment 05
800×600 · p5.js instance mode
8 PDE files 581 lines
// Assignment_05.pde
/*

[ -------------------- [ INFO ] -------------------- ]

Assignment 05: Animated Objects
Vincent Nguyen
04/18/2017

[ -------------------- [ BLURB ] -------------------- ]

Hello!

For this assignment, I really wanted to recreate rain BUT not just run-of-the-mill boring rectangular rain.
I wanted to make a rain object that would splash and split apart and create somewhat realistic looking
impacts. I also added in a mouse controlled umbrella (custom shape) which allows me to showcase the rain
particles splashing and falling off the side of the umbrella (it might be a bit hard to see). Afterwards,
I added a short story about a dog for fun. Anyway, that's pretty much all my program really does. Oh, and
there are some extra buttons apart from the time-freeze button just to fill in the space. Hope you enjoy.

As always, thanks for reading!

Vincent

[ -------------------- [ TABLE OF CONTENTS ] -------------------- ]

01. SETTING UP GLOBAL VARIABLES
02. VOID SETUP() AND ASSIGNING VALUES
03. VOID DRAW() AND A MENU SWITCH

[ -------------------- [ CREDITS ] -------------------- ]


[ Images ]

01. back01 [ https://i.imgur.com/C4r2jXu.jpg ]
02. back02 [ scromy.com/wp-content/uploads/2017/01/anime-city-scenery-wallpapers-hd-resolution.jpg ]
03. back03 [ https://s-media-cache-ak0.pinimg.com/originals/65/58/61/655861c7cf92b29d2c43cda51faa38bd.jpg ]
04. back04 [ http://www.toocraft.com/postpic/2010/05/beautiful-night-sky-anime_87454.jpg ]
05. back05 [ http://scromy.com/wp-content/uploads/2017/01/night-anime-scenery-wallpaper-full-hd.jpg ]
06. dog    [ http://4.bp.blogspot.com/-pU8NGCLtAic/U7BsXeiIXaI/AAAAAAAAABw/uNxkJ9JuFRg/s1600/perrito.png ]
  
[ Sound ]
  
01. rain    [ https://www.freesound.org/people/lebcraftlp/sounds/243628/ ]
02. thunder [ https://www.freesound.org/people/InspectorJ/sounds/360328/ ]

[ Fonts ]

01. New Cicle by TPK [ www.dafont.com/new-cicle.font ]

*/

// ============================== [ 01. SETTING UP GLOBAL VARIABLES ] ============================== //

//Sets up variables
PFont font;
PImage back01, back02, back03, back04, back05, dog;
ArrayList<Rain> rain = new ArrayList();
int state, textState, backState;
float opacity;
boolean frozen, colours;

//Sets up audio
import ddf.minim.*;
Minim minim;
AudioPlayer thunder, rains;

//Sets up objects
Button freeze, rainbow, backdrop;
Dog puppersnup;
Umbrella red;

// ============================== [ 02. VOID SETUP() AND ASSIGNING VALUES ] ============================== //

void setup() {
  size(800,600);
  
  rectMode(CENTER);
  imageMode(CENTER);
  textAlign(CENTER,CENTER);
  
  smooth(8);
  noStroke();
  
  //Font
  font = loadFont("NewCicle-Semi-36.vlw");
  
  //Images
  back01 = loadImage("background01.png");
  back02 = loadImage("background02.png");
  back03 = loadImage("background03.png");
  back04 = loadImage("background04.png");
  back05 = loadImage("background05.png");
  dog = loadImage("doggo.png");
  
  //Text
  textFont(font);
  textSize(36);
  
  //Objects
  freeze = new Button("Freeze Time", width/16*4, height*0.94, width/4, height/10);
  rainbow = new Button("Candy Rain", width/16*8, height*0.94, width/4, height/10);
  backdrop = new Button("Background", width/16*12, height*0.94, width/4, height/10);
  puppersnup = new Dog();
  red = new Umbrella();
  
  //Audio
  minim = new Minim(this);
  
  rains = minim.loadFile("rain.mp3");
  rains.setGain(-10);
  rains.loop();
  
  thunder = minim.loadFile("thunder.mp3");
  thunder.setGain(-10);
  
  //Integers
  state = 0;
  textState = 0;
  
  //Float
  opacity = 255;
}

// ============================== [ 03. VOID DRAW() AND A MENU SWITCH ] ============================== //

void draw() {
  
  audio(); //audio function
  
  switch(state) { //switch for screens
    case 0:
      drawIntro();
      break;
    case 1:
      drawGame();
      break;
    default:
      drawIntro();
      break;
  }
  
}

// Audio.pde
void audio() { //audio function
  
  if (!rains.isPlaying()) { //if rain is not playing
    rains.cue(0); //restart it
  }
  
  if (!frozen) { //if time is not frozen...
    rains.play(); //play the rain sound
  } else {
    rains.pause(); //else, if frozen...
    thunder.pause(); //pause everything
  }
  
}

// Button.pde
class Button { //Button class

  //Sets up variables
  PVector p;
  float w, h;
  String t;

  Button(String text, float tempX, float tempY, float tempW, float tempH) {
    p = new PVector(tempX, tempY);
    w = tempW;
    h = tempH;
    t = text;
  }

  //Display function
  void display() {

    noStroke();

    if (mouseOver(p.x, p.y, w, h)) { //If mouse is over button...
      fill(#FFFFFF, 10);
      if (click()) { //If mouse is over button AND clicked...
        fill(#FFFFFF, 30);
      }
    } else { //If mouse is not over button...
      fill(#FFFFFF, 0);
    }

    rect(p.x, p.y, w, h, 10); //Draw button
    fill(#FFFFFF);
    text(t, p.x, p.y); //Draw text
  }

  //Mouseover function
  boolean mouseOver(float x, float y, float w, float h) {
    if (mouseX >= (x-w/2) && mouseX <= (x+w/2) && mouseY >= (y-h/2) && mouseY <= (y+h/2)) { //if mouse is over button...
      return true;
    } else {
      return false;
    }
  }

  //Clicked function
  boolean click() {
    if (mouseOver(p.x, p.y, w, h) && mousePressed) { //if mouse is over button & mouse is pressed...
      return true;
    } else {
      return false;
    }
  }
}

// Dog.pde
class Dog { //Dog object

  //Variables
  PVector p, v;
  float angle, speed, accel;
  
  Dog() {
    p = new PVector(random(35, width-35), height/64*55);
    v = new PVector(1, 0);
    angle = -15; //Dog's starting angle
    speed = 0;
    accel = 0.1;
  }
  
  //funky rotation display function
  void display() { 
    tint(255); //display the dog at full brightness
    pushMatrix(); //push Neo
    translate(p.x, p.y); //google translate that image, quick
    
    if (!frozen) { //if time is not frozen...
      rotate(radians(angle)); //rotate that sucker!
    }
    
    image(dog, 0, 0, 70, 70); //display the dog
    popMatrix(); //pop Neo
  }
  
  //move function
  void move() { 
    if (!frozen) {//if time is not frozen, move that sucker!
      p = p.add(v);
      angle += speed; //next level rotation code
      speed += accel;
    }
  }
  
  //update function
  void update() {
    if (p.x >= (width-35)) { //if the dog hits the wall, reverse speed
      v = v.set(-1, 0);
    } else if (p.x <= 35) { //same as before
      v = v.set(1, 0);
    }

    if (speed >= 2) { //if the dog is rotating too fast, reverse acceleration
      accel = -0.1;
    } else if (speed <= -2) { //same as before
      accel = 0.1;
    }
  }
}

// drawGame.pde
void drawGame() { //drawGame function
  
  tint(100); //tints the background images to make them darker
  
  switch(backState) { //switch for image state
    case 0: image(back01, width/2, height/2); break;
    case 1: image(back02, width/2, height/2); break;
    case 2: image(back03, width/2, height/2); break;
    case 3: image(back04, width/2, height/2); break;
    case 4: image(back05, width/2, height/2); break;
    default: image(back01, width/2, height/2); break;
  }
  
  //Puppy functions
  puppersnup.display();
  puppersnup.move();
  puppersnup.update();
  
  //Umbrella functions
  red.display();
  red.update();

  //Freeze button
  if (freeze.click()) { //if button is clicked...
    if (frozen) { //if time is already frozen...
      frozen = false; //unfreeze
    } else if (!frozen) { //if time is not frozen...
      frozen = true; //freeze
    }
    mousePressed = false;
  }
  
  //Rainbow button
  if (rainbow.click()) { //if button is clicked...
    if (colours) { //if rainbow is already random...
      colours = false; //disable rainbow
    } else if (!colours) { //if rainbow is not active...
      colours = true; //enable it
    }
    mousePressed = false;
  }
  
  //Background image button
  if (backdrop.click()) { //If button is clicked...
    if (backState >= 5) { //if the background image state has reached the end...
      backState = 0; //set it back to the beginning
    }
    backState++; //move the background image state forward
    mousePressed = false;
  }
  
  //ArrayList "for" loop for the rain array
  for (Rain r : rain) {
    r.display(); //display rain

    if (!frozen) { //if time is not frozen...
      r.move(); //rain moves
    }
    
    r.collision(); //collision check with ground
  }
  
  //Regular "for" loop for the rain array
  for (int i=0; i < rain.size(); i++) {
    Rain r = rain.get(i);

    if (r.finished()) { //if rain's life span is < 0
      rain.remove(i); //remove it from the ArrayList
    }
  }
  
  //Regular "for" loop to spawn new rain objects
  for (int i=0; i < 5; i++) {
    if (!frozen) { //if time is not frozen...
      rain.add(new Rain()); //add rain!
    }
  }

  if (mouseX >= (red.getX() - 45) && mouseX <= (red.getX() + 45) && mouseY >= (red.getY() - 60) && mouseY <= (red.getY() + 30)) { //If mouse is over umbrella...
    cursor(HAND); //show hand cursor
    if (mousePressed && !frozen) { //if mouse is clicked and time is not frozen
      red.grabbed = true; //the umbrella is being "held"
    } else { //otherwise, let go of the umbrella
      red.grabbed = false;
    }
  } else { //if the mouse is not over the umbrella
    cursor(0); //return to regular cursor
    red.grabbed = false;
  }
  
  //fill and draw for the black rectangle at the bottom of the screen
  fill(#000000,180);
  rect(width/2, height, width, height/4);
  
  //display the 3 main buttons
  freeze.display();
  rainbow.display();
  backdrop.display();
  
  //random thunder code
  if (random(0, 500) > 498 && !frozen) {
    
    fill(255); //big, white flash on screen
    rect(width/2, height/2, width, height);
    
    if (!thunder.isPlaying()) { //if thunder sound is not playing
      thunder.cue(0); //reset it
    }
    thunder.play(); //and play the sound
  }
  
  //small, short black fade-in @ beginning of drawGame
  fill(#000000, opacity);
  rect(width/2, height/2, width, height);
  opacity -= 1;
}

// drawIntro.pde
void drawIntro() { //Short little intro function for funsies

  String intro = ""; //the text that is displayed

  fill(#000000, 20); //Black background. Opacity gives it a "fading" effect
  rect(width/2, height/2, width, height);

  fill(#FFFFFF, 10); //Short little tooltip @ the bottom in case anyone needs it
  text("Click to Continue", width/2, height/32*31);

  fill(#FFFFFF, 100); //For the main text!

  if (textState == 0) { //textState string thing begins here.
    intro = "Hello!";
  } else if (textState == 1) {
    intro = "Welcome to Vincent Nguyen's\nAssignment 05: Animated Objects";
  } else if (textState == 2) {
    intro = "Here, you will play the role of a citizen\ntrapped in a tragic thunderstorm\nwith your faithful companion";
  } else if (textState == 3) {
    intro = "To hold the umbrella, hover your mouse over\nand use the left mouse button to grab it";
  } else if (textState == 4) {
    intro = "Your goal...\nis to protect your friend!";
  } else if (textState == 5) {
    intro = "Best of luck!\n-Vincent";
  } else if (textState == 6) {
    state = 1;
  } //textState string thing ends here.

  text(intro, width/2, height/2); //display text

  if (mousePressed) { //Each time you click, progress the textState...
    textState++;
    mousePressed = false;
  }
}

// Rain.pde
class Rain { //Rain object

  //Variables
  PVector p, v, a, prev; //prev is a variable to store the PVector when time freezes
  float w, h, life; //life is used to determine the longevity of a single rain object
  color c;
  boolean splashed; //used later on for splashing rain

  Rain() {
    p = new PVector(random(0, width), -30);
    prev = new PVector(0, 0);
    v = new PVector(0, 0);
    a = new PVector(0, 0.1);
    w = random(2, 4);
    h = random(20, 40);
    life = 255;
    
    if (!colours) { //Decides the colour of the rain based on whether rainbow mode is on or not
      c = color(random(95, 121), random(127, 148), random(155, 175)); //regular blues
    } else {
      c = color(random(100,200), random(100,200), random(100,200)); //random colours
    }
  }
  
  //Display function
  void display() {
    fill(c,life); //colour
    if (!splashed) { //if the rain has not yet splashed...
      rect(p.x, p.y, w, h, 2); //rectangle
    } else { //if the rain has splashed...
      ellipse(p.x, p.y, w, w); //circle
    }
  }
  
  //Move function
  void move() {
    p = p.add(v); //makes the rain fall according to gravity
    v = v.add(a);
  }
  
  //Boolean function to kill the rain after a certain amount of time
  boolean finished() {
    if (!frozen) {
      life -= 1.0;
    }

    if (life < 0) { 
      return true;
    } else { 
      return false;
    }
  }
  
  //Collision function with the ground
  void collision() {

    if ( p.y >= height/8*7 && !splashed) { //if the rain has hit the ground and is a rectangle

      splashed = true; //make it splash
      p.y = p.y - random(10, 100); //move it back up
      
    } else if ( p.y >= height/8*7 && splashed) { //if the rain has hit the ground but has already splashed

      p.y = p.y - random(10, 100); //move it back up
      
    } else if ((p.x - w/2) >= (red.getX() - 45) && //UMBRELLA & RAIN COLLISION DETECTION START!!
               (p.x + w/2) <= (red.getX() + 45) &&
               (p.y + h/2) >= (red.getY() - 40) &&
               (p.y + h/2) <= (red.getY() + 40)) { 

                splashed = true; //it splashed on the umbrella
                
                p.x = red.getX() + random(-60, 60); //moves it to a random x and y position
                p.y = red.getY() - random(40, 100);
                
    }
  }
}

// Umbrella.pde
class Umbrella { //Umbrella object

  //Variables
  PVector p, prev; //prev stores previous position
  boolean grabbed; //boolean to check if mouse is "holding" the umbrella

  Umbrella() {
    p = new PVector(width/2,height/2);
    prev = new PVector(mouseX,mouseY);
    grabbed = false;
  }

  void display() {
    pushMatrix(); //push Neo
    
    translate(p.x,p.y-5);
    scale(4);
    
    fill(#404040); //Umbrella Handle
    beginShape();
      vertex(-1,-2);
      vertex(1,-2);
      vertex(1,4);
      vertex(2,5);
      vertex(3,4);
      vertex(4,5);
      vertex(4,6);
      vertex(3,7);
      vertex(1,7);
      vertex(0,6);
      vertex(-1,5);
    endShape();
    
    fill(#FF213F); //Umbrella Top
    beginShape();
      vertex(0,-1);
      vertex(-2.5,-3);
      vertex(-5,-1);
      vertex(-7.5,-3);
      vertex(-10,-1);
      vertex(-10,-7);
      vertex(-9,-9);
      vertex(-6,-12);
      vertex(-2,-13.5);
      vertex(2,-13.5);
      vertex(6,-12);
      vertex(9,-9);
      vertex(10,-7);
      vertex(10,-1);
      vertex(7.5,-3);
      vertex(5,-1);
      vertex(2.5,-3);
      vertex(0,-1);
    endShape();
    
    popMatrix(); //pop Neo
  }
  
  //Update function
  void update() {
    if (grabbed) { //if the umbrella is being "held"...
      p = p.set(mouseX, mouseY);
    } else if (!grabbed) { //if the umbrella is not being "held"...
      prev = prev.set(p.x, p.y); //store the PVector
      p = p.set(prev.x,prev.y);
    }
  }
  
  //Return functions for fun
  float getX() {
    return p.x;
  }
  
  float getY() {
    return p.y;
  }
}
read-only archive source from /2017/Assignments/A05 - Animated Objects/Assignment_05/Assignment_05.pde

Description

This page is generated from the Processing project folder at /2017/Assignments/A05 - Animated Objects/Assignment_05/Assignment_05.pde.

Archive

Assets