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