/*
Jamie Ho
jamieh@andrew.cmu.edu
10:30
Project 12
*/var particles =[]; //array to store circle particles
var d; //distance between two particles
var md; //distance between particle and
var r =255;var g =255;var b =255;functionsetup(){createCanvas(480,480);}functiondraw(){background(0); //create particles and push into array
p =newParticle();
particles.push(p); //if mouse is pressed, then add more particles & invert background colour
if(mouseIsPressed){
particles.push(p);background(255);} //first for loop counting backwards of the array
for(var i = particles.length-1; i >0; i--){
particles[i].show();
particles[i].update(); //second for loop counting forwards of the array. two for loops needed to draw lines between all particles
for(var j =0; j < particles.length; j++){ //distance between two particles
d =dist(particles[i].x, particles[i].y, particles[j].x, particles[j].y); //distance between particle and mouse
md =dist(particles[i].x, particles[i].y, mouseX, mouseY); //if distance between two particles is less than 45 then lines will be blue and thicker
if(d <45){if(d <25){stroke(102,204,255);strokeWeight(0.35);}elseif(d <45& d >25){ //if mouse is pressed, inverse colours
if(mouseIsPressed){stroke(0);strokeWeight(0.1);}else{stroke(255);strokeWeight(0.1);}}line(particles[i].x, particles[i].y, particles[j].x, particles[j].y);} //if the distance between particle and mouse is between range to determine whether or not to push particles away
if(md <50& mouseIsPressed ==false){if(particles[i].x > mouseX){
particles[i].x +=random(md/4, md/2);}elseif(particles[i].x < mouseX){
particles[i].x -=random(md/4, md/2);}elseif(particles[i].y > mouseY){
particles[i].y +=random(md/4, md/2);}elseif(particles[i].y < mouseY){
particles[i].y -=random(md/4, md/2);}} //if the alpha is less than 0 and returns true
//then that particle is "killed off" or removed from array
if(particles[i].finished()){
particles.splice(i,1);}}}}
class Particle{ //defines locations of particles and velocities and alphas
constructor(){ //if mouse is pressed then particle shows up where mouse is clicked
if(mouseIsPressed){this.x = mouseX;this.y = mouseY;}else{ //otherwise anywhere on canvas
this.x =random(width);this.y =random(height);} //size of particles
this.cSize =random(2,8); //velocities
this.vx =random(-0.5,0.5);this.vy =random(-0.5,0.5); //brightness of circles
this.alpha =255;} //creates the particles
show(){noStroke();if(mouseIsPressed){fill(r, g, b,this.alpha);}else{fill(255,this.alpha);}ellipse(this.x,this.y,this.cSize);} //to move the particles
update(){ //make particles move
this.x +=this.vx;this.y +=this.vy; //conditions where if particles hit the four edges, bounce
if(this.x > width-this.cSize/2){this.vx -=random(0.5,1.5);}elseif(this.x <0+this.cSize/2){this.vx +=random(0.5,1.5);}elseif(this.y > height-this.cSize/2){this.vy -=random(0.5,1.5);}elseif(this.y <0+this.cSize/2){this.vy +=random(0.5,1.5);} //to decrease the brightness of particles
this.alpha -=1.25;} //to "kill off" particles
finished(){returnthis.alpha <0; //either true or false
}}functionmouseDragged(){if(particles.push(p)& mouseIsPressed){
r =map(mouseY,0, height,100,255);
g -=random(2,3);
b =map(mouseX,0, width,150,255);}}
For my final project, I wanted to work with objects again to become more familiar with it. I chose to use particles and linking those particles based on different conditions. The particles are also interactive so that they’re not just floating circles that move by itself randomly. And while the mouse is clicked, the colours invert to show something more geometrical based on the lines drawn between particles.
For best viewing experience, please open in full screen here, and let it run for a while in the background. Check on your simulation occasionally to see how they’re evolving.
You can click to add producers, but this is highly unrecommended as it will alter the carrying capacity of the system. I recommend simply letting the software simulation run in the background.
//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
// EVOLUTION: An overview of genetic algorithms
//
// Evoltuion is a software that simulates evolution over time
// of a specie of consumers. The three main conceps are:
// VARIABILITY
// At setup, a diverse pool of genetic material is randomly created.
// HERERDITY
// Every time two producers mate, it's geneteics are combined and passed down.
// SELECTION
// The consumer's speed is determine by its darkness.
// Over time natural selection will probabilistically occur.
// CHARACTERS
//
// PRODUCERS:
// A certain amount of producers is randomly created every time interval.
// The producers gathers sunlight, grows, and if it exceeds a certain amount
// of calories it splits into two. Producers' calories can be consumed
// by consumers, and if producers' calories is negative it dies.
// CONSUMERS:
// A certain amount of consumers is randomly generated at setup.
// Consumers move around randomly searching for food (prdoucers).
// Each movement of a consumer consumes a certain amount of calories, and
// If a consumer's calorie is below zero, it dies. If a consumer's calorie
// reaches a certain threshold, it will stop searching for food and begin
// searching for a potential mate nearby to reproduce with.
//
// Reproduction consumes energy, and the the consumer may die shortly after.
var time =1; // Time variable
var w =480; // width
var h =480; // height
var turtles_AI =[]; // array of consumers
var INDEX =0; // ID for each turtle
var debug_mode =false; // true to see calorie transfer.
//------------------------------------------
// Creates Turtle
// Each turtle has fitness level based on its color's darkness
// The darker it is the faster it moves to food.
// Each turtle also has a certain amount of energy (calorie).
// Input: x,y,energy, color
// Output: Object turtle
functionmakeTurtle(tx, ty, energy =random(25,300),
c =color(random(0,255),random(0,255),random(0,255))){var turtle ={
x: tx,
y: ty,
life_index:random(-1,1), //random seed for perlin bheavior
life_index2:random(-1,1), //random seed for perlin bheavior
x_dir:1,
y_dir:1,
c: c,
energy: energy,
index: INDEX,
mating:false};
turtle.fitness =fitness(turtle); //0 to 100
turtle.diameter =map(turtle.energy,0,100,1,20);
INDEX +=1;return turtle;}
// Determines fitness of Turtle from 0 to 100%
// The darker the color the faster it is.
// Input: Color
// Out: fitness
functionfitness(turtle){
R =red(turtle.c);
G =green(turtle.c);
B =blue(turtle.c);
avg =(R + G + B)/3 // 0-255
returnmap(avg,0,255,100,0); //Darker the fitter
}
// Moves Turtle with noise
functionturtle_move_AI(){
speed =.045;for(i in turtles_AI){
life = turtles_AI[i].life_index;
life2 = turtles_AI[i].life_index2;
x_dir = turtles_AI[i].x_dir;
y_dir = turtles_AI[i].y_dir; // Moves turtle with Perlin Noise
SIZE =10; //Radius of displacement
turtles_AI[i].x += x_dir *(noise(time * life)-.5)* SIZE;
turtles_AI[i].y += y_dir *(noise(time * life2)-.5)* SIZE;
turtles_AI[i].energy -=.01; //Caloric Cost of movement
}}
// Contains any group of objects within the screen
// If object touch boundary of screen reverse direction
// Input: group
functioncontain(group){for(i in group){ // Min
if(group[i].x <0){
group[i].x =0
group[i].x_dir *=-1;
group[i].dx *=-1;}if(group[i].y <0){
group[i].y =0
group[i].y_dir *=-1;
group[i].dy *=-1;} // Max
if(group[i].x > w){
group[i].x = w
group[i].x_dir *=-1;
group[i].dx *=-1;}if(group[i].y > h){
group[i].y = h
group[i].y_dir *=-1;
group[i].dy *=-1;}}}
// Draws Turtle
functiondrawTurtle(){for(var i =0; i < turtles_AI.length; i++){
d =map(turtles_AI[i].energy,0,100,1,20);fill(turtles_AI[i].c);ellipse(turtles_AI[i].x, turtles_AI[i].y, d, d)fill(255);textSize(10);if(debug_mode ==true){text(floor(turtles_AI[i].energy), turtles_AI[i].x, turtles_AI[i].y)}}}
// Removes dead turtles
// If turtle has less than zero energy left it dies.
functionturtle_update(){for(var i =0; i < turtles_AI.length; i++){if(turtles_AI[i].energy >250){
turtles_AI[i].mating =true;}if(turtles_AI[i].energy <0){
turtles_AI.splice(i,1);return}}}
//------------------------------------------
// Hunt Food
// Input: individuall turtle
// Output: individiual turtle's target
functionhunt(turtle){
x = turtle.x;
y = turtle.y; // If no food return false
if(Object.keys(PRODUCERS)==0){returnfalse}else{ // Else target is the closest food
target ={
x:null,
y:null,
d:null}; // Search all food
for(j in PRODUCERS){ // Distance to food
d_food =dist(x, y, PRODUCERS[j].x, PRODUCERS[j].y); // If target is null or closer than previous
// Reassign target to closest producers
if(target.d ==null|| d_food < target.d){
target.x = PRODUCERS[j].x;
target.y = PRODUCERS[j].y;
target.d = d_food;
target.i = j
}}return PRODUCERS[target.i];}}
// Make all turtle hunt for Food
functionHUNT(){for(var i =0; i < turtles_AI.length; i++){
target =hunt(turtles_AI[i]);if(target !=false& turtles_AI[i].mating ==false){moveToward(turtles_AI[i], target, turtles_AI[i].fitness);eat(turtles_AI[i], target)}}}
// Makes Object X moves towards Object Y with V velocity
functionmoveToward(X, Y, V){
v =map(V,0,100,0,.1);
X.x =lerp(X.x, Y.x, v /2);
X.y =lerp(X.y, Y.y, v /2);}
// Eat food if food is inisde circle
// Input: individual food, FOOD array
functioneat(turtle, target){
d =dist(turtle.x, turtle.y, target.x, target.y) // If food is inside turtle
if(d <(turtle.diameter /2)){
target.energy -=.2;
turtle.energy +=1;}}
//------------------------------------------
// Mating function of turtles
// Turtle becomes mature at 200 calories and seeks to reproduce
// Input: individual turtle
// Ouput: closest mateable target
functionmate(turtle){
x = turtle.x;
y = turtle.y;
target ={
x:null,
y:null,
d:null}; // Search all potential mate
mate_count =0;for(var j =0; j < turtles_AI.length; j++){ // If Mate-able and not self
if(turtles_AI[j].mating ==true& turtles_AI[j]!= turtle){
mate_count +=1;
d =dist(turtles_AI[j].x, turtles_AI[j].y, turtle.x, turtle.y)if(target.d ==null|| d < target.d){
target.x = turtles_AI[j].x;
target.y = turtles_AI[j].y;
target.d = d;
target.i = j
}}} // If there is no mate return false.
if(mate_count ==0){returnfalse} // If there is mate return target.
else{;return turtles_AI[target.i];}}
// Makes turtles have sex.
// If mateable turtles touch one another they both lose 100 calorie
// and creates 1 baby. Turtle bcomes mateable at 200 calories.
functionsex(turtle, target){
d =dist(turtle.x, turtle.y, target.x, target.y)if(d < turtle.diameter /2){
turtle.energy -=100;
target.energy -=100; // Genetic Averaging and Mutation
c =lerpColor(turtle.c, target.c,random(.3,.7));
x =(turtle.x + target.x)/2;
y =(turtle.y + target.y)/2;
turtles_AI.push(makeTurtle(x, y,66, c))}}
// Loop through turtles to and make them mate
functionMATE(){for(var i =0; i < turtles_AI.length; i++){
target =mate(turtles_AI[i]);if(target !=false& turtles_AI[i].mating ==true){moveToward(turtles_AI[i], target, turtles_AI[i].fitness);sex(turtles_AI[i], target);}}}
//------------------------------------------
// Control
// Adds producers where mouse is clicked
functionmouseClicked(){ // FOOD.push(new makeFood(mouseX, mouseY));
producer =(newmakeProducer(mouseX, mouseY,30));
PRODUCERS[time]= producer;print(PRODUCERS);}
// Adds producers where mouse is dragged
functionmouseDragged(){if(millisecond %2==0){
producer =(newmakeProducer(mouseX, mouseY,30));
PRODUCERS[time]= producer;}}
//------------------------------------------
// Producers
// Make food from sunlight
// Grows overtime and increase cell amount
var PRODUCERS ={};
// Creates prodcuers that grows from light
// Producers are eaten by turtles
// Input: x,y, energy, dx, dy
functionmakeProducer(x, y, energy =10, dx =0, dy =0){this.x = x;this.y = y;this.life_index =random(-1,1); //random seem for perlin beheavior
this.life_index2 =random(-1,1); //random seem for perlin beheavior
this.energy = energy;this.c =color(0,255/2,0,255*random(.5,1));this.mitosis =false;this.dx = dx;this.dy = dy;}
// Draws producers
functiondrawProducer(){for(key in PRODUCERS){
x = PRODUCERS[key].x;
y = PRODUCERS[key].y;
c = PRODUCERS[key].c;
energy = PRODUCERS[key].energy;fill(c);strokeWeight(1) // Perlin noise to size to give it life
base_vivacity =5;
speed =1
life = base_vivacity *(sin(time /5* speed)) // Make rectangles rotate randomly
push();rectMode(CENTER);translate(x, y);rotate((noise(PRODUCERS[key].life_index)*360));rect(0,0, energy + life, energy + life);pop(); // Debug mode
if(debug_mode ==true){fill(255);textAlign(CENTER);text(round(PRODUCERS[key].energy), x, y);}}}
// Makes producer grow and reproduce if it has enough energy
functiongrowProducer(){for(key in PRODUCERS){ // Grow Producer
life_index = PRODUCERS[key].life_index;
PRODUCERS[key].energy +=noise(time * life_index)/4; // Reproduce
if(PRODUCERS[key].energy >50){
PRODUCERS[key].mitosis =true}}}
// Producers preform mitosis by using it's energy to reproduce
functionmitosisProducer(){for(key in PRODUCERS){if(PRODUCERS[key].mitosis ==true){
energy = PRODUCERS[key].energy
// Create 2 new cells
for(i =0; i <2; i++){
producer =(newmakeProducer(
PRODUCERS[key].x,
PRODUCERS[key].y,5,random(-energy /4, energy /4),random(-energy /4, energy /4)));
PRODUCERS[time]= producer;
PRODUCERS[key].energy -=25;}}}}
// Basic Physics for producer while splittig
functionmitosisPhysic(){for(key in PRODUCERS){
PRODUCERS[key].x += PRODUCERS[key].dx;
PRODUCERS[key].y += PRODUCERS[key].dy;
PRODUCERS[key].dx =lerp(PRODUCERS[key].dx,0,.1);
PRODUCERS[key].dy =lerp(PRODUCERS[key].dy,0,.1);}}
// Kills Producer if its energy is below 0.
functiondieProducer(){for(key in PRODUCERS){if(PRODUCERS[key].energy <0){
delete PRODUCERS[key]}}}
// Give Producer Perlin noise to make it look alive
functionlifeProducer(){for(key in PRODUCERS){
SIZE =.5;
lifeX =(noise(time * PRODUCERS[key].life_index)-.5)* SIZE;
lifeY =(noise(time * PRODUCERS[key].life_index2)-.5)* SIZE;
PRODUCERS[key].x += lifeX;
PRODUCERS[key].y += lifeY;}}var producer_timer =1;
// Adds new producer into the system every producer timer interval
functionadd_food(interval){
producer_timer +=1;print(producer_timer)if(producer_timer %500==0){for(var i =0; i <random(0,6); i++){
PRODUCERS[time]=(newmakeProducer(random(0, w),random(0, h),1));
time +=.1;}}}
//------------------------------------------
// SETUP
functionpreload(){
w = windowWidth;
h = windowHeight;}
// Creates petri dish
functionsetup(){createCanvas(w, h);background(255);
num_node =100; // Create a diverse genetic pool of consumers
for(i =0; i < num_node; i++){
t =makeTurtle(random(0, w),random(0, h));
turtles_AI.push(t);} // Initial set of producers
for(i =0; i < num_node /10; i++){
PRODUCERS[i]=(newmakeProducer(random(0, w),random(0, h)));}}
//------------------------------------------
functiondraw(){background(255,255,255,255*.33);
millisecond =floor(millis())%2000; // Model
time +=.1;turtle_move_AI();contain(turtles_AI);contain(PRODUCERS);HUNT();MATE()turtle_update(); // Producers
growProducer();dieProducer();mitosisProducer();mitosisPhysic();lifeProducer();add_food(1000); // Draw
noStroke();drawTurtle();drawProducer();}
Producer splits into two after growing big enough:
Producers splitting.
Consumers mate after it exceeds a certain caloric threshold and combines their genes with some amount of mutation:
Consumers mating.
At first, the simulation begins with a lot genetic diversity:
The simulation begins with a lot gentic diversity.
But over time due to natural selection for faster (darker) consumers, the genetic diversity is significantly decreased:
Over time natural selection reduces genetic diversity.
Interestingly, membrane-like structures also start to emerge from how food is being consumed. Here, the producers form a membrane around a dense cluster of producers that is rapidly splitting.
Membrane-like structures emerged although it wasn’t explicity programmed.
These membrane-like and clusters macrostructures were not explicitly programmed, they emerge probabilistically out of the specification and rules of this simulation. Here, a wall of producer is protecting a rapidly splitting colony of producers.
Wall of producers protecting a rapidly growing colony.
Group behavior also emerged out of the algorithm. Here, the producers began to form almost cell like clusters where food is rapidly consumed and reproduction distance is significantly decreased thereby creating a cell-like unit.
Individual cell-like clusters of rapidly reproducing and consuming begin to emerge.Here, one cell-like cluster separately moves towards another group of producers.Last colony of producers consumed.
As the system reaches its carrying capacity, the producer begins to starve and die.
No more food left.Consumers begin to starve and die.As food emerge, the cycle of population repeats.
And as this cycle of extreme population swing for both the producers and consumers restarts, the genetic diversity of population doesn’t. Over time, despite natural mutation rate, the consumer population becomes abosolutely homogenous without any genetic diversity. In real life, this means that the population is extremely susceptible to a disease that can complete wipe its whole population out.
No more genetic diversity is left.
Conclusion:
Features can be created implicitly through explicitly programming beheaviors. Alhtough certain feaures of this simulation wasn’t explicity programmed, it emerge through the algorithms of the character’s beheavior.
A system of genetic evolution will never reach its ultimate form. Although the black ones were the fastest, they needed to reproduced with inferior consumers thereby creating sub par offpsrings. Over time, this means that humans as a geneticically evolving organsims will never reach our ultimate form, if such form exist.
What happens when there is no genetic diversity? If life on earth continued to evolve due to natural selection and converge towards an ideal form and homogenity what would happen?
//Michelle Janco
//mjanco@andrew.cmu.edu
//Final Project - Section B
var fish =[];var tree =.05;var treeSpeed =.0009;var lX =300;var song;
//yellow sky color
var yellowSkyR =240;var yellowSkyG =215;var yellowSkyB =87;
//new sky color
var skyR =217;var skyG =98;var skyB =88;functionsetup(){createCanvas(640,240); // create fish
for(var i =0; i <5; i++){var rx =random(width);
fish[i]=makefish(rx);}frameRate(30);}functiondraw(){background(yellowSkyR, yellowSkyG, yellowSkyB);displayHorizon();makeTree();updateAndDisplayfish();removefishThatAreOutOfView();addNewfishWithSomeRandomProbability(); //change background color as mouse
//moves across canvas
if((mouseX >=640)&(mouseX <=640)){
mouseX =640;}if((mouseX >0)&(mouseX <640)){
yellowSkyR = mouseX*((217-240)/640)+240;
yellowSkyG = mouseX*((98-215)/640)+215;
yellowSkyB = mouseX*((88-87)/640)+87;} //big cloud
fill(255);ellipse(mouseX +5,55,20);ellipse(mouseX +25,50,35);ellipse(mouseX +40,60,25);ellipse(mouseX +55,50,40);ellipse(mouseX +80,50,25);ellipse(mouseX +95,55,15); //smaller cloud
fill(255);ellipse(mouseX +68,10,10);ellipse(mouseX +80,10,20);ellipse(mouseX +95,10,25);ellipse(mouseX +110,10,30);ellipse(mouseX +125,8,30);ellipse(mouseX +140,10,15);ellipse(mouseX +145,10,10); //smallest cloud
fill(255);ellipse(mouseX +268,40,10);ellipse(mouseX +280,40,20);ellipse(mouseX +295,40,25);ellipse(mouseX +310,40,40);ellipse(mouseX +325,38,30);ellipse(mouseX +340,40,15);ellipse(mouseX +345,40,10);}functionmouseClicked(){ //if mouse is inside sun, draw text
var d =dist(mouseX, mouseY,550,50);if(d <100){showText(true);}}functionshowText(mouse){if(mouse==true){textSize(32);fill(0);text("Salmon Skies",20,50);}}
//make trees
functionmakeTree(){noStroke();fill(22,60,28);beginShape();for(var i =0; i < width; i++){var x =(i * tree)+(millis()* treeSpeed);var y =map(noise(x),0,1, height/2, height/3);vertex(i, y);}vertex(width, height-height/2);vertex(0, height-height/2);endShape();}functiondisplayHorizon(){noStroke();line(0,height-height/2, width, height-height/2); //pond
fill(44,80,108);rect(0, height-height/2, width, height-height/2); //sun
fill(240);noStroke();ellipse(550,50,50,50);}functionupdateAndDisplayfish(){ // update fish positions, display them
for(var i =0; i < fish.length; i++){
fish[i].move();
fish[i].display();}}functionremovefishThatAreOutOfView(){ //if entirety of the fish are off canvas
//then remove them
var fishToKeep =[];for(var i =0; i < fish.length; i++){if(fish[i].x + fish[i].breadth >0){
fishToKeep.push(fish[i]);}}
fish = fishToKeep;}functionaddNewfishWithSomeRandomProbability(){ //small probability, add a new fish to the end
var newfishLikelihood =0.005;if(random(0,1)< newfishLikelihood){
fish.push(makefish(width));}}
//update position of fish
functionfishMove(){this.x +=this.speed;}
//draw the fish
functionfishDisplay(){var fishHeight =random(10,15);var fHeight =(20);fill(219,97,87,150);noStroke();push();translate(this.x, height -60); //fish body
ellipse(0,-fHeight,this.breadth, fishHeight);fill(255); //fish eyes
ellipse(-13,-fHeight,4,6);fill(0);ellipse(-13,-fHeight,2,3); //fish fins
fill(219,97,87,150);ellipse(0,-fHeight+7,4,8);fill(219,97,87,150);ellipse(-2,-fHeight-7,6,8);fill(219,97,87,150);arc(23,-fHeight,30,30,0, HALF_PI); //fish reflection
fill(219,97,87,30);ellipse(0, fHeight,this.breadth, fishHeight); //reflection fish eyes
fill(255,30);ellipse(-13, fHeight,4,6);fill(0,30);ellipse(-13, fHeight,2,3); //reflection fish fins
fill(219,97,87,30);ellipse(0, fHeight+7,4,8);fill(219,97,87,30);ellipse(-2, fHeight-7,6,8);fill(219,97,87,30);arc(23, fHeight,30,30,0, HALF_PI)pop();}functionmakefish(birthLocationX){var fis ={x: birthLocationX,
breadth:50,
speed:-2.0,
nlil:round(random(2,40)),
move: fishMove,
display: fishDisplay}return fis;}
For this project, I wanted to go back to a concept that I struggled with. During the generative landscape project, I ran into quite a few problems and was not able to make an image that I found aesthetically pleasing. I wanted to return to this, and have more time to work through the concepts to be able to make something calming to watch. I am drawn to imagery that relaxes the viewer, and I imagine this is the type of image that could be watched to slow down a person’s heart rate, as the fish move at a calming pace. I love going to the lake back home with my Dad and watching the fish go by, which was always a therapeutic activity. This image in my head was what I wanted to emulate. Considering the amount of difficulty and trouble I have faced in this class, I’m glad I had extra time to really focus, take my time, and make something that feels fairly complete. I learned a lot more skills from being able to slow down and focus on these concepts.
//Cora Hickoff
//Section D
//chickoff@andrew.cmu.edu
//Final-Project
//image of dog
var imgD;
//image of fish
var imgF;
//for iterating through dog and fish photos
var num =0;
//images of dog
var loadedImagesD =[];
//images of fish
var loadedImagesF =[];
//for dragging mouse
var xarray =[];var yarray =[];
//variables for moth
var x;var y;var dx;var dy;
//variables for blue moth
var w;var z;var dw;var dz;
//variables for bee
var b;var p;var db;var dp;functionpreload(){var backgroundImageURL ="https://i.imgur.com/qDrD310.png";
backgroundIMG =loadImage(backgroundImageURL);var sunImageURL ="https://i.imgur.com/6SDAJjt.png";
sunIMG =loadImage(sunImageURL);var mothImageURL ="https://i.imgur.com/bGUODEv.png?1";
mothIMG =loadImage(mothImageURL);var bluemothImageURL ="https://i.imgur.com/FR3gCsQ.png";
bluemothIMG =loadImage(bluemothImageURL);var beeImageURL ="https://i.imgur.com/oTcCy45.png";
beeIMG =loadImage(beeImageURL); //dog photos
for(var i =0; i < dogPhotos.length; i++){
loadedImagesD.push(loadImage(dogPhotos[i]));} //fish photos
for(var i =0; i < fishPhotos.length; i++){
loadedImagesF.push(loadImage(fishPhotos[i]));}}functionsetup(){createCanvas(700,500);var d =floor(random(0, dogPhotos.length));var f =floor(random(0,0, fishPhotos.length)); //images of dog
imgD = loadedImagesD[d]; //images of fish
imgF = loadedImagesF[f];
x =random(width);
y =random(height);
dx =random(-5,5);
dy =random(-5,5);
w =random(width);
z =random(height);
dw =random(-5,5);
dz =random(-5,5);
b =random(width);
p =random(height);
db =random(-5,5);
dp =random(-5,5);}functiondraw(){background(200); //photo of background
image(backgroundIMG,0,0,0); //photo of sun
image(sunIMG,0,0,0); //photo of dog
image(imgD,0,0, imgD.width, imgD.height); //photo of fish
image(imgF,0,0, imgF.width, imgF.height); //drags smaller dog image along canvas
for(var i =0; i < xarray.length; i++){fill(0);image(imgD, xarray[i], yarray[i], imgD.width/2.4, imgD.height/2.4);}if(xarray.length >8){
xarray.shift(1);
yarray.shift(1);} //photo of moth
image(mothIMG, x, y, mothIMG.width/2.3, mothIMG.height/2.3);
x += dx;
y += dy; //if image exceeds canvas width,
//set back to 0
if(x > width) x =0;elseif(x <0) x = width; //if image exceeds canvas height,
//set back to 0
if(y > height) y =0;elseif(y <0) y = height; //photo of blue moth
image(bluemothIMG, w, z, bluemothIMG.width/1.9, bluemothIMG.height/1.9);
w += dw;
z += dz; //if image exceeds canvas width,
//set back to 0
if(w > width) w =0;elseif(w <0) w = width; //if image exceeds canvas height,
//set back to 0
if(z > height) z =0;elseif(z <0) z = height; //photo of bee
image(beeIMG, b, p, beeIMG.width/2.5, beeIMG.height/2.5);
b += db;
p += dp; //if image exceeds canvas width,
//set back to 0
if(b > width) b =0;elseif(b <0) b = width; //if image exceeds canvas height,
//set back to 0
if(p > height) p =0;elseif(p <0) p = height; //lightens screen when mouse over sun
if(mouseX <=398& mouseX >=320&& mouseY >=30&& mouseY <=105){rectMode(CORNER);noStroke();fill(246,215,161,70);rect(0,0,700,500);}}functionmouseDragged(){
xarray.push(mouseX);
yarray.push(mouseY);}functionmousePressed(){ //iterates through dog photos when mouse clicks its body
if(mouseX <=500& mouseX >=150&& mouseY >=275&& mouseY <=400){var d = num % dogPhotos.length;
imgD = loadedImagesD[d];
num++;} //iterates through fish photos when mouse clicks blanket
if(mouseX <=700& mouseX >=0&& mouseY >=130&& mouseY <=250){var f = num % fishPhotos.length;
imgF = loadedImagesF[f];
num++;}}var dogPhotos =[ //rusty-colored dog
"https://i.imgur.com/2vglMnn.png", //white/pink dog
"https://i.imgur.com/IWbYamo.png", //lilac dog
"https://i.imgur.com/I5xU7LF.png", //black dog
"https://i.imgur.com/AAQQgCj.png", //blue dog
"https://i.imgur.com/CTZSr9D.png", //mulberry dog
"https://i.imgur.com/kt5rN0R.png"]var fishPhotos =[ //first fish
"https://i.imgur.com/bD3GBjE.png", //second fish
"https://i.imgur.com/eUWa3dx.png", //third fish
"https://i.imgur.com/XJFlBTd.png"]
When I started this project, I knew that I wanted to give users a hands-on experience, similar to the I Spy computer games that I’d play as a kid, which I drew inspiration from. The worlds created in these games still felt genuine despite the fact that they were within a computer screen. This is in part because photos from real life were used.
Moreover, I really loved the Mixies Assignment and that it felt like we were playing with puzzle pieces and working with our hands, even though we were doing this electronically. This is why I chose to use photos that I’ve taken and use similar methods from that assignment to make this project interactive and fun.
//Daphne Lee
//15-104::1 (9:30am) Section D
//daphnel@andrew.cmu.edu
//Final-Project
//x is x location of ball;
//y is y location of ball;
var x =200;var y =200;var dirx =1;var diry =5;var speed =0.75;var paddleWidth =75;var paddleHeight =10;var ballDiam =20;var score =0;var lives =3;var scaled =0.6;var blockRowCount =4;var blockColCount =13;var blockWidth =50;var blockHeight =20;var blockPadding =10;var blockOffsetX =30;var blockOffsetY =10;var blockXArr =[];var blockYArr =[];var statusArr =[];var started =false;
//preloaded items
var bg;var girlLeft;var girlRight;var girlYPosition =150;var girlsSize =100;var press;var enter;functionpreload(){
bg =loadImage("https://i.imgur.com/kElOb6m.jpg"); //items on the start page before game starts
if(started==false){
press =loadImage("https://i.imgur.com/kbAP99M.png");
enter =loadImage("https://i.imgur.com/4ijF2zc.png") // the girl gifs on the start screen
girlLeft =createImg("https://i.imgur.com/IjEVc03.gif");
girlLeft.position(150* scaled, girlYPosition * scaled);
girlLeft.size(girlsSize, girlsSize)
girlRight =createImg("https://i.imgur.com/IjEVc03.gif");
girlRight.position(500* scaled, girlYPosition * scaled);
girlRight.size(girlsSize, girlsSize);}}functionsetup(){createCanvas(800,400);for(var i =0; i < blockRowCount * blockColCount; i++){ //status makes sure if blocks disappear or remain
statusArr.push(1);}}functioncollision(){for(var c =0; c < blockColCount; c++){for(var r =0; r < blockRowCount; r++){if(statusArr[r * blockColCount + c]==1){var radius = ballDiam /2; //creating the blocks;
var blockX = c *(blockWidth + blockPadding)+ radius
var blockY = r *(blockHeight + blockPadding)+ radius; //collision points for each block;
var minXCollide = blockX - radius;var maxXCollide = blockX + radius + blockWidth;var minYCollide = blockY - radius;var maxYCollide = blockY + radius + blockHeight;var collidesX =(x > minXCollide & x < maxXCollide);var collidesY =(y > minYCollide & y < maxYCollide) //what happens as a result of the collision;
if(collidesX & collidesY){
diry =-diry;
score++;
statusArr[r * blockColCount + c]=0;}}}}}functioncountScore(){stroke(255);strokeWeight(1);textSize(15); //gives you a score when you lose
text("Score: "+ score, width -70, height -10);}functiondrawLives(){stroke(255);strokeWeight(1);textSize(15); //shows you the number of lives you have
text("Lives: "+ lives,10, height -10);}
//creating the end result of what happens if you destroy all the blocks
functioncongrats(){if(score == blockColCount * blockRowCount){fill("lavender");textStyle(BOLD);textFont("cursive",50);text("Congratulations You Won!",120,200);}}functiondraw(){scale(scaled);background(bg);noStroke();var textWidth =150;var textHeight =50; //creates the beginning press enter text before the game starts
if(started ==false){image(press,340,150, textWidth, textHeight);image(enter,340,210, textWidth, textHeight);}if(started){ //ping pong ball
rectMode(CENTER);fill(255);ellipse(x, y, ballDiam, ballDiam); //the paddle on the bottom
fill(100,300);rect(mouseX * scaled *3, height - paddleHeight, paddleWidth,
paddleHeight); //moves the ball
x += dirx * speed;
y += diry * speed; //left and right wall boundaries
if(x > width - ballDiam /2|| x < ballDiam /2){
dirx =-dirx;} //top wall boundary
if(y < ballDiam /2){
diry =-diry;} // else if(y > height + ballDiam / 2){
if(lives >0& y > height + ballDiam /2){
x = width /2;
y = height /2;
lives --;}elseif(lives ==0){
speed =0;stroke(0);fill("lavender");textStyle(BOLD);textFont("cursive",50); //creating text to show if you fail to complete game
text("GAME OVER",250,200);textSize(20);text("Score: "+ score,350,250);} //Collision detection for the paddle
var radius = ballDiam /2;var minXCollide =(mouseX * scaled *3)- radius - paddleWidth /2;var maxXCollide =(mouseX * scaled *3)+ radius + paddleWidth /2;var minYCollide =(height - paddleHeight)- radius - paddleHeight /2;var maxYCollide =(height - paddleHeight)+ radius + paddleHeight /2var collidesX =(x >= minXCollide & x <= maxXCollide);var collidesY =(y >= minYCollide & y <= maxYCollide)if(collidesX && collidesY){if(diry >0){
diry =-diry;
dirx =random(-5,5);
dirx =-dirx;}}countScore();drawLives();rectMode(CORNER); //creating the blocks
for(var c =0; c < blockColCount; c++){for(var r =0; r < blockRowCount; r++){if(statusArr[r * blockColCount + c]==1){var blockX = c *(blockWidth + blockPadding)+ ballDiam /2;var blockY = r *(blockHeight + blockPadding)+ ballDiam /2;fill(100,100);stroke(255);strokeWeight(1);rect(blockX, blockY, blockWidth, blockHeight);}}}collision();congrats();}}functionkeyPressed(){ // start the game
if(keyCode ==13){ //hides the girls running in the beginning frame before the game starts
girlLeft.hide();
girlRight.hide();
started =true;}}
I had a lot of ideas for my proposal but I found implementing the ideas I had difficult. For my project, I focused on keeping it at one level. You start out with three lives and whenever you die, the ball will reset at the middle of the canvas and move downwards from there. Once the 3 chances are used, it’s game over. I made it so that even if you are late in hitting the ball and you hit the left or right edge of the paddle, the ball could still be saved and move back up. As long as any contact with the paddle is made, the ball will be in play. When two side by side blocks are simultaneously hit by a ball due to the ball hitting the blocks directly in between the blocks, both blocks will disappear and the ball will continue moving upwards or diagonally until it has reached a solid border like the wall or the edge of another block.
Some Key Points
Note that the ball moves randomly at all times so you need to make sure to keep your focus on the direction of the ball at all times.
Refresh the page to play the game again.
The ball is reset in the middle of the screen when you die and will immediately start moving again towards a random downwards direction.
For Graders:: TIP! Playing this game takes a while so if you would like, you can increase the PaddleWidth from 75 to 800 or 900 and center it on the screen and let it just run itself until the blocks are all gone.
This game does not work as well on WordPress due to some parts of the code that could not be scaled well. Please click below for the Zip File to the full size of the game.
//Robert Managad
//Section-E
//rmanagad@andrew.cmu.edu
//Final Project -- Trigonometric Loading Icons
//This code loops on the basis of the trigonometric functions cosine, sine, and tangent.
//It can be modified to produce three distinct animations, depending on the trig function used,
// and on the axis be affected.
var spins =[];var drips =[];var warps =[];var pluss =[];functionsetup(){createCanvas(420,420); //Spin Loop, center
push();for(var i =0; i <12; i++){var spinposition =createVector(i *20, i);var spinradius = i *1; // Radius increases by 200% for every iteration of i, up to 12.
spins[i]=newSpin(spinposition, spinradius); //holds circle function in the array
}pop(); //Drip loop, top center
for(var i =0; i <8; i++){var dripposition =createVector(i*18, i);var dripradius = i *2;
drips[i]=newDrip(dripposition, dripradius);} //Warp loop, left center
for(var i =0; i <12; i++){var warpposition =createVector(i*20, i);var warpradius = i *1.5;
warps[i]=newWarp(warpposition, warpradius);} //Plus loop, left center
for(var i =0; i <12; i++){var plusposition =createVector(i*20, i);var plusradius = i *1.5;
pluss[i]=newPlus(plusposition, plusradius);}}functiondraw(){background(0); //drip draw
for(var i = drips.length -1; i >=0; i--){var drip = drips[i];
drip.update();
drip.display();} //rectangle mask
fill(0);noStroke();rect(140,130,140,300); //warp draw
for(var i = warps.length -1; i >=0; i--){var warp = warps[i];
warp.update();
warp.display();} //spin draw
for(var i = spins.length -1; i >=0; i--){var spin = spins[i];
spin.update();
spin.display();} //plus draw
for(var i = pluss.length -1; i >=0; i--){var plus = pluss[i];
plus.update();
plus.display();}}
//--------------------
//elements of each circle are compounded into the Spin function.
functionSpin(spinposition, spinradius){this.position = spinposition;this.radius = spinradius;this.direction =1;this.time =0; //controls the placement of the starting anchor, time to jump towards.
//updates position every time draw is called.
this.update =function(){this.time +=this.direction *this.radius *0.007; //holds value of velocity. Higher radius value = higher speed.
this.position.y =(200+90*cos(this.time))/2;this.position.x =(200+90*sin(this.time))/2; //trig function directs the animation (slowing down in middle/accelerating the circles as they approach the edges)
} //holds visual presentation
this.display =function(){noFill();stroke(255);strokeWeight(1.5);ellipse(this.position.x -20,this.position.y -20,this.radius,this.radius);}}
//---------------------
functionDrip(dripposition, dripradius){this.position = dripposition;this.radius = dripradius;this.direction =1;this.time =0; //controls the placement of the starting anchor, time to jump towards.
//updates position every time draw is called.
this.update =function(){this.time +=this.direction *this.radius *0.004; //holds value of velocity. Higher radius value = higher speed.
this.position.y =(200+90*tan(this.time))/3; //trig function directs the animation (slowing down in middle/accelerating the circles as they approach the edges)
} //holds visual presentation
this.display =function(){noFill();stroke(255);strokeWeight(1.5);ellipse(this.position.x +275,this.position.y -10,this.radius,this.radius);}}
//------------------------
functionWarp(warpposition, warpradius){this.position = warpposition;this.radius = warpradius;this.direction =1;this.time =0; //controls the placement of the starting anchor, time to jump towards.
//updates position every time draw is called.
this.update =function(){this.time +=this.direction *this.radius *0.002; //holds value of velocity. Higher radius value = higher speed.
this.position.y =200+30*cos(this.time);this.position.x =200+30*tan(this.time); //trig function directs the animation (slowing down in middle/accelerating the circles as they approach the edges)
} //holds visual presentation
this.display =function(){noFill();stroke(255);strokeWeight(1.5);ellipse(this.position.x ,this.position.y +160,this.radius,this.radius);}}
//----------------------------
functionPlus(plusposition, plusradius){this.position = plusposition;this.radius = plusradius;this.direction =1;this.time =0; //controls the placement of the starting anchor, time to jump towards.
//updates position every time draw is called.
this.update =function(){this.time +=this.direction *this.radius *0.002; //holds value of velocity. Higher radius value = higher speed.
this.position.y =200+40*1/cos(this.time)/3;this.position.x =200+40*1/sin(this.time)/3; //trig function directs the animation (slowing down in middle/accelerating the circles as they approach the edges)
} //holds visual presentation
this.display =function(){noFill();stroke(255);strokeWeight(1.5);ellipse(this.position.x ,this.position.y,this.radius,this.radius);}}
If gifs below are frozen: right-click and open the image in a new tab.
My final project culminated in a series of six loading icons. I used trigonometric functions to calculate x and y positions — because of their cyclical behaviours, sin, cosine, and tangent worked well for looping animations. Individual animation gifs can be seen above. Process work can be seen below
From a design standpoint, I developed these loading icons with several human factors in mind — from longevity and human attention span, to interactivity and engagement. Repetition in form, symmetry in composition and shape, and cyclical rhythm all contribute to keeping people from becoming disengaged with the content. As a component living in a transitionary space, the loading icon serves to bridge one space to the next.
Loading icon sketches on Illustratorinitial sketches
// Jenny Zhang
// jennyzha
// Section D
// Final Project
var img;
//setting a global variable for picture the user can paint
var col =[0,0,0,0];
//setting a an initial color for the paintbrush color
var aSlider;
//setting a global variable for the slider that will control the width of the brush
var SizeOfBrush =10;
//setting initial SizeOfBrush for the width of the brush
functionpreload(){var imgs =[]; //preloading all of the possible images the user can paint into an array
imgs[0]="http://i.imgur.com/UyyTNyF.png";
imgs[1]="http://i.imgur.com/sW4fWRP.png";
imgs[2]="http://i.imgur.com/6HBfsCu.png";
imgs[3]="http://i.imgur.com/60ITEbG.png";
imgs[4]="http://i.imgur.com/Zli7OsC.png";
imgs[5]="http://i.imgur.com/ztRhRts.png";
imgs[6]="http://i.imgur.com/Qx8zJO4.png";
imgs[7]="http://i.imgur.com/mzxbto4.png";
imgs[8]="http://i.imgur.com/vXdn15r.png";
imgs[9]="http://i.imgur.com/shwrAy5.png";
imgs[10]="http://i.imgur.com/manEqm3.png";
imgs[11]="http://i.imgur.com/oh8iKpK.png";
imgs[12]="http://i.imgur.com/oh8iKpK.png";
imgs[13]="http://i.imgur.com/306OVy6.png";
imgs[14]="http://i.imgur.com/xJVNo7U.png";
imgs[15]="http://i.imgur.com/4mv8uhP.png";
imgs[16]="http://i.imgur.com/MvNo2DV.png";
imgs[17]="http://i.imgur.com/dxlMoKR.png";
imgs[18]="http://i.imgur.com/mxti4c2.png";
imgs[19]="http://i.imgur.com/hDtDFhD.png";
imgs[20]="http://i.imgur.com/shwrAy5.png";var num =floor(random(0, imgs.length)); //randomly choosing a picture from the array to paint
img =loadImage(imgs[num]); //assigning the image to the variable img
}functionsetup(){createCanvas(800,650);background(145,200,200);
aSlider =createSlider(10,50, SizeOfBrush);
aSlider.position(670,620); //creating the slider, placing it at the bottom of the canvas
fill(250);noStroke();rect(0,300,800,650); //creating the canvas that the user will draw on
fill(145,200,200);noStroke();rect(0,590,800,650); //creating the canvas that the user will draw on
fill(0);textSize(20);text("Paint Away!",0,20); //writing the title of the page
fill(0);textSize(15);text("Click on the painting to choose your color, then paint by clicking on the bottom canvas provided.",0,40); //writing the instructions to choosing your color
fill(0);textSize(15);text("Move the slider in the bottom right corner to change the size of your paint brush.",0,55); //writing the instructions to choosing your paintbrush size
}functionmousePressed(){
SizeOfBrush = aSlider.value(); //setting the width of the brush SizeOfBrush to the slider value
//this is adapted from lab 15
if(mouseX >0& mouseX <800&& mouseY >0&& mouseY <350){
col =get(mouseX, mouseY);} //creating a restriction that the user can only get their color from the provided image
elseif(mouseX >0& mouseX <800&& mouseY >350&& mouseY <600- SizeOfBrush/2){fill(color(col));ellipse(mouseX, mouseY, SizeOfBrush);} //telling the program that anywhere else besides the picture, they can draw a single ellipse
fill(145,200,200);rect(70,615,250,15); //effectively "erases"/"refreshes" the text every time the draw function is called
fill(0);textSize(12);text("Your brush color is ("+ col +")",70,625); //creates a text box telling you your current paintbrush color
//this is adapted from assignment 11A, text rain
}functionmouseDragged(){
SizeOfBrush = aSlider.value(); //setting the brush size to the slider value
if(mouseX >0& mouseY >0&&
mouseX <800&& mouseY >300&&
mouseY <600- SizeOfBrush/2){noStroke();fill(color(col)); //setting the restriction so that when the mouse is dragged the user can draw in the provided canvas area
ellipse(mouseX, mouseY, SizeOfBrush);}}functiondraw(){image(img,0,60); //place current picture the user will draw
fill(color(col));rect(10,595,50,50); //creates the square in the botton that shows the current color the user is using
}
My final project is essentially a virtual coloring book. The steps are very simple and easy. All you have to do is refresh the page if you don’t want to paint the painting provided until you are satisfied with the one loaded. Next, choose your first color to paint with by clicking on the color in the painting. Afterwards, choose the thickness of your brush by sliding the slider in the bottom right corner. Finally, click or drag across the bottom half of the screen, or your “canvas” to draw!
*unfortunately, wordpress is unable to handle the canvas size of the program, that being said, please refer to the attached zip file for the full effect – thank you!*
//Ashley Chan
//Section C
//ashleyc1@andrew.cmu.edu
//Final Project - Type in Motion
/////////////////////////////////////
// MAIN CONTROL //
///////////////////////////////////
var index =0;
//global var for images
var revealImg;var twinkleImg;var eraseImg;var sprayHintImage;var sprayOverlayImage;functionpreload(){
//load all the images
revealImg =loadImage("https://i.Imgur.com/giFSIcI.jpg?1");
twinkleImg =loadImage("https://i.imgur.com/hqn6Cv9.jpg?1");
eraseImg =loadImage("https://i.imgur.com/VO4buSz.png");
sprayHintImage =loadImage("https://i.imgur.com/P6LkUET.jpg");
sprayOverlayImage =loadImage("https://i.imgur.com/dr6JWoH.png");}functionsetup(){createCanvas(480,180);background(0); //index that cycles through animations
//call each animations' setups
//depending on index number
if(index ==0){revealSetup();}if(index ==1){twinkleSetup();}if(index ==2){eraseSetup();}if(index ==3){spraySetup();}}functiondraw(){ //call each animations' draw depending on index number
if(index ==0){revealDraw();}if(index ==1){twinkleDraw();}if(index ==2){eraseDraw();}if(index ==3){sprayDraw();}}
// Cycles through animations every time
//any key is pressed
functionkeyPressed(){
index =(index +1)%4;setup();}
////////////////////////////////////////////
// REVEAL ANIMATION //
///////////////////////////////////////////
//var that will spell out reveal
var revealCircles;var revealDots;functionrevealSetup(){ //Draw a black rectangle for every animation
//because we need to make sure the animations
//restart without actually calling setup
//and messing everything up
fill(0);rect(0,0,480,180);
revealCircles =[];
revealDots =[]; // iterate through pixels
image(revealImg,0,100);
revealImg.loadPixels();for(var i =0; i <2* revealImg.width; i++){for(var j =0; j < revealImg.height; j++){var revealIndex = i *2+(j * revealImg.width)*8; //locate the dark pixels of underlaying image
//where there is dark, make a revealCircle
if(revealImg.pixels[revealIndex]<200){
revealDots.push(createVector( i /2, j *2));}}}var num_circles =0; //draw certain number of revealCircles every frame
while(num_circles <400){var c =revealCreateCircle();if(c){
revealCircles.push(c);
num_circles++;}}}functionrevealDraw(){background(0); //draw the revealCircles
for(var i =0; i < revealCircles.length; i++){var x = revealCircles[i].x;var y = revealCircles[i].y;var r = revealCircles[i].r; //calculate distance around mouse
//any space within radius will be drawn and shown
var d =dist(x, y, mouseX, mouseY);if(d <90){ //center image
push();scale(.5,.5);translate(150,0);
revealCircles[i].show();pop();}}}
//While creating a new revealCircle
//Do not create one inside existing one
functionrevealCreateCircle(){var x;var y; // find a random position to create a revealCircle
var position =int(random(0, revealDots.length));
x = revealDots[position].x;
y = revealDots[position].y;var valid =true;for(var i =0; i < revealCircles.length; i++){ //Don't draw inside another revealCircle
// If generated already drawn revealCircle, redo
if(dist(x, y, revealCircles[i].x, revealCircles[i].y)<= revealCircles[i].r){
valid =false;break;}} //if no revealCircle drawn at spot, draw one
if(valid){returnnewrevealCircle(x, y, width, height);}returnfalse;}
//define the circles
functionrevealCircle(xPos, yPos, gwidth, gheight){this.x = xPos;this.y = yPos;this.r =8;this.width = gwidth;this.height = gheight; //controls the look of the revealCircles
//randomizes color when mouse is pressed
this.show =function(){fill(255);noStroke();strokeWeight(1);ellipse(this.x,this.y,this.r);}}
////////////////////////////////////////////////
// TWINKLE ANIMATION //
///////////////////////////////////////////////
//var that will spell out twinkle
var twinkleCircles;var twinkleDots;functiontwinkleSetup(){fill(0);rect(0,0,480,180);
twinkleCircles =[];
twinkleDots =[]; // iterate through pixels
//image(twinkleImg, 0, 100);
twinkleImg.loadPixels(); //locate the dark pixels of underlaying image
//where there is dark, make a twinkleCircle
for(var i =0; i <2* twinkleImg.width; i++){for(var j =0; j < twinkleImg.height; j++){var twinkleIndex = i *2+(j * twinkleImg.width)*8;if(twinkleImg.pixels[twinkleIndex]<200){
twinkleDots.push(createVector( i /2, j *2));}}}var num_circles =0; //draw certain number of twinkleCircles every frame
while(num_circles <300){var c =twinkleCreateCircle();if(c){
twinkleCircles.push(c);
num_circles++;}} //draw the twinkleCircles
for(var i =0; i < twinkleCircles.length; i++){var x = twinkleCircles[i].x;var y = twinkleCircles[i].y;var r = twinkleCircles[i].r; //center image
push();scale(.6,.6);translate(50,80);
twinkleCircles[i].show();pop();}}functiontwinkleDraw(){ //if mouse pressed, "redraw" circles
//so that color is randomized
if(mouseIsPressed){for(var i =0; i < twinkleCircles.length; i++){var x = twinkleCircles[i].x;var y = twinkleCircles[i].y;var r = twinkleCircles[i].r; //center image
push();scale(.6,.6);translate(50,80);
twinkleCircles[i].show();pop();}}}
//While creating a new twinkleCircle
//Do not create one inside existing one
functiontwinkleCreateCircle(){var x;var y; // find a random position to create a twinkleCircle
var position =int(random(0, twinkleDots.length));
x = twinkleDots[position].x;
y = twinkleDots[position].y;var valid =true;for(var i =0; i < twinkleCircles.length; i++){ //Don't draw inside another twinkleCircle
// If generate already drawn twinkleCircle, redo
if(dist(x, y, twinkleCircles[i].x, twinkleCircles[i].y)<= twinkleCircles[i].r){
valid =false;break;}} //if no twinkleCircle drawn at spot, draw one
if(valid){returnnewtwinkleCircle(x, y, width, height);}returnfalse;}
//define twinkleCircles
functiontwinkleCircle(xPos, yPos, gwidth, gheight){this.x = xPos;this.y = yPos;this.r =8;this.width = gwidth;this.height = gheight; //controls the look of the twinkleCircles
//randomizes color when mouse is pressed
this.show =function(){stroke(255);strokeWeight(1); //start out as empty twinkleCircles
var value =0;fill(value); //change the color every time mouse is pressed
if(mouseIsPressed){
value =random(0,255);fill(value, value, value);}ellipse(this.x,this.y,this.r);}}
////////////////////////////////////////////
// ERASE ANIMTATION //
///////////////////////////////////////////
//var for erase animation
var eraseLastMinute;var eraseCurrentMinute;
//eraseIndex for animations
var eraseIndex =0;functioneraseSetup(){ //scale(.5, .5);
fill(0);rect(0,0,480,180);
eraseImg.loadPixels();
eraseLastMinute =minute(); //make for loop to control how many images we are making
for(i =0; i <50; i++){image(eraseImg,random(-50,800),random(-50, height),100,43);}}functioneraseDraw(){fill(0);noStroke();ellipse(mouseX, mouseY,30,30); //call setup and reset every minute
eraseCurrentMinute =minute(); //if a minute has passed, call setup and generate
//different arrangement of words
if(eraseLastMinute != eraseCurrentMinute){eraseSetup();}}
///////////////////////////////////////////
// SPRAY ANIMATION //
//////////////////////////////////////////
var sprayDots;functionspraySetup(){fill(0);rect(0,0,480,180);noCursor();noStroke();
sprayDots =[];}functionsprayDraw(){image(sprayHintImage,50,100);
sprayHintImage.resize(300,100);background(0);var position =createVector(mouseX, mouseY); //if mouse is pressed, draw a bunch of sprayCircles
//that move toward the overlaying image
if(mouseIsPressed){var target =sprayFindPixel();var spraydot =newsprayDot(position, target);
sprayDots.push(spraydot); //allow user to draw a bunch of dots
if(sprayDots.length >2000) sprayDots.shift();} //draws the sprayDots
for(var i =0; i < sprayDots.length; i++){ //make sure sprayDots align with hint image
push();translate(100,50);
sprayDots[i].update();
sprayDots[i].draw();pop();} //call image of Spray outline
image(sprayOverlayImage,100,50);
sprayOverlayImage.resize(300,100);}
//calculate where the underlying image is dark
//and then draw a spraydot overtop
functionsprayFindPixel(){var x;var y;for(var i =0; i <200; i++){
x =floor(random(sprayHintImage.width));
y =floor(random(sprayHintImage.height));if(red(sprayHintImage.get(x, y))<255)break;}returncreateVector(x, y);}
//create sprayDots and define characteristics
functionsprayDot(position, target){this.position = position;this.target = target;this.diameter =random(10,20);}
sprayDot.prototype.update =function(){this.position =
p5.Vector.lerp(this.position,this.target,0.1);};
sprayDot.prototype.draw =function(){ //color of sprayDots
fill(255);ellipse(this.position.x,this.position.y,this.diameter,this.diameter);};
For this project, I was interested in creating interactive animations that allowed type to be dynamic. I wanted the user to interact with the text based on the actions the words described (erase = erase the words). This project was super challenging and I wish I had more time to generate more interactive animations but I’m overall satisfied with it because I like exploring how to make type more dynamic that I can now use within my own art and design practice.
//Christopher Reyes
//creyes1@andrew.cmu.edu
//Section D
//Capstone Project
//This program is a reinterpretation of Patatap (www.Patatap.com) created by
//Jono Brandel (jonobr1.com) and Lullatone (www.lullatone.com).
//Animations and drumkit sounds play if a key is pressed on the keyboard
//To differentiate from Patatap, there is a beat loop functionality that
//records the users\'s actions, then plays them in sequence for beatmaking
//DIRECTIONS
//SPEAKERS ON
//Press SPACEBAR to begin loop recording, play drum sounds with KEYS 1-5,
//Press SPACEBAR AGAIN to stop recording and play recorded beat
//Press SPACEBAR TWICE to clear loop
//Note: Records/plays one loop at a time
var introTextX =30; //Initalizes intro text position, sets to undefined to hide
//Color scheme - RGB values
var softYellow =[248,249,197]; //Background
var softPink =[252,202,199]; //For bigSlideH
var softViolet =[187,170,192]; //For bigSlideV
var lightCyan =[187,252,223]; //For rectSlide
var darkerTeal =[85,200,190]; //For ringPulse
var transWhite =[255,255,255,100]; //Transparent white for bg rings
//Looping variables and arrays
var actions =[]; //Lists actions performed
var actionFrames =[]; //Frames on which actions were performed
var actionSounds =[]; //Lists sounds to be played
var counter =0; //Counts frames
var counterMax; //Cap on frame count, signals when to loop
var actionIndex; //Relationship between actions, actionFrames, actionSounds
//Drumkit sound samples: "Urban Drum Samples" by user Biochron of soundpacks.com
//Source Link: https://soundpacks.com/free-sound-packs/urban-drum-samples/
var snare;var bass;var hihat;var hightom;var lowtom;functionpreload(){
snare =loadSound("https://courses.ideate.cmu.edu/15-104/f2017/wp-content/"+"uploads/2017/12/creyes1-snare.wav");
snare.setVolume(.3);
bass =loadSound("https://courses.ideate.cmu.edu/15-104/f2017/wp-content/"+"uploads/2017/12/creyes1-bass.wav");
bass.setVolume(1);
hihat =loadSound("https://courses.ideate.cmu.edu/15-104/f2017/wp-content/"+"uploads/2017/12/creyes1-hihat.wav");
hihat.setVolume(.6);
hightom =loadSound("https://courses.ideate.cmu.edu/15-104/f2017/"+"wp-content/uploads/2017/12/creyes1-hightom.wav");
hightom.setVolume(.5);
lowtom =loadSound("https://courses.ideate.cmu.edu/15-104/f2017/wp-content/"+"uploads/2017/12/creyes1-lowtom.wav");
lowtom.setVolume(.5);}functionsetup(){createCanvas(480,480);background(softYellow);}functiondraw(){background(softYellow); //Background detail, layered circles
noStroke();fill(transWhite);ellipse(width/2, height/2,400,400);fill(softYellow);ellipse(width/2, height/2,350,350);stroke(transWhite);noFill();strokeWeight(10);ellipse(width/2, height/2,320,320);strokeWeight(5);ellipse(width/2, height/2,500,500);noStroke();fill(transWhite);ellipse(width/2, height/2,200,200); //Introductory Text & Instructions
//Disappears once user begins playing
noStroke();fill(255);rect(introTextX-10,420,440,50,10);fill(100);textStyle(BOLD);textFont("Courier New",12);text('Press any key 1-5, press SPACEBAR to start/stop recording your loop. '+'Double-tap SPACEBAR to stop loop. (Speakers up)',
introTextX,430,450,50); //Starts initial counter to track actions
if(recording ==true){
counter++;} //If in playback, and items are in array, play on a loop
if(recording ==false& actionFrames.length >0){
counter++; //Loops counter after hitting max
if(counter === counterMax){
counter =0;} //Plays action if counter is the same as the frame which action occurred
var success =false;for(i =0; i < actionFrames.length; i++){if(counter === actionFrames[i]){
success =true;
actionIndex = i;break;}} //Plays the action if counter number matches the stored frame count
if(success ==true){(actions[actionIndex])();(actionSounds[actionIndex]).play();}} //Functions check if anything is in their respective arrays, then draw
playSlideH();playSlideV();playRectSlide();playRingPulse();playDotSpray(); //Visual feedback
//Red dot when recording
if(recording ==true){noStroke();fill(204,67,67);ellipse(30,30,10,10);} //Playback icon if looping with actions in array
if(recording ==false& actions.length >0){noStroke();fill(110,142,105);triangle(25,25,25,35,35,30);}}var recording =false;functionkeyPressed(){ //Hides intro text once user begins playing
if(keyCode ==32|| keyCode ==49|| keyCode ==50||
keyCode ==51|| keyCode ==52|| keyCode ==53){
introTextX = undefined;} //Toggles a loop recorder
if(keyCode ==32& recording ==false){
counter =0;
actions =[];
actionFrames =[];
actionSounds =[];
recording =true;print("start");}elseif(keyCode ==32& recording ==true){
counterMax = counter; //Creates a cap for counter to loop
counter =0;
recording =false;print("stop");} //Triggers an animation and sound clip on press
//If recording, stores action, the frame that action occurred, and the sound
//into respective arrays - actions[], actionFrames[], actionSounds[]
//Excluding dotSpray, clears arrays on press
//Pressing 1 sprays dots while playing a highhat clip
if(keyCode ==49){
hihat.play();dotSpray();if(recording ==true){print('1');
actionFrames.push(counter);
actions.push(dotSpray);
actionSounds.push(hihat);}} //Pressing 2 slides two rectangles while playing a bass drum clip
if(keyCode ==50){
bass.play();
rectSliders =[];rectSlide();if(recording ==true){print('2');
actionFrames.push(counter);
actions.push(rectSlide);
actionSounds.push(bass);}} //Pressing 3 creates a scaling ring while playing a snare clip
if(keyCode ==51){
snare.play();
rings =[];ringPulse();if(recording ==true){print('3');
actionFrames.push(counter);
actions.push(ringPulse);
actionSounds.push(snare);}} //Pressing 4 slides a large panel horizontally, plays a hightom clip
if(keyCode ==52){
hightom.play();
bigSliderH =[];bigSlideH();if(recording ==true){print('4');
actionFrames.push(counter);
actions.push(bigSlideH);
actionSounds.push(hightom);}} //Pressing 5 slides a large panel vertically, plays a lowtom clip
if(keyCode ==53){
lowtom.play();
bigSliderV =[];bigSlideV();if(recording ==true){print('5');
actionFrames.push(counter);
actions.push(bigSlideV);
actionSounds.push(lowtom);}}}/*----Dot Spray Functions-----------------------------------------------------*/
//Dots fly out from a random position
var dots =[]; //For dotSpray
//Places dots into array
functiondotSpray(){var dotOriginX =random(0, width);var dotOriginY =random(0, height);for(var i =0; i <10; i++){
dots.push(makeDot(dotOriginX, dotOriginY));}}
//Creates dot object
functionmakeDot(inputX, inputY){var dot ={x: inputX,
y: inputY,
stepX:random(-20,20),
stepY:random(-20,20),
color:[random(0,255),random(0,255),random(0,255)],
size:random(5,10),
move: dotStep,
display: drawDot}return dot;}
//Render dot
functiondrawDot(){noStroke();fill(this.color);ellipse(this.x,this.y,this.size);}
//Moves dot
functiondotStep(){this.x +=this.stepX;this.y +=this.stepY;}
//If something is in the array, execute animation
functionplayDotSpray(){ //Checks if anything exists inside array
if(dots.length >0){for(var i =0; i < dots.length; i++){ //Moves and renders
dots[i].move();
dots[i].display(); //If dot leaves canvas, remove it from dots array
if(dots[i].x <0|| dots[i].x > width ||
dots[i].y <0|| dots[i].y > height){
dots.splice(i,1);}}}}/*----------------------------------------------------------------------------*//*----rectSlide Functions-----------------------------------------------------*/
//Two rectangles slide vertically across the screen, direction random
var rectSliders =[]; //For rectSliders
//Places slider into array
functionrectSlide(){var startingY =480;var slideRate =20;var sliderY1; //Input for the first rectangle's Y position
var sliderStep1; //Input for the first rectangle's move speed
var sliderY2; //Input for the second rectangle's Y position
var sliderStep2; //Input for the first rectangle's move speed
//50/50 chance on which direction the sliders travel
var coin1 =coinToss();if(coin1 ==true){
sliderY1 =-startingY;
sliderStep1 = slideRate;}else{
sliderY1 = startingY;
sliderStep1 =-slideRate;}
rectSliders.push(makeSlider(100, sliderY1, sliderStep1));var coin2 =coinToss();if(coin2 ==true){
sliderY2 =-startingY;
sliderStep2 = slideRate;}else{
sliderY2 = startingY;
sliderStep2 =-slideRate;}
rectSliders.push(makeSlider(300, sliderY2, sliderStep2));}
//Creates slider object
functionmakeSlider(inputX, inputY, inputS){var slider ={x: inputX,
y: inputY,
w:150,
h:480,
color: lightCyan,
stepY: inputS,
move: slideStep,
display: drawSlider};return slider;}
//Renders slider
functiondrawSlider(){noStroke();fill(this.color);rect(this.x,this.y,this.w,this.h);}
//Moves slider
functionslideStep(){this.y +=this.stepY;}
//If something is in the array, execute animation
functionplayRectSlide(){ //Checks if anything exists inside array
if(rectSliders.length >0){for(var i =0; i < rectSliders.length; i++){
rectSliders[i].move();
rectSliders[i].display(); //If rectangle leaves canvas, remove it from array
if(rectSliders[i].y <-500|| rectSliders[i]>500){
rectSliders.splice(i,1);}}}}/*----ringPulse Functions-----------------------------------------------------*/
//Creates a ring that grows or shrinks in size from center
var rings =[];
//Places ring into array
functionringPulse(){var scaleRate =50;var startingSize; //Input for ring's starting size
var scaleTick; //Input for ring scale rate
var coin =coinToss(); //Determines direrction ring is scaling
if(coin ==true){ //Ring explodes outwards
startingSize =0;
scaleTick = scaleRate;}else{ //Ring collapses inwards
startingSize = width*1.5;
scaleTick =-scaleRate;}
rings.push(makeRing(startingSize, scaleTick));}
//Creates ring object
functionmakeRing(inputSize, inputStep){var ring ={x: width/2,
y: height/2,
size: inputSize,
step: inputStep,
color: darkerTeal,
weight:50,
scale: ringStep,
display: drawRing};return ring;}
//Renders ring
functiondrawRing(){strokeWeight(this.weight);stroke(this.color);noFill();ellipse(this.x,this.y,this.size);}
//Scales ring
functionringStep(){this.size +=this.step;}
//If something is in the array, execute animation
functionplayRingPulse(){if(rings.length >0){ //Renders and scales ring
for(var i =0; i < rings.length; i++){
rings[i].scale();
rings[i].display(); //If ring gets too big or too small, remove it from array
if(rings[i].size > width*2|| rings[i].size <0){
rings.splice(i,1);}}}}/*----------------------------------------------------------------------------*//*----bigSlideH Functions-----------------------------------------------------*/
//Slides a big block of color horizontally across the screen
var bigSliderH =[];
//Places slider into array
functionbigSlideH(){var startingX =580;var moveRate =50;var sliderHX; //Input for X position of slider
var sliderHS; //Input for movement rate of slider
var coin =coinToss(); //50/50 chance of coming in from either side of canvas
if(coin ==true){
sliderHX =-startingX;
sliderHS = moveRate;}else{
sliderHX = startingX;
sliderHS =-moveRate;}
bigSliderH.push(makeSliderH(sliderHX, sliderHS));}
//Creates slider object
functionmakeSliderH(inputX, inputS){var sliderH ={x: inputX,
y:0,
w: width+100,
h: height,
speed: inputS,
col: softPink,
move: sliderHStep,
display: drawSliderH};return sliderH;}
//Renders slider
functiondrawSliderH(){noStroke();fill(this.col);rect(this.x,this.y,this.w,this.h);}
//Moves slider
functionsliderHStep(){this.x +=this.speed;}
//If something is in the array, execute animation
functionplaySlideH(){if(bigSliderH.length >0){for(var i =0; i < bigSliderH.length; i++){
bigSliderH[i].display();
bigSliderH[i].move(); //Clear array if sliders leave canvas
if(bigSliderH[i].x <-580|| bigSliderH[i].x >580){
bigSliderH =[];}}}}/*----------------------------------------------------------------------------*//*----bigSlideV Functions-----------------------------------------------------*/
//Slides a big block of color horizontally across the screen
var bigSliderV =[];
//Places slider into array
functionbigSlideV(){var startingY =580;var moveRate =50;var sliderVY; //Input for Y position of slider
var sliderVS; //Input for movement rate of slider
var coin =coinToss(); //50/50 chance of coming in from either side of canvas
if(coin ==true){
sliderVY =-startingY;
sliderVS = moveRate;}else{
sliderVY = startingY;
sliderVS =-moveRate;}
bigSliderV.push(makeSliderV(sliderVY, sliderVS));}
//Creates slider object
functionmakeSliderV(inputY, inputS){var sliderV ={x:0,
y: inputY,
w: width,
h: height +100,
speed: inputS,
col: softViolet,
move: sliderVStep,
display: drawSliderV};return sliderV;}
//Renders slider
functiondrawSliderV(){noStroke();fill(this.col);rect(this.x,this.y,this.w,this.h);}
//Moves slider
functionsliderVStep(){this.y +=this.speed;}
//If something is in the array, execute animation
functionplaySlideV(){if(bigSliderV.length >0){for(var i =0; i < bigSliderV.length; i++){
bigSliderV[i].display();
bigSliderV[i].move(); //Clear array if sliders leave canvas
if(bigSliderV[i].y <-580|| bigSliderV[i].y >580){
bigSliderV =[];}}}}/*----------------------------------------------------------------------------*//*----------------------------------------------------------------------------*/
//Returns a Boolean value with a 50/50 chance
functioncoinToss(){var coin =floor(random(0,2));if(coin ===0){returntrue;}else{returnfalse;}}
DIRECTIONS: Press number keys 1-5 to play various drum sounds, hit spacebar to record your beat, then spacebar once more to play it back – double-tap spacebar to clear your loop. A red dot in the upper-left indicates that you are recording, and an arrow indicates a loop is being played. Please turn on your speakers.
This program is a reinterpretation of Patatap created by Jono Brandel and Lullatone. While I really enjoyed my experience with Patatap, I felt that it was lacking a system to create a looping beat capability seen on percussion pads or Launchpads. Because of this, I wanted to focus less on creating a complete keyboard’s worth of complex animation and moreso on creating that kind of robust looping system.
The program works by having a running frame counter once recording begins, and storing the action with its respective animation and sound, as well as the frame that it was performed into separate arrays. To loop, the counter resets, and whenever the counter number is the same as a stored frame number, the associated action is executed. For me, the biggest challenge was having all of these arrays relate to each other and keeping everything organized for a clean loop, however once I figured out the core system down, it was just a matter of adding more content in terms of possible actions.
In the future, I’d like to develop this further to have a full keyboard’s worth of sound and animation, as well as being able to perform several loops at once (likely involving storing arrays within arrays), but for now, I’m really pleased with the final result. I’ve played percussion for several years, so it was really enjoyable to get the chance to translate that interest over to a different medium.
For our final project, Sharon and I made a game named, “TOM.” In order to play TOM, users are to:
Use the arrow keys (up, down, left, right) to move the main character, TOM
Avoid contact with bombs – if contact is made, TOM dies and the game is over
Avoid contact with puffs – if contact is made, TOM loses a point (-1)
Consume hearts – if contact is made, TOM earns a point (+1)
Notice: If bombs make contact with hearts, the bomb bursts and gets rid of the hearts
Notice: Hearts randomly get patched across the canvas. It shrinks in size and disappears if not consumed by TOM.
Notice: When the game starts, you might immediately see the game over sign because the randomly generated bombs overlap with the initial position of TOM (100,100). Don’t panic and just refresh the webpage so you can restart.
Your goal is to get as much point as possible. Compete with friends and see who can get the most points!
Please download the file and use the local file to access the html file of TOM.
//Kyunga Ko
//15104B
//kyungak@andrew.cmu.edu
//Capstone Project:Tom and Toms (COMPLETE VERSION)
var bomb;var puff;var heart;var explosion;var tomcharacter;var eating;var gameover;var scoreboard;var score =0;functionpreload(){ //Preloading gameover and scoreboard image
gameover =loadImage("https://i.imgur.com/VlLC4xC.png");
scoreboard =loadImage("https://i.imgur.com/8ke3Z26.png");}functionsetup(){createCanvas(800,800); //Grouping variables
bomb =newGroup();
puff =newGroup();
heart =newGroup();
explosion =newGroup();
tomcharacter =newGroup();
eating =newGroup(); //Create bomb at random locations on canvas
for(var i=0; i<15; i++){createBomb(random(0,width),random(0,height));} //Single character "Tom" is created
for(var i=0; i<1; i++){createTom(100,100);}}functiondraw(){background(230); //Reduce the size of the heart by the rate of the frameCount
if(frameCount%60==0& heart.length<5){ //Create hearts at random locations on the canvas
createHeart(random(0,width),random(0,height));} //Recycle puff on four sides = randomly displaced
if(frameCount%60==0& puff.length<10){var canvasside =floor(random(0,4));if(canvasside ==0) //left
createPuff(0,random(height));if(canvasside ==1) //right
createPuff(width,random(height));if(canvasside ==2) //top
createPuff(random(width),0);if(canvasside ==3) //bottom
createPuff(random(width), height);} //(BOMB) Bomb orientation in general
for(var i =0; i<bomb.length; i++){var b = bomb[i];
b.noisePosition +=0.1;
b.rotation +=(noise(b.noisePosition)-0.5)*10;
b.setSpeed(2, b.rotation);randomrelocation(b);} //(PUFF) When puff collides with bomb and heart
for(var i =0; i<puff.length; i++){var p = puff[i];randomrelocation(p);for(var j =0; j<bomb.length; j++){var b = bomb[j]; //Distance btw puff and bomb
var dis = p5.Vector.dist(p.position, b.position); //Puff and bomb does not attract
if(dis <70){var angle =degrees(atan2(b.position.y-p.position.y,
b.position.x-p.position.x)); //repel
var attraction =-30/ dis;
p.addSpeed(attraction, angle);}}for(var z =0; z<heart.length; z++){var h = heart[z]; //Distance btw heart and puff
var dis2 = p5.Vector.dist(p.position, h.position); //Puff and heart attract
if(dis2 <30){var angle2 =degrees(atan2(h.position.y-p.position.y,
h.position.x-p.position.x));var attraction2 =100/ dis2;
p.addSpeed(attraction2, angle2);}}} //(HEART) When heart collides with bomb and puff
for(var i =0; i<heart.length; i++){var h = heart[i]; //save in a temp variable
h.scale =map(h.life,300,0,1,0);
h.overlap(bomb, bombeatsheart);
h.overlap(puff, puffeatsheart);} //(TOM) When Tom collides with bomb and heart
for(var i =0; i<tomcharacter.length; i++){var t = tomcharacter[i]; //save in a temp variable
t.overlap(bomb, bombmeetstom);
t.overlap(heart, heartmeetstom);
t.overlap(puff, puffmeetstom);} //Scoreboard
image(scoreboard,580,15); //Scoreboard image
textSize(30);fill(0);text(score,670,90); //Displays the score
//Draws all sprites
drawSprites();}
//Makes Tom move up, down, left, right using the arrow keys
functionkeyPressed(){var tab =20;var clickCount =0;for(var i =0; i<tomcharacter.length; i++){var t = tomcharacter[i];if(keyIsPressed ===true){
clickCount ++; //clickcount increases with movement
}if(keyIsDown(LEFT_ARROW)){
t.position.x -= tab; //left
}if(keyIsDown(RIGHT_ARROW)){
t.position.x += tab; //right
}if(keyIsDown(UP_ARROW)){
t.position.y -= tab; //up
}elseif(keyIsDown(DOWN_ARROW)){
t.position.y += tab; //down
}}}
//The object dissapears outside the canvas and is randomly located again
functionrandomrelocation(w){ //wrap around the screen
if(w.position.x > width)
w.position.x =0;if(w.position.x <0)
w.position.x = width;if(w.position.y > height)
w.position.y =0;if(w.position.y <0)
w.position.y = height;}
//When puff eats the heart, they multiply x2
functionpuffeatsheart(puff, heart){
puff.remove();createPuff(heart.position.x, heart.position.y);}
//When Tom meets puff, score decreases by one
functionpuffmeetstom(puff, tomcharacter){
tomcharacter.remove();
score--;}
//Bomb eats/gets rid of the heart + explosion sign
functionbombeatsheart(bomb, heart){
bomb.remove();createExplosion(heart.position.x, heart.position.y);createExplosion(heart.position.x, heart.position.y);createExplosion(heart.position.x, heart.position.y);createExplosion(heart.position.x, heart.position.y);createExplosion(heart.position.x, heart.position.y);createExplosion(heart.position.x, heart.position.y);createExplosion(heart.position.x, heart.position.y);}
//Tom eats heart and +1 sign comes up
functionheartmeetstom(heart, tomcharacter){
tomcharacter.remove();aftereatingheart(heart.position.x, heart.position.y);
score++;}
//When bomb meets Tom, Tom dies and game over sign comes up
functionbombmeetstom(bomb, Tom){
bomb.remove();noLoop();push();scale(0.7);image(gameover,175,400);pop();}
//Bomb is created
functioncreateBomb(x, y){var b =createSprite(x, y);
b.addAnimation("bomb","https://i.imgur.com/N4m1kty.png");
b.setSpeed(2,random(0,360));
b.noisePosition =random(0,1000);
b.maxSpeed =2;
bomb.add(b);}
//When bomb eats heart, explosion is created to indicate that a heart was ate
functioncreateExplosion(x, y){var e =createSprite(x, y);
e.addAnimation("bomb","https://i.imgur.com/wzVAcbK.png");
e.setSpeed(2,random(0,360));
e.noisePosition =random(0,1000);
e.maxSpeed =2;
explosion.add(e);}
//After Tom eats heart, +1 sign is created
functionaftereatingheart(x, y){var a =createSprite(x,y);
a.addAnimation("eat","https://i.imgur.com/b9C1Xyl.png");
a.setSpeed(2,random(0,360));
a.noisePosition =random(0,1000);
a.maxSpeed =2;
eating.add(a);}
//Puff is created
functioncreatePuff(x, y){var p =createSprite(x, y);
p.addAnimation("puff","https://i.imgur.com/cs8Mkcr.png");
p.setSpeed(-2,random(0,360));
p.maxSpeed =1;
puff.add(p);}
//Heart is created
functioncreateHeart(x, y){var h =createSprite(x, y);
h.addAnimation("heart","https://i.imgur.com/u2uRAYl.png");
h.life =300;
heart.add(h);}
//Tom is created
functioncreateTom(x, y){var t =createSprite(x, y);
t.addAnimation("tomcharacter","https://i.imgur.com/Q8FnPtP.png","https://i.imgur.com/QzOR227.png");
tomcharacter.add(t);}