Because it can’t be viewed properly on WordPress, please download the file.
I was always fascinated in animation ever since I was little and I always wanted to create something that would help introduce people to making animations. I made this so anyone at any age can know or get the idea and possibly get inspired.
SAMPLE:
Instructions:
//Sheenu You
//Section E
//sheenuy@andrew.cmu.edu;
//Final Project
//Initial X and Y coordinates for the Ragdoll Bodyparts
var charx = 640;
var chary = 380;
var hedx = 640;
var hedy = 220;
var arlx = 640 - 160;
var arly = 380;
var arrx = 640 + 160;
var arry = 380;
var brlx = 640 - 80;
var brly = 650;
var brrx = 640 + 80;
var brry = 650;
//Arrays that register all the X Y coordinates of all the bodyparts
var xb = [];
var yb = [];
var xh = [];
var yh = [];
var xal = [];
var yal = [];
var xar = [];
var yar = [];
var xbl = [];
var ybl = [];
var xbr = [];
var ybr = [];
//Variables that track animation frames
var frameNumber = -1;
var frames = 0;
//Variables that test if functions are running.
var initialized = 0;
var forward = 0;
var backward = 0;
function setup() {
createCanvas(1280, 720);
background(220);
frameRate(24);
}
function draw() {
noStroke();
//Controls drawing of buttons
var playing = 0;
var blockyMath = 100;
var distance = 150;
background(255, 245, 195);
body();
fill(124, 120, 106);
textSize(20);
text("FRAMES: " + frames, 5, 20);
//Draws NewFrame Button
fill(252, 223, 135);
rect(width/2 - 10, 80 + 10, 180, 100);
fill(141, 205, 193);
rect(width/2, 80, 180, 100);
//Draws Play/Stop Button
fill(252, 223, 135);
rect((width/2) - distance - 10, 80 + 10, blockyMath, blockyMath);
fill(235, 110, 68);
rect((width/2) - distance, 80, blockyMath, blockyMath);
//Fills triangle if one frame is made
if (frames >= 1){
fill(255);
} else {
fill(231, 80, 29);
}
triangle((width/2) - distance + 40, 40, (width/2) - distance + 40, 120, (width/2) - distance - 40, 80);
push();
fill(255);
textSize(30);
text("ADD", 610, 75);
text("FRAME", 590, 110);
pop();
//Draws Rewind/Stop Button
fill(252, 223, 135);
rect((width/2) + distance - 10, 80 + 10, blockyMath, blockyMath);
fill(211, 227, 151);
rect((width/2) + distance, 80, blockyMath, blockyMath);
if (frames >= 1){
fill(255);
} else {
fill(182, 204, 104);
}
triangle((width/2) + distance - 40, 40, (width/2) + distance - 40, 120, (width/2) + distance + 40, 80);
//PLAY/Stop Button Functions-Cycles forward through frames if mouse is pressing the button
if (mouseX >= ((width/2) + distance - blockyMath/2) & mouseX <= ((width/2) +
distance + blockyMath/2) && mouseY >= 30 && mouseY <= 135 && mouseIsPressed && frames >= 1){
frameNumber += 1
//Cycles through all arrays
charx = xb[frameNumber];
chary = yb[frameNumber];
hedx = xh[frameNumber];
hedy = yh[frameNumber];
arlx = xal[frameNumber];
arly = yal[frameNumber];
arrx = xar[frameNumber];
arry = yar[frameNumber];
brlx = xbl[frameNumber];
brly = ybl[frameNumber];
brrx = xbr[frameNumber];
brry = ybr[frameNumber];
playing = 1;
initialized = 1;
forward = 1;
//Goes back to latest frame when mouse is released.
} else if (forward == 1){
frameNumber =xb.length - 1
playing = 0;
initialized = 0;
forward = 0;
}
//REWIND/Stop Button Functions-Cycles backward through frames if mouse is pressing the button
if (mouseX >= ((width/2) - distance - blockyMath/2) & mouseX <= ((width/2) - distance +
blockyMath/2) && mouseY >= 30 && mouseY <= 135 && mouseIsPressed && frames >= 1){
frameNumber -= 1;
//Cycles through all arrays
charx = xb[frameNumber];
chary = yb[frameNumber];
hedx = xh[frameNumber];
hedy = yh[frameNumber];
arlx = xal[frameNumber];
arly = yal[frameNumber];
arrx = xar[frameNumber];
arry = yar[frameNumber];
brlx = xbl[frameNumber];
brly = ybl[frameNumber];
brrx = xbr[frameNumber];
brry = ybr[frameNumber];
initialized = 1;
playing = 1;
backward = 1;
//Goes back to latest frame when mouse is released.
} else if (backward == 1){
frameNumber = xb.length - 1
playing = 0;
initialized = 0;
backward = 0;
}
//Allows frames to loop when animation is going forward
if (frameNumber >= xb.length - 1 & playing == 1 && forward == 1){
frameNumber = -1;
}
//Allows frame to loop when animation is going backward
if (frameNumber <= 0 & backward == 1 && playing == 1){
frameNumber = xb.length;
}
}
//Draws Ragdoll
function body(){
//Shadow
fill(252, 223, 135);
ellipse(charx, 670, (chary/2) + 100, 30);
//Ligaments
//Neck
push();
stroke(249, 213, 151);
strokeWeight(30);
line(charx, chary - 80, hedx, hedy);
stroke(190, 228, 171);
//ArmLeft
line(charx, chary - 80, arlx, arly);
//ArmRight
line(charx, chary - 80, arrx, arry);
stroke(88, 203, 172);
//FootLeft
line(charx - 20, chary + 70, brlx, brly);
//FootRight
line(charx + 20, chary + 70, brrx, brry);
pop();
noStroke();
rectMode(CENTER);
//Head
fill(249, 213, 151);
ellipse(hedx, hedy, 100, 100);
fill(80);
ellipse(hedx - 10, hedy - 10, 10, 20);
ellipse(hedx + 10, hedy - 10, 10, 20);
ellipse(hedx, hedy + 20, 30, 30);
fill(249, 213, 151);
ellipse(hedx, hedy + 15, 30, 30);
//Left Arm
fill(249, 213, 151);
ellipse(arlx, arly, 50, 50);
//Right Arm
fill(249, 213, 151);
ellipse(arrx, arry, 50, 50);
//Left Foot
fill(112, 47, 53);
rect(brlx, brly, 50, 50);
//Right Foot
fill(112, 47, 53);
rect(brrx, brry, 50, 50);
//Character
fill(190, 228, 171);
rect(charx, chary, 100, 200);
fill(88, 203, 172);
rect(charx, chary + 50, 100, 100);
fill(88, 203, 172);
rect(charx + 30, chary - 50, 20, 100);
rect(charx - 30, chary - 50, 20, 100);
//MouseDrag Body
if (mouseX >= charx - 50 & mouseX <= charx + 50 && mouseY >= chary - 100 && mouseY <= chary + 100 && mouseIsPressed){
charx = mouseX;
chary = mouseY;
}
//MouseDrag Head
if (mouseX >= hedx - 50 & mouseX <= hedx + 50 && mouseY >= hedy - 50 && mouseY <= hedy + 50 && mouseIsPressed){
hedx = mouseX;
hedy = mouseY;
}
//MouseDrag Left Arm
if (mouseX >= arlx - 25 & mouseX <= arlx + 25 && mouseY >= arly - 25 && mouseY <= arly + 25&& mouseIsPressed){
arlx = mouseX;
arly = mouseY;
}
//MouseDrag Right Arm
if (mouseX >= arrx - 25 & mouseX <= arrx + 25 && mouseY >= arry - 25 && mouseY <= arry + 25 && mouseIsPressed){
arrx = mouseX;
arry = mouseY;
}
//MouseDrag Left Foot
if (mouseX >= brlx - 25 & mouseX <= brlx + 25 && mouseY >= brly - 25 && mouseY <= brly + 25 && mouseIsPressed){
brlx = mouseX;
brly = mouseY;
}
//MouseDrag Right Foot
if (mouseX >= brrx - 25 & mouseX <= brrx +25 && mouseY >= brry - 25 && mouseY <= brry + 25 && mouseIsPressed){
brrx = mouseX;
brry = mouseY;
}
}
function mousePressed(){
//Register/records character coordinates to new frame when "New Frame" button is pressed
if (mouseX >= (width/2) - 90 & mouseX <= (width/2) + 90 && mouseY >= 30 && mouseY <= 135 && mouseIsPressed){
frameNumber += 1
frames += 1
//Push character coordinates to x y arrays.
xb.push(charx);
yb.push(chary);
xh.push(hedx);
yh.push(hedy);
xal.push(arlx);
yal.push(arly);
xar.push(arrx);
yar.push(arry);
xbl.push(brlx);
ybl.push(brly);
xbr.push(brrx);
ybr.push(brry);
//Flash
background(255, 0, 0, 90);
}
}
//Resets all body parts to x y coordinates of last frame created when mouse is released
//and cycling is over.
function mouseReleased(){
if (initialized == 1){
charx = xb[xb.length - 1];
chary = yb[yb.length - 1];
hedx = xh[xh.length - 1];
hedy = yh[yh.length - 1];
arlx = xal[xal.length - 1];
arly = yal[yal.length - 1];
arrx = xar[xar.length - 1];
arry = yar[yar.length - 1];
brlx = xbl[xbl.length - 1];
brly = ybl[ybl.length - 1];
brrx = xbr[xbr.length - 1];
brry = ybr[ybr.length - 1];
}
}
Because it can’t be viewed properly on WordPress, please download the file.
]]>
For this project I wanted to create a game, but not one of those kinds where you feel anxious and competitive while playing the game.
So I created this game where you can enjoy the winter scenery and a cute dog running while given a bit of an entertainment of being able to move around the dog and its sled to collect the presents.
How to:
Use the left/right arrow keys to move around the dog and its sled.
Use the space bar to generate more presents (will be falling from the sky)
NEVER HOLD THE KEY DOWN!!!
The sliding motion of the presents was to re-enact the real time inertia of the objects.
//Claire Koh
//juyeonk@andrew.cmu.edu
//Section E
//Final Project
var frames = []; // An array to store the puppy images
var x = 0; // Variable to draw out an image from the array
var houses = []; // An array to store the house images
var housepics = []; // Array to store the passing by houses
var terrainSpeed = 0.0015;
var terrainDetail = 0.01;
var stars = []; // Array to store the snowflakes
var puppyX = 270; // Initial x position of the puppy
var puppyY = 330; // Initial y position of the puppy (remains the same throughout)
var presents = []; //Array to store the newly created presents
function setup() {
createCanvas(600, 426);
frameRate(13)
// Creates the snowflakes at the beginning
for (var g = 0; g < 150; g ++) {
var ry = random(width);
stars[g] = makeStar(ry);
}
// Creates the houses at the beginning
var x = 0;
for(var i = 0; i < 4; i++) {
var newHouse = new House();
newHouse.image = housepics[i];
newHouse.x = x;
if(i == 2) {
newHouse.width = 300;
newHouse.y = 120;
}
x += 300;
houses.push(newHouse);
}
// Creates the presents at the beginning
for (i = 0; i <= width; i +=40) {
presents.push(new Present());
}
}
function preload(){
var filenames = [];
filenames[0] = "https://i.imgur.com/Dv85eeW.png";
filenames[1] = "https://i.imgur.com/kRjE8sW.png";
filenames[2] = "https://i.imgur.com/AZLU597.png";
filenames[3] = "https://i.imgur.com/8wakuK8.png";
filenames[4] = "https://i.imgur.com/7mD1cW9.png";
filenames[5] = "https://i.imgur.com/tqUCgkx.png";
filenames[6] = "https://i.imgur.com/yQ4WaYh.png";
//Loads the images into the frames[] array
for (var i = 0; i < filenames.length; i ++) {
frames[i]= loadImage(filenames[i]);
}
var housepic =[];
housepic[0] = "https://i.imgur.com/RNMEypc.png";
housepic[1] = "https://i.imgur.com/NgL94xZ.png";
housepic[2] = "https://i.imgur.com/TRsZkpd.png";
housepic[3] = "https://i.imgur.com/X6qFGHM.png";
housepic[4] = "https://i.imgur.com/TKd1cpX.png";
housepic[5] = "https://i.imgur.com/uVz8Spc.png";
// Loads teh images into the housepics[] array
for (var j = 0; j < housepic.length; j ++) {
housepics[j] = loadImage(housepic[j]);
}
}
function draw() {
background(200);
var sky1 = color(27, 36, 49);
var sky2 = color(30, 55, 92);
for (var c = 0; c <= height; c += 1) {
var amt = map(c, 0, height/2, 0, 1);
var skygradient1 = lerpColor(sky1, sky2, amt);
noStroke();
fill(skygradient1);
rect(0, c, width, 1);
}
for (var i = houses.length-1; i>=0; i--){
houses[i].render();
houses[i].move();
}
createHillShadow();
createHill();
//SLED
stroke(0);
strokeWeight(1);
line(puppyX-10, puppyY+68, puppyX+25, puppyY+50)
push();
noStroke();
fill(112, 100, 35);
ellipse(puppyX-10, puppyY+68, 8);
strokeWeight(8);
stroke(112,100,35);
line(puppyX-100, puppyY+50, puppyX-80, puppyY+67.5);
noStroke();
rect(puppyX-80, puppyY+64, 70, 8);
pop();
//PUPPY
image(frames[x], puppyX, puppyY, 90, 90);
x += 1;
if (x > 6) {
x = 0;
}
for (var i = 0; i < presents.length; i++) {
presents[i].draw();
presents[i].move();
presents[i].update();
}
//SNOW
updateAndDisplayStars();
removeStarsThatHaveSlippedOutOfView();
addNewStarsWithSomeRandomProbability();
//INSTRUCTIONS
push();
if (frameCount < 50) {
fill(255);
textAlign(CENTER);
text("Use left/right arrow keys to move the puppy", width/2, height/2 - 40)
text("Press the spacebar to generate more presents", width/2, height/2 - 20)
text("Try to collect as many presents as you want but you don't have to!", width/2, height/2)
pop();
}
}
// Function to create the presents
function Present() {
this.x = random(width);
this.y = -50;
this.width = this.height = 20;
this.velocity = random(1,5);
this.R = random(100,255);
this.G = random(100, 255);
this.B = random(100, 255);
this.w = -20
this.draw = function() {
noStroke();
fill(this.R,this.G,this.B,200)
rect(this.x, this.y, this.width, this.height);
push();
stroke(255);
line(this.x, this.y+10, this.x + this.width, this.y + 10)
line(this.x + 10, this.y, this.x + 10, this.y + this.width)
pop();
}
this.move = function() {
this.y += this.velocity;
}
this.update = function() {
if (this.y >= height-52 & this.y <= height && abs((puppyX-50)-this.x) < 40) {
this.y = height-52;
this.velocity = 0;
}
if (keyIsDown(LEFT_ARROW) & this.velocity == 0) {
this.x -= 10;
}
if (keyIsDown(RIGHT_ARROW) & this.velocity == 0) {
this.x += 10;
}
}
}
function keyPressed(){
// Generates more presents
if (keyCode === 32) {
for (i = 0; i <= width; i +=40) {
presents.push(new Present());
}
}
// Moves the puppy with the left/right arrow keys
if (keyCode === LEFT_ARROW) {
puppyX -= 10;
if (Present.velocity == 0) {
presents[i].x -= 10;
}
}
if (keyCode === RIGHT_ARROW) {
puppyX += 10;
if (Present.velocity == 0) {
presents[i].x += 10
}
}
}
// Draws House
function House(){
this.x = width;
this.y = 180;
this.width = 200;
this.speed = 6;
this.image;
this.render = function(){
image(this.image,this.x, this.y, this.width, this.width);
}
this.move = function(){
this.x -= this.speed;
if (this.x < -200) {
this.x = width + 100;
}
this.remove = function() {
if (this.x < -150) {
return true;
}
else {
return false;
}
}
}
}
//BACKGROUND ELEMENTS
// Draws the snowflakes
function updateAndDisplayStars(){
// Update the lantern's positions, and display them.
for (var i = 0; i < stars.length; i++){
stars[i].move();
stars[i].display();
}
}
function removeStarsThatHaveSlippedOutOfView(){
var starsToKeep = [];
for (var i = 0; i < stars.length; i++){
if (stars[i].x> 0) {
starsToKeep.push(stars[i]);
}
}
stars = starsToKeep;
}
function addNewStarsWithSomeRandomProbability() {
// With some possibility, add new snowflakes
var newStarLikelihood = 0.8;
if (random(0,1) < newStarLikelihood) {
stars.push(makeStar(width));
}
}
// Makes the snowflakes move
function starMove() {
this.x -= this.speed*1.2;
}
// Draws the snowflakes
function starDisplay() {
noStroke()
fill(255, this.transparency);
ellipse(this.breadth, this.x, this.size)
}
function makeStar(birthLocationX) {
var star = {x: birthLocationX,
y: random(10,70),
breadth: random(width),
breadthy: random(height),
speed: random(0.1,4),
move: starMove,
display: starDisplay,
size: random(2,7),
transparency: random(150, 255)
}
return star;
}
// Creates the shadow of the hill
function createHillShadow() {
var noiseScale = 0.001;
var forestDetail = 0.0005;
var forestSpeed = 0.0005;
for (var g = 0; g < width; g++) {
h = (g * forestDetail * 7 + millis() * forestSpeed/8);
i = map(noise(h), 0, 1, 40, 100);
stroke(30,70);
line(g, i+200, g, height-80);
}
}
// Creates the hill
function createHill() {
var noiseScale = 0.001;
var forestDetail = 0.0005;
var forestSpeed = 0.0005;
for (var g = 0; g < width; g++) {
h = (g * forestDetail * 8 + millis() * forestSpeed/4);
i = map(noise(h), 0, 1, 40, 100);
stroke(255);
line(g, i+250, g, height);
}
}
]]>//Isabelle Vincent
//ifv@andrew.cmu.edu
//Section E
//Final Project
var bigs;
var littles;
var algaes;
var foods;
var l;
var littleFish;
var bigFish;
var algae;
var lilypad;
var title;
var state = "title";
function preload() {
title = loadImage('https://i.imgur.com/aebxPZS.png');
algae = loadImage("https://i.imgur.com/qnqf1gs.png");
lilypad = loadImage("https://i.imgur.com/3bfrSSw.png");
littleFish = loadAnimation('https://i.imgur.com/AUq3ML3.png', 'https://i.imgur.com/1z3PLA8.png', 'https://i.imgur.com/Pxw05Sj.png', 'https://i.imgur.com/yA0uKGs.png', 'https://i.imgur.com/dnUjjsr.png', 'https://i.imgur.com/vprw1op.png', 'https://i.imgur.com/u9dgtas.png', 'https://i.imgur.com/tV1RxJZ.png');
bigFish = loadAnimation('https://i.imgur.com/zqn5YLQ.png', 'https://i.imgur.com/GSV79Mw.png', 'https://i.imgur.com/oh8VzDx.png', 'https://i.imgur.com/RRiwPTC.png', 'https://i.imgur.com/nswooQs.png', 'https://i.imgur.com/w95esvz.png', 'https://i.imgur.com/uPy62tp.png', 'https://i.imgur.com/uHA6DaY.png');
}
function setup() {
createCanvas(800, 400);
//looping fish animations
littleFish.looping = true;
bigFish.looping = true;
i = 1;
//start out on title screen
if(state == "title"){
imageMode(CORNER);
image(title,0,0);
}
//create empty groups
bigs = new Group();
littles = new Group();
algaes = new Group();
foods = new Group();
//assign new sprites to groups
for (var i = 0; i < 6; i++) {
//i put all the creation and initialization instructions in a function I created
createbig(random(0, width), random(0, height));
}
}
function draw() {
if(state == "gameplay"){
//the more algae there is the darker the bg is
var q = algaes.length * 20
var c = color(136-q, 180-q, 136-q);
background(c);
textSize(20);
fill(210, 239, 220);
text("Click to feed fish, if you dont there will be no more fish",10,30);
//spawn a algae randomly
if (frameCount % 40 == 0 & algaes.length < 4 && bigs.length > 3) {
createAlgae(random(0, width), random(0, height));
}
//create a new little fish every 60 frames if there are less than 20 little fish
if (frameCount % 60 == 0 & littles.length < 20) {
var side = floor(random(0, 4));
if (side == 0) //left
createlittle(0, random(height));
if (side == 1) //right
createlittle(width, random(height));
if (side == 2) //top
createlittle(random(width), 0);
if (side == 3) //bottom
createlittle(random(width), height);
}
for (var i = 0; i < algaes.length; i++) {
var a = algaes[i];
for (var j = 0; j < bigs.length; j++) {
var b = bigs[j];
a.overlap(bigs, algaeTouchesBig);
}
}
//go through the bigs - they wander randomly
for (var i = 0; i < bigs.length; i++) {
//way to store fish position
var b = bigs[i];
b.noisePosition += 0.1;
b.rotation += (noise(b.noisePosition) - 0.5) * 10;
//set the velocity based on the new rotation
b.setSpeed(2, b.rotation);
//check all the bigs,
for (var j = 0; j < foods.length; j++) {
var f = foods[j]; //same as above
var distance = p5.Vector.dist(b.position, f.position);
//if they are closer make them attract
if (distance < 500) {
//find angle between the two
var angle = degrees(atan2(f.position.y - b.position.y, f.position.x - b.position.x));
//attraction inverseley proportional to distance
var attraction = 200 / distance;
b.addSpeed(attraction, angle);
b.overlap(foods, BigTouchesFood);
}
}
wrapAroundScreen(b);
}
//go through the littles group -
//they go straight until they get close to bigs
littles.bounce(bigs);
bigs.bounce(bigs);
for (var i = 0; i < littles.length; i++) {
var l = littles[i]; //save in a temp variable
l.overlap(algaes, littleTouchesAlgae);
wrapAroundScreen(l);
}
//don't forget to draw all the sprites
drawSprites();
}
}
//click mouse to feed fish
function mousePressed() {
for (var i = 0; i < random(3, 5); i++) {
createFood(mouseX, mouseY);
}
}
//checks if a sprite is outside of the screen and teleports it on the other side
function wrapAroundScreen(s) {
//wrap around the screen
if (s.position.x > width + 20)
s.position.x = 0;
if (s.position.x < -20)
s.position.x = width;
if (s.position.y > height + 20)
s.position.y = 0;
if (s.position.y < -20)
s.position.y = height;
}
//if little fish touches algae a new little fish is made and algae destroyed
function littleTouchesAlgae(little, algae) {
algae.remove();
createlittle(little.position.x, little.position.y);
}
//If algae and Big fish touch big fish disappear
function algaeTouchesBig(algae, big) {
big.remove();
}
//If Big Fish touches food a new fish is created at a semi-random size
function BigTouchesFood(big, food) {
food.remove();
push()
big.scale = random(0.5, 0.7);
createbig(big.position.x, big.position.y);
pop();
}
//function to create Big fish & add to group
function createbig(x, y) {
var b = createSprite(x, y);
b.addAnimation("big", bigFish);
b.velocity.y += random(-2, 2);
b.velocity.x += random(-2, 2);
b.scale = 0.5;
b.mass = b.scale;
b.setCollider("spiral", -2, 2, 55);
//use to generate the noise wandering
b.noisePosition = random(0, 1000);
//image rotates toward the direction
b.rotateToDirection = true;
b.maxSpeed = 2;
bigs.add(b);
}
//function to create little fish & add to group
function createlittle(x, y) {
var l = createSprite(x, y);
l.addAnimation("little", littleFish);
//set a random speed
l.setSpeed(2, random(0, 360));
l.scale = random(0.3, 0.7);
//slower speed than bigs so they will never stick to them
l.maxSpeed = 1.8;
l.mass = l.scale;
l.setCollider("spiral", -2, 2, 55);
l.life = 500;
//image rotates toward the direction
l.rotateToDirection = true;
littles.add(l);
}
//function to create food particles & add to group
function createFood(x, y) {
var f = createSprite(x, y);
f.scale = 0.4;
f.addAnimation("food", "https://i.imgur.com/FTsnjxr.png");
f.velocity.y += random(-2, 2);
f.velocity.x += random(-2, 2);
foods.add(f);
}
//function to create algae & add to group
function createAlgae(x, y) {
var a = createSprite(x, y);
a.addAnimation("algae", "https://i.imgur.com/qnqf1gs.png");
a.life = 800;
algaes.add(a);
}
//start game after spacebar pressed by changing the state
function keyPressed() {
if (state === "title" & keyCode === 32) {
state = "gameplay";
}
}
This Project is a small ecosystem that is reliant on user interaction for it the eco system to flourish. Unfortunately I wasn’t able to take this project to the level I originally wanted to but coding with a different library was a learning experience for me.
]]>var angle = 0; //tree branch angle
var mic; //internal microphone
var forest = []; //holds trees
var iInc; //branch incriment
var ns = 10; //stars
var p; //moon curve variable
var q; //moon curve variable
var curveSize; //moon curve constraint
function setup() {
createCanvas(480, 280);
background(51);
mic = new p5.AudioIn(); //create mic
mic.start(); //activate mic
//push 3 trees into array
var tree1 = new Branch(87,10);
forest.push(tree1);
var tree2 = new Branch(70,70);
forest.push(tree2);
var tree3 = new Branch(40, 300);
forest.push(tree3);
flock = new Flock();
//creating and pushing stars into an array
for (var i = 0; i < ns; i++) {
var p = makeStar(-10, -10,random(-50, 50), random(-50, 50));
stars.push(p);
}
frameRate(10);
}
function draw() {
background(51, 7.5);
stroke(255,5);
//get volume from mic (trees, stars, moon)
var micLevel = mic.getLevel()*200;
angle = micLevel/40;
//call the function
flock.run();
//get volume from mic (flowy energy)
var vol = mic.getLevel()*15;
//if the volume is above a certain threshold, add a new flock of boids to the scene
if (vol > 2) {
flock.addBoid(new Boid(0, height/2));
}
pop();
background(51,51,51,255*.2); //redrawing the background to give ghostly layering effect
//Trees
for(var i = 0; i < forest.length; i++){ //create multiple trees
push();
var xPos = forest[i].x;
translate(xPos, height);
forest[i].display();
pop();
}
//Stars
//if the volume exceeds a certain threshold, new stars are drawn
if (micLevel > 10) {
var newS = makeStar(random(10, width), random(10, height/3*2), random(-0.5, 0.5), random(-0.5, 0.5));
stars.push(newS);
}
//store newly created stars
newStars = [];
for (var i = 0; i < stars.length; i++) {
var p = stars[i];
p.draw();
if (p.age < 200) {
newStars.push(p);
}
}
stars = newStars;
//Moon
//map volume threshold to moon curve formula
p = map (micLevel, 0, 100, 0, 100);
q = map (micLevel, 0, 100, 0, 130);
curveSize = map (micLevel, 0, width, 20, 20);
//curve formula
var k = p/q;
push();
translate (380, 70);
iInc = map (micLevel, 0, height, 0.05, 1.5);
for (var i = 0; i < TWO_PI * q ; i+= iInc*1.2) {
var r = curveSize * cos (k*i);
var x = r * cos(i);
var y = r * sin(i);
fill(189, 207 , 253, 10);
strokeWeight(iInc*5);
point (x, y);
fill(255);
}
}
//Completing the tree objects
function Branch(len, xTrans){
this.originalTall = len;
this.x = xTrans;
this.display = function(){
push();
translate(50);
branching(this.originalTall);
pop();
}
}
//Making the recursive tree
function branching(len){
line(0,0,0,-len);
translate(0,-len);
stroke(255);
if(len > 4) {
push();
rotate(angle);
branching(len * 0.67);
pop();
push();
rotate(-angle);
branching(len * 0.67);
pop();
}
}
//Making the stars
function starDraw() {
fill(255);
point(this.x + random (0.1, -0.1), this.y + random(-0.1, 0.1));
}
//create the star
function makeStar(sx, sy) {
p = {x: sx +random(-0.1, 0.1), y: sy + (-0.1, 0.1),
age: 0,
draw: starDraw
}
return p;
}
var stars = [];
// Starting here:
// Flocking Behavior algorithm sampled from Daniel Shiffman, "The Nature of Code"
// http://natureofcode.com
function Flock() {
// An array for all the boids
this.boids = []; // Initialize boids array
}
Flock.prototype.run = function() {
for (var i = 0; i < this.boids.length; i++) {
this.boids[i].run(this.boids); // Passing the entire list of boids to each boid individually
}
}
Flock.prototype.addBoid = function(b) {
this.boids.push(b); //
}
// Separation, Cohesion, and Alignment forces added
//defining the boid object
function Boid(x,y) {
this.acceleration = createVector(0,0);
this.velocity = createVector(random(-1,1),random(-1,1));
this.position = createVector(x,y);
this.r = 3.0; //radius of boid
this.maxspeed = 2; // Maximum speed
this.maxforce = 0.05; // Maximum steering force
// Starting here:
// Our own original code
var rr = random(70, 90);
var gg = random(70, 90);
var bb = random(80, 100);
this.rcolor = rr;
this.gcolor = gg;
this.bcolor = bb;
// Keep track of old x y coordinates of boid
this.history = [];
}
// Our own original code
// Ending here:
// Continuing here:
// Flocking Behavior algorithm sampled from Daniel Shiffman, "The Nature of Code"
// http://natureofcode.com
Boid.prototype.run = function(boids) {
this.flock(boids);
this.update();
this.borders();
this.render();
}
Boid.prototype.applyForce = function(force) {
this.acceleration.add(force);
}
// We accumulate a new acceleration each time based on three rules
Boid.prototype.flock = function(boids) {
var sep = this.separate(boids); // Separation
var ali = this.align(boids); // Alignment
var coh = this.cohesion(boids); // Cohesion
// Arbitrarily weight these forces
sep.mult(1.5);
ali.mult(1.0);
coh.mult(1.0);
// Add the force vectors to acceleration
this.applyForce(sep);
this.applyForce(ali);
this.applyForce(coh);
}
// Method to update location
Boid.prototype.update = function() {
// Update velocity
this.velocity.add(this.acceleration);
// Limit speed
this.velocity.limit(this.maxspeed);
this.position.add(this.velocity);
// update the property that stores old positions
var v = [this.position.x, this.position.y]; //AG
this.history.push(v); //AG
// Reset accelertion to 0 each cycle
this.acceleration.mult(0);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
Boid.prototype.seek = function(target) {
var desired = p5.Vector.sub(target,this.position); // A vector pointing from the location to the target
// Normalize desired and scale to maximum speed
desired.normalize();
desired.mult(this.maxspeed);
// Steering = Desired minus Velocity
var steer = p5.Vector.sub(desired,this.velocity);
steer.limit(this.maxforce); // Limit to maximum steering force
return steer;
}
//Starting Here:
//Heavily modified perameters by us
Boid.prototype.render = function() {
// Draw a triangle rotated in the direction of velocity
var theta = this.velocity.heading() + radians(90);
noFill();
noStroke();
push();
translate(this.position.x,this.position.y);
rotate(theta);
beginShape();
vertex(0, -this.r);
vertex(-this.r, this.r*6); //boid size
vertex(this.r, this.r*6); //boid size
endShape(CLOSE);
pop();
// Starting here:
// Our own original code
// Displays path of old locations
for (var i = 0; i < this.history.length; i++) {
var posx = this.history[i][0];
var posy = this.history[i][1];
fill(this.rcolor, this.gcolor, this.bcolor, 90);
ellipse(posx, posy, 5, 5);
}
}
// Our own original code
// Ending here:
// Starting here:
// Separation, Alignment and Cohesion force algorithms sampled from Daniel Shiffman, "The Nature of Code"
// http://natureofcode.com
// Border Constraints
Boid.prototype.borders = function() {
if (this.position.x < 0) {
this.velocity.x = -this.velocity.x;
}
if (this.position.y > height) {
this.velocity.y = -this.velocity.y;
}
if (this.history.length > 10) {
this.history.shift();
}
}
// Separation
// Method checks for nearby boids and steers away
Boid.prototype.separate = function(boids) {
var desiredseparation = 25.0;
var steer = createVector(0,0);
var count = 0;
// For every boid in the system, check if it's too close
for (var i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position,boids[i].position);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) & (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
var diff = p5.Vector.sub(this.position,boids[i].position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
steer.div(count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// Implement Reynolds: Steering = Desired - Velocity
steer.normalize();
steer.mult(this.maxspeed);
steer.sub(this.velocity);
steer.limit(this.maxforce);
}
return steer;
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
Boid.prototype.align = function(boids) {
var neighbordist = 50;
var sum = createVector(0,0);
var count = 0;
for (var i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position,boids[i].position);
if ((d > 0) & (d < neighbordist)) {
sum.add(boids[i].velocity);
count++;
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(this.maxspeed);
var steer = p5.Vector.sub(sum,this.velocity);
steer.limit(this.maxforce);
return steer;
} else {
return createVector(0,0);
}
}
// Cohesion
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
Boid.prototype.cohesion = function(boids) {
var neighbordist = 50;
var sum = createVector(0,0); // Start with empty vector to accumulate all locations
var count = 0;
for (var i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position,boids[i].position);
if ((d > 0) & (d < neighbordist)) {
sum.add(boids[i].position); // Add location
count++;
}
}
if (count > 0) {
sum.div(count);
return this.seek(sum); // Steer towards the location
} else {
return createVector(0,0);
}
}
Anna Gusman and I created a therapeutic garden landscape that grows when it’s sung to. We chose to collaborate on this project because we were both super eager to explore p5’s comprehensive and lauded sound library. We thought that sonic interactions and audiovisual expressions would be great domains to explore by utilizing this tool.
Initially, we brainstormed ways by which people could see themselves “reflected” in a dynamic digital environment. By activating and scaling properties of the internal mic, we could poise the voice of an audience as the actuator of a captivating and therapeutic experience. The scene we designed contains four dynamic elements: recursion, flocking behavior, algorithmic curves and a particle system. Respectively, these would inform the emergence of natural objects like trees, wind, the moon and stars. Each of these dynamic elements are initiated by a singing voice and continue to grow as the viewer continues to sing! While some elements with more exposure to sound multiply, others express continued metamorphosis within themselves.
]]>PSA: THIS IS A TWO-PART ENDEAVOR, SO BE SURE TO SCROLL DOWN FOR PART 2!
Hi guys! This is a game we made called “Carl Cooks a Meal” that exists in two parts. Under the premise, our friend Carl is trying to make a lovely meal for his girlfriend Carla. However, he has absolutely no idea how to start! The first part is a clickventure where people help Carl gather ingredients. People have the option to either check in the refrigerator to see what’s inside OR take a trip to a distant country to get some more exotic ingredients. In travelling, users can learn about the histories behind these ingredients, adding an educational aspect to this part. Users can then return home to begin the second part. In the second part, people help Carl “cook” the meal. This is in the form of a game where users have to catch these ingredients in a pan to reach the final score. However, after each time an ingredient is caught in the pan, they begin to fall faster, making it more difficult as time passes. Once thirty ingredients have been caught, the meal is done, and Carla is very happy! Thanks for helping Carl make the meal!
/*15-104 final projec
team members: rachel park (rsp1) and hamza qureshi (hqq)
section: b; e
CARL COOKS A MEAL*/
var button1, button2, button3, button4, button5; //these variables create buttons, which are defined
//locally to avoid having to create dozens of em
var home, meetCarl, where2go, worldMap, fridge, //these variables will hold the images that form each slide
turmeric, miso, acai, foieGras, uSure,
startup;
var col; //sets color
//---------------------------------------------------
function setup() {
createCanvas(480,480);
background(0);
noLoop(); //allows the slides to remain static (prevents flickering!)
}
//---------------------------------------------------
function draw() { //will only comment once in detail because it can get redundant
home = createImg("https://i.imgur.com/aI9WG89.jpg"); //creates slide
home.position(-760,-760); //position and scales are used to fit the images on the canvas
home.style("transform", "scale(0.25)");
button1 = createButton('Play Game!'); //creates a button
button1.position(300,200);
col = color(129,178,154);
button1.style("background-color", col);
button1.style("color", "white");
button1.mousePressed(PromptPage); //allows the button to load the next screen
}
//---------------------------------------------------
//functions for each page
function PromptPage() {
//prompts with info on what to do
meetCarl = createImg("https://i.imgur.com/HAX6uEa.jpg");
meetCarl.position(-760, -760);
meetCarl.style("transform", "scale(0.25)");
button1 = createButton('Help me out →');
col = color(129,178,154);
button1.style("background-color", col);
button1.style("color", "white");
button1.position(350,200);
button1.mousePressed(ScenePage);
}
//---------------------------------------------------
function ScenePage() {
//loads scene where users have option of gathering ingredients
where2go = createImg("https://i.imgur.com/7F5M1iF.jpg");
where2go.position(-760,-760);
where2go.style("transform", "scale(0.25)");
button1 = createButton('Open the fridge');
col = color(129,178,154);
button1.style("background-color", col);
button1.style("color", "white");
button1.position(20,220);
button1.mousePressed(FridgeFoodPage);
button2 = createButton('Take a trip');
col = color(129,178,154);
button2.style("background-color", col);
button2.style("color", "white");
button2.position(140,460);
button2.mousePressed(WorldFoodPage);
button3 = createButton('Time to cook!');
col = color(129,178,154);
button3.style("background-color", col);
button3.style("color", "white");
button3.position(300,180);
button3.mousePressed(gameLandingPage);
}
//---------------------------------------------------
function WorldFoodPage() {
//loads international map screen, with buttons for diff locations
worldMap = createImg("https://i.imgur.com/aNsxfi1.jpg");
worldMap.position(-760,-760);
worldMap.style("transform", "scale(0.25)");
button1 = createButton('Brazil');
button1.style("background-color", col);
button1.style("color", "white");
button1.position(130,230);
button1.mousePressed(brazil);
button2 = createButton('France');
button2.style("background-color", col);
button2.style("color", "white");
button2.position(150,80);
button2.mousePressed(france);
button3 = createButton('India');
button3.style("background-color", col);
button3.style("color", "white");
button3.position(320,160);
button3.mousePressed(india);
button4 = createButton('Japan');
button4.style("background-color", col);
button4.style("color", "white");
button4.position(420,120);
button4.mousePressed(japan);
button5 = createButton('Go back home!');
button5.style("background-color", col);
button5.style("color", "white");
button5.position(190,450);
button5.mousePressed(ScenePage);
}
//---------------------------------------------------
function FridgeFoodPage() {
//loads fridge screen with items available in the fridge
fridge = createImg("https://i.imgur.com/jPanqPC.jpg");
fridge.position(-760,-760);
fridge.style("transform", "scale(0.25)");
button1 = createButton('Grab the items!');
col = color(129,178,154);
button1.style("background-color", col);
button1.style("color", "white");
button1.position(320,220);
button1.mousePressed(FridgeGrab);
button2 = createButton('No thanks!');
col = color(129,178,154);
button2.style("background-color", col);
button2.style("color", "white");
button2.position(320,260);
button2.mousePressed(ScenePage);
}
//---------------------------------------------------
function FridgeGrab(){
//simulates "grabbing" items from the fridge
fridge = createImg("https://i.imgur.com/zlj1DaE.jpg");
fridge.position(-760,-760);
fridge.style("transform", "scale(0.25)");
button1 = createButton('Back to the kitchen!');
col = color(129,178,154);
button1.style("background-color", col);
button1.style("color", "white");
button1.position(320,220);
button1.mousePressed(ScenePage);
}
//---------------------------------------------------
function india() {
//loads turmeric screen
turmeric = createImg("https://i.imgur.com/tj04pYa.jpg")
turmeric.position(-760,-760);
turmeric.style("transform", "scale(0.25)");
countryButtons();
}
//---------------------------------------------------
function japan(){
//loads miso screen
miso = createImg("https://i.imgur.com/A0mow9a.jpg")
miso.position(-760,-760);
miso.style("transform", "scale(0.25)");
countryButtons();
}
//---------------------------------------------------
function france(){
//loads france screen
foieGras = createImg("https://i.imgur.com/4OLHPzQ.jpg")
foieGras.position(-760,-760);
foieGras.style("transform", "scale(0.25)");
countryButtons();
}
//---------------------------------------------------
function brazil(){
//loads brazil screen
acai = createImg("https://i.imgur.com/H4gDOUD.jpg")
acai.position(-760,-760);
acai.style("transform", "scale(0.25)");
countryButtons();
}
//---------------------------------------------------
function countryButtons(){
//creates two sets of buttons on country screen to
//allow for less code to be used in each of the country slides.
button1 = createButton('Take home!');
button1.style("transform", "scale(0.8)");
button1.style("background-color", col);
button1.style("color", "white");
button1.position(170,310);
button1.mousePressed(WorldFoodPage);
button2 = createButton('All done!');
button2.style("transform", "scale(0.8)");
button2.style("background-color", col);
button2.style("color", "white");
button2.position(178, 370);
button2.mousePressed(gameLandingPage);
}
//---------------------------------------------------
function gameLandingPage(){
//makes sure the user is ready (lol)
uSure = createImg("https://i.imgur.com/9RFTHko.jpg");
uSure.position(-760,-760);
uSure.style("transform", "scale(0.25)");
button1 = createButton('Yes, I am ready!');
button1.style("background-color", col);
button1.style("color", "white");
button1.position(190,250);
button1.mousePressed(gameStartScreen);
button2 = createButton('No, not yet!');
button2.style("background-color", col);
button2.style("color", "white");
button2.position(200, 300);
button2.mousePressed(ScenePage);
}
//---------------------------------------------------
function gameStartScreen(){
//loads final screen of this part, instructing users to scroll
startup = createImg("https://i.imgur.com/duuVdOZ.jpg");
startup.position(-760,-760);
startup.style("transform", "scale(0.25)");
}
//---------------------------------------------------
/*15-104 final project
team members: rachel park (rsp1) and hamza qureshi (hqq)
section: b; e
CARL COOKS A MEAL*/
//setting global variables to use throughout the code
//for score
var score = 0;
//for falling objects
var speed = 10;
var canHit = true;
var x = 0;
var y = 0;
var s = 5;
//for key functions
var keyRIGHT= false;
var keyLEFT= false;
var moveRight = false;
var moveLeft = false;
//for frypan options
var onBasket = false;
//setting modes to use to run the functions
var beforeGame;
var endGame;
var beginning;
var ending;
//for arrays used in code
var fridge = [];
var ixs = [50,-50,350];
var iys = [-500, 0, -1000];
//to load frypan image
var frypan;
//---------------------------------------------------
//preloading images of foods and pushing into new array
function preload() {
var Foods = [
"https://i.imgur.com/WrAqBJF.png",
"https://i.imgur.com/F6VoqQ8.png",
"https://i.imgur.com/6Piz1HF.png",
"https://i.imgur.com/Qltr0uK.png"];
for (var i = 0; i < Foods.length; i++){
fridge.push(loadImage(Foods[i]));
}
}
//---------------------------------------------------
//setting up canvas and using modes
function setup () {
createCanvas(480, 480);
background(129,178,154);
beforeGame = true;
endGame = false;
frypan = loadImage("https://i.imgur.com/UdaokKr.png");
ending = loadImage("https://i.imgur.com/0EdDOXJ.jpg");
beginning = loadImage("https://i.imgur.com/crhULDP.jpg");
}
//---------------------------------------------------
//function to start game when any key is pressed
function keyPressed() {
beforeGame = false;
}
//---------------------------------------------------
//function to make frypan move as a gathering platform
function keyTyped() {
if (keyCode === LEFT_ARROW) {
keyLEFT = true;
} else if (keyCode === RIGHT_ARROW) {
keyRIGHT = true;
}
}
//---------------------------------------------------
//drawing the game by calling the other functions which make the visuals of the objects
function draw() {
if (beforeGame == true) {
push();
scale(0.24);
imageMode(CORNER);
image(beginning,0,0);
pop();
} else {
background(129,178,154);
BasketDraw();//drawing the frypan
foodDraw();//drawing the falling food objects
update();//updating the so that frypan moves with keys and food continuously falls onto canvas
displayScore();//displaying number of foods caught
}
if (endGame == true) {//displaying ending page when game is finished
push();
scale(0.24);
imageMode(CORNER);
image(ending,0,0);
pop();
}
}
//---------------------------------------------------
function reachBottom() {//ending the game when food hits limit
endGame = true;
}
//---------------------------------------------------
function displayScore() {//function to create the score
fill(0);
textSize(20);
text(("Score: " + this.score + " out of 30!"), 80, 23);
}
//--------------------------------------------------
function makeFood(length, xpos, ypos, space) {//class to draw the food objects
var food = {"l": length, "ix": xpos, "iy": ypos, "s": space}
food.draw = foodDraw;
return food;
}
//--------------------------------------------------
function foodDraw() {//drawing the foods
for (var i = 0; i < ixs.length; i++){
imageMode(CORNER);
canHit = true;
fill(255);
stroke(4);
image(fridge[i], this.ixs[i], this.iys[i]);
}
for (var i = 0; i < iys.length; i++) {
this.iys[i] += this.s/2
}
}
//---------------------------------------------------
function makeBasket(xpos,ypos,moveBasket) {//class to make the frypan (aka basket)
var Basket = {"x": xpos, "y": ypos}
Basket.draw = BasketDraw;
return Basket;
}
//---------------------------------------------------
function BasketDraw() {//drawing the basket
noStroke();
fill("#FFD581");
image(frypan,this.x, this.y + height-50);
}
//---------------------------------------------------
function update() {//function to update the objects and have them restart at top to be continuously moving
//for basket
if(keyIsDown(RIGHT_ARROW) & this.x < width-20){
this.x += speed;
print(x);
}
if (keyIsDown(LEFT_ARROW) & this.x > -20){
this.x -= speed;
print(x);
}
print(width)
//for food
for(var i = 0; i < iys.length; i++){
if (this.iys[i] >= height-80) {
if(this.ixs[i] > this.x - 100 & this.ixs[i] < this.x + 100) {
this.score++;
this.s ++;
if( this.score == 30) {
reachBottom();
}
}
this.iys[i] = random(-1000, -300);
this.ixs[i] = random(-300 ,width-40);
}
}
}
//---------------------------------------------------
As one might expect with almost 400 lines of code, there were a couple of roadblocks on the way. The biggest one was probably the marrying of the two parts to create one code, which we weren’t able to do. This is primarily because the first part uses the DOC library via buttons and commands like createImg, while the second part relies solely on p5. This caused difficulties in combining the two sets of code because they required a change in the HTML template to allow them to be combined. Once we were able to, the code wasn’t running as smoothly as we had intended. However, despite dividing them into these two parts, we were able to successfully create a unified game experience that uses two modes to reach a greater goal. For us, that’s a win!
// BORROWED FROM IRA GREENBERG
var radius = 45, rotAngle = -90;
var accelX = 0.0, accelY = 0.0;
var deltaX = 0.0, deltaY = 0.0;
var springing = 0.0009, damping = 0.98;
//corner nodes
var nodes = 5;
//zero fill arrays
var nodeStartX = [];
var nodeStartY = [];
var nodeX = [];
var nodeY = [];
var angle = [];
var frequency = []; // END OF BORROWED CODE
// array for the rings and boxes
var rings = [];
var boxes = [];
// initializing colors for keypressed changes
var r = 250;
var g = 250;
var b = 250;
var frames = [];
//var score = 0;
function preload() { // loading ring popping animation frames
var f = [];
f[0] = "https://i.imgur.com/AZJNy6P.png";
f[1] = "https://i.imgur.com/coAJvFm.png";
f[2] = "https://i.imgur.com/Y3RE12y.png";
f[3] = "https://i.imgur.com/9sTJNBz.png";
for(var i =0; i < 4; i++){
frames[i] = loadImage(f[i]);
}
}
function setup() {
createCanvas(480, 480);
// BORROWED FROM IRA GREENBERG: initialize arrays to 0
for (var i=0; i<nodes; i++){
nodeStartX[i] = 0;
nodeStartY[i] = 0;
nodeY[i] = 0;
nodeY[i] = 0;
angle[i] = 0;
} // END OF BORROWED CODE
// initializes collection of rings
for (var i = 0; i < 3; i++){
var ry = random(-300, 0); //rings are falling from above the canvas at random
rings[i] = makeRing(ry);
boxes[i] = makeBox(ry);
}
// BORROWED FROM IRA GREENBERG: iniitalize frequencies for corner nodes
for (var i = 0; i < nodes; i++){
frequency[i] = random(4, 5);
} // END OF BORROWED CODE
noStroke();
frameRate(30);
}
function draw() {
fill(50);
rect(0,0,width, height);
// display rings + boxes
updateAndDisplayRings();
ringAdd();
updateAndDisplayBox();
boxAdd();
// for the character
drawShape();
moveShape();
// instructional text
text("press 'Q' to eat blue, 'W' to eat pink, 'E' to eat yellow", 180, 450);
}
// CHARACTER
// CODE IS BASED ON IRA GREENBERG'S SOFT BODY EXAMPLE:
// https://p5js.org/examples/simulate-soft-body.html
// HAS BEEN HEAVILY EDITED BY ME
function drawShape() {
// calculate node starting locations
for (var i=0; i<nodes; i++){
nodeStartX[i] = mouseX+cos(radians(rotAngle))*radius;
nodeStartY[i] = mouseY+sin(radians(rotAngle))*radius;
rotAngle += 360.0/nodes;
}
// draw polygon
curveTightness(0.5); // to create soft body like organic shape
noStroke();
fill(r,g,b);
beginShape();
// creates a point at each (nodeX, nodeY) for the 5 corners in the array
for (var i=0; i<nodes; i++){
curveVertex(nodeX[i], nodeY[i]);
}
// to make shape connect all the way around
for (var i=0; i<nodes-1; i++){
curveVertex(nodeX[i], nodeY[i]);
}
endShape(CLOSE); // END OF BORROWED CODE
// eyes
fill(149, 166, 193);
ellipse(mouseX+30, mouseY, 10, 10);
ellipse(mouseX-30, mouseY, 10, 10);
push();
noFill();
stroke(149, 166, 193);
strokeWeight(3);
ellipse(mouseX+30, mouseY, 15, 15);
ellipse(mouseX-30, mouseY, 15, 15);
pop();
}
function moveShape() { // BORROWED FROM IRA GREENBERG
//move center point
deltaX = mouseX;
deltaY = mouseY;
//create springing effect
deltaX *= springing;
deltaY *= springing;
accelX += deltaX*0.8;
accelY += deltaY*0.8;
// slow down springing
accelX *= damping;
accelY *= damping;
//move nodes
for (var i=0; i<nodes; i++){
nodeX[i] = nodeStartX[i]+sin(radians(angle[i]))*(accelX);
nodeY[i] = nodeStartY[i]+sin(radians(angle[i]))*(accelY);
angle[i] += frequency[i];
}
} // END OF BORROWED CODE
function keyPressed() { // changes blob's color
if(keyCode == 81) { // "Q" blue
r = 202;
g = 220;
b = 247;
}
if(keyCode == 87) { // "W" pink
r = 247;
g = 207;
b = 207;
}
if(keyCode == 69) { // "E" yellow
r = 255;
g = 241;
b = 193;
}
}
// RINGS
function updateAndDisplayRings(){
// Update the rings positions, and display them.
for (var i = 0; i < rings.length; i++){
rings[i].move();
rings[i].display();
}
}
function ringAdd() {
// With a very tiny probability, add a new ring to the end.
var newringLikelihood = 0.02;
if (random(0,1) < newringLikelihood) {
rings.push(makeRing(0));
rings.push(makeRing(0));
}
}
// moving the rings
function ringMove() {
this.y += this.speed;
}
// drawing the rings
function ringDisplay() {
noFill();
stroke(210);
strokeWeight(2);
if (dist(mouseX, mouseY, this.x, this.y) <= 50) { // if the mouse is 50 points close to the ring, it pops
this.isPopped = true;
this.timePopped = frameCount; // record the framecount at which it pops
}
if (this.isPopped == false) { // if the state of the ring is not popped
ellipse(this.x, this.y, this.diam, this.diam);
}
else {
this.popped(); // if this.isPopped == true, then calls ringPop which displays pop animation
}
}
function ringPop() { // animating rings popping
var num = frameCount-this.timePopped;
if (num >= frames.length) {
// if num goes past the number of animation frames, the pop dissapears
}
else {
image(frames[num], this.x, this.y, 50, 50);
}
}
// making the rings
function makeRing(cy) {
var ring = {y: cy,
x: random(0,600),
diam: random(15,25),
speed: random(2.0, 3.0),
move: ringMove,
display: ringDisplay,
isPopped: false,
popped: ringPop,
timePopped: -10
}
return ring;
}
// SQUARES
function updateAndDisplayBox(){
// Update the clouds' positions, and display them.
for (var i = 0; i < boxes.length; i++){
boxes[i].bmove();
boxes[i].bdisplay();
}
}
function boxAdd() {
// With a very tiny probability, add a new ring to the end.
var newboxLikelihood = 0.02;
if (random(0,1) < newboxLikelihood) {
boxes.push(makeBox(0));
}
}
// moving the rings
function boxMove() {
this.by += this.bspeed;
this.py += this.pspeed;
this.yy += this.yspeed;
}
// drawing the rings
function boxDisplay() {
// blue box
if (dist(mouseX, mouseY, this.bx, this.by) <= 50 & r == 202 && g == 220 && b == 247) {
// if the mouse is 50 points close to the box and the blob is blue
this.bisEaten= true;
}
if (this.bisEaten == false) { // if the state of the box is not eaten
noStroke();
fill(202, 220, 247);
rect(this.bx, this.by, this.bs, this.bs, 5);
}
else {
}
// pink box
if (dist(mouseX, mouseY, this.px, this.py) <= 50 & r == 247 && g == 207 && b == 207) {
// if the mouse is 50 points close to the box and the blob is pink
this.pisEaten = true;
}
if (this.pisEaten == false) { // if the state of the box is not eaten
noStroke();
fill(247, 205, 202);
rect(this.px, this.py, this.bs, this.bs, 5);
}
else {
// box disapears when state is true
}
// yellow box
if (dist(mouseX, mouseY, this.yx, this.yy) <= 50 & r == 255 && g == 241 && b == 193) {
// if the mouse is 50 points close to the box and the blob is pink
this.yisEaten = true;
}
if (this.yisEaten == false) { // if the state of the box is not eaten
noStroke();
fill(255, 241, 193);
rect(this.yx, this.yy, this.bs, this.bs, 5);
}
else {
// box disapears when state is true
}
}
// making the rings
function makeBox(ty) {
var box = { // blue box coord
by: ty,
bx: random(0,600),
// pink box coord
py: random(0,200),
px: random(0,600),
// yellow box coord
yy: random(0,200),
yx: random(0,600),
bs: random(20,25),
bspeed: random(1.0, 2.0),
pspeed: random(1.0, 2.0),
yspeed: random(1.0, 2.0),
bmove: boxMove,
bdisplay: boxDisplay,
bisEaten: false, // blue false
pisEaten: false, // pink false
yisEaten: false, // yellow false
}
return box;
}
For my final project, I wanted to create a game with a fun ambiguous character. In a way, the game is like a fight between an organic shape and geometric shapes. It’s slightly different from my proposal but I like the way it turned out. It uses a modified version of the generative landscape functions, making the terrain (falling objects) fall downwards instead of sideways. It was difficult to modify the code so that the shapes would fall in a way that was relatively even, and not in lines or waves. The character is done using a heavily modified version of the soft body code found on the p5.js examples.
The objective of the game is to clear the screen! The rings pop whenever the character touches them, but the character’s own color must match up with the color of the squares to eat them. To change the character’s color, the player must select Q, W or E on their keyboard.
]]>For my project, I decided to stay with the theme I had developed throughout the semester with plane-based projects.
The objective of the game is to fly the plane onto the runway while avoiding mountains and lightning. Instructions for running the game are included.
I had a really hard time with this project. My original concept was perhaps more interesting but I had an extremely hard time executing it, so I pivoted my project to this secondary concept at the last minute. However, I had a lot of fun creating it, as well as working on the styling and themes of the splash screens in particular. I hope you enjoy it!
//Jackie Chou
//jwchou@andrew.cmu.edu
//Section E
//Final Project
//stores image variables
var explosion;
var lost;
var crash;
var win;
var beginScreen;
var lightning;
var mountain;
var img;
//variable to determine if the game has started
var gameStarted = false;
//position and speed variables for the plane
var xPos = 240;
var yPos = 0;
var xSpeed = 0;
var ySpeed = 0;
//arrays to store the obstacles in
var mountains = [];
var lightnings = [];
function setup() {
createCanvas(480, 480);
//load background and obstacle images
img = loadImage("https://i.imgur.com/x3rvhGU.png");
lightning = loadImage("https://i.imgur.com/v6p1ANv.png");
mountain = loadImage("https://i.imgur.com/tLB1n6D.png");
explosion = loadImage("https://i.imgur.com/8J62X6Z.png");
//load splash screens
lost = loadImage("https://i.imgur.com/znFRmOW.png");
crash = loadImage("https://i.imgur.com/TXv7bto.png");
win = loadImage("https://i.imgur.com/T0qvSdh.png");
beginScreen = loadImage("https://i.imgur.com/J34UN7I.png");
//pushes random coordinates into the obstacle arrays
for (i = 0; i < 8; i++) {
lightnings.push(random(0, width));
lightnings.push(random(80, 350));
mountains.push(random(0, width));
mountains.push(random(80, 350))
}
}
function draw() {
imageMode(CENTER);
//draws background image
image(img, 240, 240);
//initializes plane if the game has begun
if (gameStarted == true){
ySpeed = 0.5;
}
//controls plane's direction
yPos += ySpeed;
xPos += xSpeed;
//calls function to draw obstacles
drawObstacles();
//displays splash screen before the game starts
if (gameStarted == false) {
image(beginScreen, width/2, height/2);
}
//drawing the airplane
fill(240);
strokeWeight(0.5);
//wings
ellipse(xPos, yPos, 70, 11);
ellipse(xPos, yPos - 20, 35, 8);
//horz stabilizer
fill(108, 190, 225);
ellipse(xPos, yPos, 17, 45);
//fuselage
ellipse(xPos + 17, yPos + 5, 6, 15);
//left engine
ellipse(xPos - 17, yPos + 5, 6, 15);
//right engine
fill(0);
ellipse(xPos - 17, yPos + 10, 10, 2);
//right propeler
ellipse(xPos + 17, yPos + 10, 10, 2);
//left propeller
fill(240);
ellipse(xPos, yPos - 25, 5, 17);
//tail
fill(0);
beginShape();
//cockpit
vertex(xPos - 5, yPos + 10);
vertex(xPos, yPos + 17);
vertex(xPos + 5, yPos + 10);
vertex(xPos + 5, yPos + 5);
vertex(xPos, yPos + 10);
vertex(xPos - 5, yPos + 5);
vertex(xPos - 5,yPos + 10);
endShape();
//checks to see if the plane has collided into lightning
for (i = 0; i < lightnings.length; i += 2) {
if (dist(xPos, yPos, lightnings[i], lightnings[i+1]) <= 35) {
gameOver();
}
}
//checks to see if the plane has collided in mountains
for (i = 0; i < mountains.length; i += 2) {
if (dist(xPos + 3, yPos, mountains[i], mountains[i+1]) <= 38) {
gameOver();
}
}
//calls landing function if plane crosses top edge of runway
if (dist(xPos, yPos, 235, 440) <= 15) {
xSpeed = 0;
ySpeed = 0;
landed();
}
//calls lost screen function if plane leaves canvas (x)
if (xPos <= 10 || xPos >= 470) {
gotLost();
}
//calls lost screen function if plane leaves canvas (y)
if (yPos >= 470) {
gotLost();
}
}
//draws the obstacles using randomized values from the arrays
function drawObstacles() {
for (i = 0; i < lightnings.length; i += 2) {
image(lightning, lightnings[i], lightnings[i+1]);
//image(mountain, random(0, width), random(80, 350));
}
for (i = 0; i < mountains.length; i += 2) {
image(mountain, mountains[i], mountains[i+1]);
}
}
//controls the direction of the plane via arrow keys
function keyPressed() {
if (keyCode === RIGHT_ARROW) {
xSpeed = 0.65;
}
if (keyCode === LEFT_ARROW) {
xSpeed = -0.65;
}
if (keyCode === DOWN_ARROW) {
xSpeed = 0;
}
}
//starts the game
function mousePressed() {
gameStarted = true;
}
//game over function, displays splash screen
function gameOver() {
image(explosion, xPos, yPos - 3);
image(crash, width/2, height/2);
noLoop();
}
//plane lost function
function gotLost() {
image(lost, width/2, height/2);
noLoop();
}
//plane landed function
function landed() {
image(win, width/2, height/2);
noLoop();
}
]]>//Name: Max Stropkay
//Andrew ID: mstropka@andrew.cmu.edu
//Section: E
//Final Project
//decalare variables for font, and audio file
var avenir;
var littlewing;
//array to store vehicle objects
var vehicles = [];
//diameter of circles
var diameter;
//store the value of the amplitude of the audio file
var amplitude;
//array to store the strings that make up the lyrics
//of the song
var lyrics = ['little wing', 'well','shes','walking','through',
'the','clouds','with a', 'circus', 'mind', 'thats','running', 'round',
'butterflies', 'zebras', 'moonbeams', 'fairytales',
'thats all', 'she ever', 'thinks about', 'riding with', 'the', 'wind', 'when',
'Im sad', 'she comes', 'to me', 'with a', 'thousand', 'smiles', 'she',
'gives to', 'me', 'free','its alright', 'she said', 'its alright', 'take',
'anything', 'you', 'want', 'from me', 'anything'];
//array to store the times at which the lyrics
//should appear on screen
var times = [34000, 500, 500, 3000, 500, 500, 2000, 200, 300, 3000, 500,
500, 3000, 1500, 1500, 2000, 3000, 3000, 300, 300, 300, 2000, 4000,
500, 500, 3000, 500, 500, 2000, 200, 300, 3000, 500,
500, 3000, 1500, 1500, 2000, 3000, 3000, 300, 300, 2000, 300, 18000];
var word = -1;
//load soundfile and font
function preload() {
littlewing = loadSound('https://courses.ideate.cmu.edu/15-104/f2017/wp-content/uploads/2017/12/Jimi-Hendrix-Little-Wing.mp3')
avenir = loadFont("https://s3.us-east-2.amazonaws.com/maxstropkayfinalproject/AvenirNextLTPro-Demi.otf");
}
function setup() {
createCanvas(1200, 480);
//play audio file,set volume
littlewing.play();
littlewing.setVolume(0.5);
//set value of amplitude to the amplitude of audio
amplitude = new p5.Amplitude(.04);
updateLyrics();
}
function draw() {
background(51);
//for every vehicle run behaviors, update, and show
for (var i = 0; i < vehicles.length; i++){
var v = vehicles[i];
v.behaviors();
v.update();
v.show();
}
//set diameter to be determined by the amplitude
var level = amplitude.getLevel();
var volume = map(level, 0, 1, 0, 200);
diameter = volume;
}
//define Vehicle object
function Vehicle(x, y) {
this.pos = createVector(random(0, width), random(0, height));
this.target = createVector(x, y);
this.vel = p5.Vector.random2D();
this.acc = createVector();
this.r = 10;
this.color = 255;
this.maxspeed = 10;
this.maxforce = 0.5;
}
Vehicle.prototype.behaviors = function(f) {
var arrive = this.arrive(this.target);
this.applyForce(arrive);
}
Vehicle.prototype.applyForce = function(f) {
this.acc.add(f);
}
//move vehicles based on attraction to the
//target location
Vehicle.prototype.update = function() {
this.pos.add(this.vel);
this.vel.add(this.acc);
this.acc.mult(0);
this.r = diameter + 10*(random(0,1));
this.color = color(diameter*random(0, 100), diameter*random(0, 5), diameter*random(0, 10));
}
//draw ellipses at x,y coordinates of objects
Vehicle.prototype.show = function() {
noStroke();
fill(this.color);
ellipse(this.pos.x, this.pos.y, this.r, this.r);
}
//change speed of object as it gets closer to
//its target location
Vehicle.prototype.arrive = function(target) {
var desired = p5.Vector.sub(target, this.pos);
var d = desired.mag();
var speed = this.maxspeed;
if (d < 100){
var speed = map(d, 0, 100, 0, this.maxspeed);
}
desired.setMag(speed);
var steer = p5.Vector.sub(desired, this.vel);
steer.limit(this.maxforce);
return steer;
}
//move object toward its desired position
Vehicle.prototype.seek = function(target) {
var desired = p5.Vector.sub(target, this.pos);
desired.setMag(this.maxspeed);
var steer = p5.Vector.sub(desired, this.vel);
steer.limit(this.maxforce);
return steer;
}
//display the next word in the array lyrics
//at the time from the time array
function updateLyrics(){
vehicles = [];
word = (word + 1) /*% lyrics.length*/;
print(word);
textAlign(CENTER);
textFont("Avenir")
var points = avenir.textToPoints(lyrics[word], 70, 300, 192);
//console.log(points)
for (var i = 0; i < points.length; i++){
var pt = points[i];
var vehicle = new Vehicle(pt.x, pt.y);
vehicles.push(vehicle);
// stroke(0,255,0);
// strokeWeight(4);
// point(pt.x, pt.y);
}
print(times[word]);
setTimeout(updateLyrics,times[word]);
}
For my final project, I made a program that generates dots that change size and color based on the volume of the music thats being played in the background. The dots then fly to form the lyrics in the song. Syncing up the timing of the lyrics and the music was harder and more time consuming than I anticipated, so it only is synced for the first verse.
Attached is the zip file that contains the audio and the font that can be run on a local server.
To run, first open terminal and copy and paste in this line of code
python -m SimpleHTTPServer 8000
This will run a local server. Then type into the URL in your browser
localhost:8000
Then navigate to wherever you downloaded the file and click to run it.
]]>
Click on either of the two choices that are available to continue through the story.
(Try the closet route!)
//calls beginning function to start the game over
var scene = new beginning();
//holds background images
var bg = [];
var bgURL = [
//outside image
"https://i.imgur.com/NhThk6g.jpg",
//lake reflection image
"https://i.imgur.com/GA10Vet.jpg",
//image of both lake and forest
"https://i.imgur.com/c6C6zEC.jpg",
//cat image
"https://i.imgur.com/4zrzVTj.jpg",
//true ending image
"https://i.imgur.com/LADTQJI.jpg"];
function setup() {
createCanvas(480, 450);
}
function preload(){
// load images from URL
for (i = 0; i < bgURL.length; i++){
bg.push(loadImage(bgURL[i]));
}
}
//LIST OF SCENES
function beginning() {
this.sentence = "You wake up surrounded by complete darkness." +
" Your body aches and you hear the faint sound of growling behind you." +
" You pull your red hood around yourself to keep warm." +
" You feel around and find two doors." +
" One with a round knob and one of with a square knob.";
this.left = new sit1();
this.right = new sitA();
this.lefttext = "go through the round knobbed door";
this.righttext = "go through the square knobbed door";
this.fillcolor = "black";
}
//Round knobbed door
function sit1() {
this.sentence = "You immediately begin to sprint out the door." +
" The fresh air hits your face like cold knives. Outside." +
" You look behind you to hear the growling rumble louder." +
" She's waking up too.";
this.left = new sit2();
this.right = new death("You wait and see what happens." +
" The beast begins to wake up and it immediately sees you" +
" She's angry and you know exactly why." +
" She leaps towards you in a familiar fashion," +
" mouth wide open and ready to bite down...");
this.lefttext = "RUN!!!!";
this.righttext = "Wait and see what happens";
this.fillcolor = "";
this.b = "outside";
}
function sit2() {
this.sentence = "You run away before the beast could notice you leaving." +
" You see a forest and a lake in the distance";
this.left = new sitOne();
this.right = new sit3();
this.lefttext = "Run towards the forest";
this.righttext = "Run towards the lake";
this.fillcolor = "";
this.b = "treeAndLake"
}
function sit3() {
this.sentence = "As you run towards the lake," +
" you stop by the edge of the water," +
" mesmorized by your own unrecognizable reflection...";
this.left = new death("You can't help but continue staring at yourself." +
" Bright blue eyes and a long red cape embracing your frail body." +
" You hear growling beghind you... GIVE...IT...BACK.... ");
this.right = new sitThree();
this.lefttext = "Keep staring at your own reflection";
this.righttext = "Pull your eyes away and continue running";
this.fillcolor = "";
this.b = "reflection"
}
function sitOne(){
this.sentence = "Start running faster and faster through the forest," +
" trees flashing past you." +
" You hear the growling not too far behind...";
this.left = new death("You climbed up the tree as fast as you could." +
" Right as you grabbed a second branch," +
" you feel your hood getting tugged, pulling you down with it...");
this.right = new sitTwo();
this.lefttext = "Climb up a tree";
this.righttext = "Hide in the bushes";
this.fillcolor = "flashing green";
}
function sitTwo(){
this.sentence = "You jump into a nearby bush and wait..." +
" the sound of a frustrated growling felt close," +
" but it seems to have disappeared now.";
this.left = new sitThree();
this.right = new sit3();
this.lefttext = "Keep running!";
this.righttext = "Run back towards the lake";
this.fillcolor = "";
this.b = "outside";
}
function sitThree(){
this.sentence = "You decide to keep running." +
" As you run you trip over a soft rock." +
" Wait, that's a cat!";
this.left = new sitFour();
this.right = new sitFour();
this.lefttext = "Pet the cat";
this.righttext = "Scratch the cat's belly";
this.fillcolor = "";
this.b = "cat";
}
function sitFour(){
this.sentence = "The cat purrs and rolls around on the ground." +
" After a few minutes it gets up.";
this.left = new sitneutralending();
this.right = new sitneutralending();
this.lefttext = "Follow the cat";
this.righttext = "Why wouldn't you follow this cat?";
this.fillcolor = "";
this.b = "cat";
}
//Neutral ending
function sitneutralending(){
this.sentence = "(Neutral ending) You follow the cat into a small den." +
" I guess this is a nicer ending."
this.lefttext = "";
this.righttext = "";
this.fillcolor = "";
this.b = "outside";
}
//--------------------
//Square knobbed door
function sitA() {
this.sentence = "You open the door and find yourself looking into a closet." +
" You run in and shut the door as quietly as you can." +
" She's awake now too.";
this.left = new sitB();
this.right = new death("You decided to scream on the top of your lungs." +
" Immediately and without warning, the beast breaks through the closet" +
" door. Did you have a death wish?");
this.lefttext = "Stay quiet and hope she leaves";
this.righttext = "SCREAM!!!";
this.fillcolor = "black";
}
//Closet scene
function sitB() {
this.sentence = "You decide to sit quietly in the closet." +
" After what seemed like hours, the growling disappeared...";
this.left = new sitC();
this.right = new sit1A();
this.lefttext = "Stay in the closet";
this.righttext = "Walk out";
this.fillcolor = "black";
}
function sitC() {
this.sentence = "You felt uneasy and decided to stay in the closet." +
" You lean back onto the back of the closet and surprisingly," +
" you fell into a hole that leads outside!";
this.left = new sitD();
this.right = new sit1A();
this.lefttext = "Stay in the closet";
this.righttext = "Crawl outside";
this.fillcolor = "black";
}
function sitD(){
this.sentence = "You STILL decide to stay in the closet for some reason." +
" Maybe you're still feeling uneasy..." +
" Time continues to pass as it usually does."+
" Are you even going to continue on this journey?";
this.left = new sitE();
this.right = new sit1A();
this.lefttext = "Stay in the closet";
this.righttext = "CRAWL OUTSIDE";
this.fillcolor = "black";
}
function sitE(){
this.sentence = "You still stay in the closet. This is not like the narnia" +
" wardrobe. There is nothing special about this closet." +
" Why do you want to stay in here so badly?";
this.left = new sitF();
this.right = new sit1A();
this.lefttext = "Stay in the closet";
this.righttext = "Crawl. Outside. Now.";
this.fillcolor = "black";
}
function sitF(){
this.sentence = "Okay, you've committed, we'll stay in this dumb closet."+
" I even took away the 'crawl outside' button. I hope you're happy with yourself.";
this.left = new sitG();
this.right = new sitG();
this.lefttext = "Stay in the closet";
this.righttext = "Stay in the closet";
this.fillcolor = "black";
}
function sitG(){
this.sentence = "I bet you're happy about this endless loop,"+
" Even if you change your mind you won't get it back, you're gonna have to" +
" refresh this whole game manually.";
this.left = new sitH();
this.right = new sitH();
this.lefttext = "Stay in the closet";
this.righttext = "Stay in the closet";
this.fillcolor = "black";
}
function sitH(){
this.sentence = "...";
this.left = new sitI();
this.right = new sitI();
this.lefttext = "Stay in the closet";
this.righttext = "Stay in the closet";
this.fillcolor = "black";
}
function sitI(){
this.sentence = "..........";
this.left = new sitJ();
this.right = new sitJ();
this.lefttext = "Stay in the closet";
this.righttext = "Stay in the closet";
this.fillcolor = "black";
}
function sitJ(){
this.sentence = "..................";
this.left = new sitK();
this.right = new sitK();
this.lefttext = "Stay in the closet";
this.righttext = "Stay in the closet";
this.fillcolor = "black";
}
function sitK(){
this.sentence = "Okay, I'm just going to push you outside. Shoo!";
this.left = new sit1A();
this.right = new sit1A();
this.lefttext = "OUTSIDE";
this.righttext = "GO. OUTSIDE.";
this.fillcolor = "black";
}
//To grandmothers house we go!
function sit1A(){
this.sentence = "You walk outside to see the beast far off in the distance," +
" obviously looking for you. But you have other plans...";
this.left = new death("You dance(?) towards the beast flailing about,"+
" probably hoping to get eaten. (I bet you were the same person wanting to" +
" stay in that closet...)");
this.right = new sit1B();
this.lefttext = "Ignore your plans and dance towards the beast";
this.righttext = "Head towards the smoke in the nearby forest";
this.fillcolor = "";
this.b = "outside";
}
function sit1B(){
this.sentence = "You run through the forest, to grandmother's house." +
" She'll protect you from the beast. You hear the beast" +
" catching up to you, desperate to get what you've stolen back..." +
" You notice that there is a large pit nearby";
this.left = new sit1C();
this.right = new goodishending();
this.lefttext = "Continue running towards grandmother's house";
this.righttext = "Wait to push the wolf into the pit";
this.fillcolor = "flashing green";
}
function sit1C(){
this.sentence = "You finally reach the door of the house" +
" The beast is not far behing you. 'GRANDMOTHER' you scream, let me in!" +
" Hurry!!";
this.left = new trueending();
this.right = new death("You decide to keep running, but the beast gets to you." +
" And you were so close too!");
this.lefttext = "Wait for grandmother to open the door";
this.righttext = "Keep running!";
this.fillcolor = "";
this.b = "outside";
}
//True ending
function trueending(){
this.sentence = "(True Ending) Soon after, the door opens." +
" It's almost impossible to hide your grin..." +
" You look back at the girl in wolfs skin that was chasing you," +
" desperate to get her hood back." +
" 'My, what big teeth you have, little riding hood'!";
this.lefttext = "";
this.righttext = "";
this.fillcolor = "";
this.b = "trueEnd";
}
//Death scene when the beast gets you
function death(sentence) {
this.sentence = sentence;
this.lefttext = "";
this.righttext = "";
this.fillcolor = "red";
}
//Good ending where you kill the beast
function goodishending(){
this.sentence = "(Good Ending) You push the wolf into the pit. Hooray!" +
" Now nothing is in your way...";
this.lefttext = "";
this.righttext = "";
this.fillcolor = "";
this.b = "outside";
}
function draw() {
//Determining background color
if (scene.fillcolor == "red"){
background(171,6,11);
}
else if (scene.fillcolor == "blue"){
background(0, 6, 34);
}
else if (scene.fillcolor == "flashing green"){
frameRate(8);
var r = random(0, 8);
var g = random(0, 60);
var b = random(0, 5);
background(r, g, b);
}
else if (scene.fillcolor == "green"){
background(2, 26, 8);
}
else if (scene.fillcolor == "black"){
background(0);
}
else {
background(0);
}
//Creates background images
if (scene.b == "outside"){
image(bg[0], 0, 0, 480, 450);
}
if (scene.b == "reflection"){
image(bg[1], 0, 0, 480, 450);
}
if (scene.b == "treeAndLake"){
image(bg[2], 0, 0, 480, 450);
}
if (scene.b == "cat"){
image(bg[3], 0, 0, 480, 450);
}
if (scene.b == "trueEnd"){
image(bg[4], 0, 0, 480, 450);
}
//Story text details
fill(200);
textSize(12);
text(scene.sentence, 50, 270, 380, 80);
//left text decision
text(scene.lefttext, 50, 380, 100);
//right text decision
text(scene.righttext, 300, 380, 100);
//Reset button text
if (scene.lefttext == "") {
text("click here to start over", 180, 370);
}
}
//Creating "buttons" for choices and for reset
function mouseClicked(){
//Reset button
if (scene.lefttext == "") {
if (mouseX > 180 & mouseX < 300 && mouseY > 360 && mouseY < 380){
//resets game
scene = new beginning();
}
}
else{
//left button decision
if (mouseX > 50 & mouseX < 130 && mouseY > 370 && mouseY < 420){
scene = scene.left;
}
//right button decision
if (mouseX > 300 & mouseX < 440 && mouseY > 370 && mouseY < 420){
scene = scene.right;
}
}
}
I decided to create a choose-your-own-adventure game! My initial idea was to focus on having no visuals—using only text and sound to guide the user through the story—but ultimately ended up using both visuals and text together, and just text on its own.
The story was difficult to write in its own right and I don’t claim that it is that good, but the point of this game is that most of the endings the user runs into will build on the story of the game. I decided to focus mainly on using objects (since that was the most difficult part of this class for me and I wanted to make sure I ended this class with the knowledge of how to use them).
]]>/*
* GyuEun Park
* 15-104 E
* gyueunp@andrew.cmu.edu
* Final Project
*/
var dots = []; //array of dots in beginning scene
var gravity;
var stars = []; //array of stars in ending scene
var speed;
var ismoving = true;
function setup() {
createCanvas(600, 600);
background(14, 94, 96);
//turtle for the center of the transition scene
var turtle = makeTurtle(width - 115, height - 455);
turtle.penDown();
turtle.setColor(0);
for (var i = 0; i < 1300; i++) {
turtle.forward(10);
turtle.right(141.5);
turtle.forward(420);
if (i % 20 === 0) {
turtle.forward(70);
}
}
if (ismoving){
//dots jump up relatively high due to gravity
gravity = createVector(0, 0.2);
fill(16, 198, 216, 100);
stroke(186, 198, 216, 200);
strokeWeight(4);
}
else {
//array of stars up to 2000
for (var i = 0; i < 2000; i++) {
stars[i] = new Star();
}
}
}
function draw() {
if (ismoving) {
//drawing jumping dots in the initial scene
background(1, 11, 28, 50);
if (random(1) < 0.2) {
dots.push(new Dots());
}
//push through the array of dots, update and show them
for (var i = 0; i < dots.length; i++) {
dots[i].update();
dots[i].show();
}
}
else {
background(1, 11, 28, 10);
//the lower the cursor, the slower the star movement
speed = map(mouseY, 10, width / 2, 0, 5);
//translate so that stars moving out from center, not top left
translate(width / 2, height / 2);
for (var i = 0; i < stars.length; i++) {
//update and show stars that are in motion
stars[i].update();
stars[i].show();
}
}
}
//dot constructor function
function Dots() {
this.dots = new Particle(random(width), height);
this.update = function() {
this.dots.applyForce(gravity);
this.dots.update();
}
this.show = function() {
this.dots.show();
}
}
//particle constructor function
function Particle(x,y) {
this.pos = createVector(x,y);
this.vel = createVector(0, random(-15, -5));
this.acc = createVector(0, 0);
this.applyForce = function(force){
//add force to acceleration, force accumulation
this.acc.add(force);
}
this.update = function() {
//take the acceleration and adds it to the velocity
this.vel.add(this.acc);
//take the velocity and adds it to the position
this.pos.add(this.vel);
//multiply acc to 0 so that acc starts with 0
this.acc.mult(0);
}
this.show = function() {
point(this.pos.x, this.pos.y);
}
}
//star details in the transitioned scene
function Star() {
this.x = random(-width, width);
this.y = random(-height, height);
this.z = random(width);
this.pz = this.z;
this.update = function() {
this.z = this.z - speed;
if (this.z < 1) {
this.z = width;
this.x = random(-width, width);
this.y = random(-height, height);
this.pz = this.z;
}
}
this.show = function() {
fill(16, 198, 216, random(200));
noStroke();
//the locations of the stars, dispersed across the canvas
var sx = map(this.x / this.z, 0, 4, 0, width);
var sy = map(this.y / this.z, 0, 3, 0, height);
//when closer bigger, when farther smaller in size
var r = map(this.z, 0, width, 16, 0);
ellipse(sx, sy, r, r);
}
}
function mousePressed(){
ismoving = !(ismoving);
setup();
}
function turtleLeft(d){this.angle-=d;}function turtleRight(d){this.angle+=d;}
function turtleForward(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;
var newy=this.y+sin(rad)*p;this.goto(newx,newy);}function turtleBack(p){
this.forward(-p);}function turtlePenDown(){this.penIsDown=true;}
function turtlePenUp(){this.penIsDown = false;}function turtleGoTo(x,y){
if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);
line(this.x,this.y,x,y);}this.x = x;this.y = y;}function turtleDistTo(x,y){
return sqrt(sq(this.x-x)+sq(this.y-y));}function turtleAngleTo(x,y){
var absAngle=degrees(atan2(y-this.y,x-this.x));
var angle=((absAngle-this.angle)+360)%360.0;return angle;}
function turtleTurnToward(x,y,d){var angle = this.angleTo(x,y);if(angle< 180){
this.angle+=d;}else{this.angle-=d;}}function turtleSetColor(c){this.color=c;}
function turtleSetWeight(w){this.weight=w;}function turtleFace(angle){
this.angle = angle;}function makeTurtle(tx,ty){var turtle={x:tx,y:ty,
angle:0.0,penIsDown:true,color:color(128),weight:1,left:turtleLeft,
right:turtleRight,forward:turtleForward, back:turtleBack,penDown:turtlePenDown,
penUp:turtlePenUp,goto:turtleGoTo, angleto:turtleAngleTo,
turnToward:turtleTurnToward,distanceTo:turtleDistTo, angleTo:turtleAngleTo,
setColor:turtleSetColor, setWeight:turtleSetWeight,face:turtleFace};
return turtle;}
Instructions: Click anywhere or move your cursor around to make alterations.
Brief summary: Jumping Dots, Turtle, and Turquoise Starfield.
For my final project, I took the advantage of making my canvas a space in which the viewers could momentarily be immersed in. As I believe that the strength of interactive artworks is their ability to allow the audiences to create unexpected changes, I allowed the environment of my work to be altered by the viewers. Despite the changeable environment, however, I also focused on achieving a sense of visual consistency through the usage of coherent colorations and forms.
Conflicting factors coexist in my work; the space is chaotic yet orderly, inviting yet daunting, random yet systematic. Coexistences such as these were merged in creating this single work. I hope you enjoy momentarily being immersed in this space I created!
I also filmed projections of my work to experience its amplified effects outside of my screen.
and here are screenshots of various possible outcomes:
Here is a video of a slight alteration of the piece. I liked how it looked (and reminded me of Christmas and our imminent winter break!), so I decided to include it.
]]>