Eliza Pratt – Final Project

dress up doll

/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Final Project
*/

//This program uses images to simulate an interactive dressup game.
//It allows users to click on items which will then jump to the 
//front of the screen via reordering of the array. Users can drag 
//clothing close to the body, where it will then snap into place
//in a smooth motion. When a shirt is snapped onto the body, a button
//will appear that allows the user to recolor the shirt (if clothing is 
//layered, only the top layer will be recolored). There is additional
//functionality for resetting the canvas and randomizing outfits.

//stores figure and clothing image links
var croquisLink = "https://i.imgur.com/7aZm27c.png";

var hairLinks = ["https://i.imgur.com/SwP45yO.png", 
                 "https://i.imgur.com/TqmIRYi.png", 
                 "https://i.imgur.com/JqFGPxq.png", 
                 "https://i.imgur.com/QzqTfIY.png", 
                ];

var shirtLinks = ["https://i.imgur.com/vNLNc6V.png", 
                 "https://i.imgur.com/e3LzXk6.png", 
                 "https://i.imgur.com/tBuSMNk.png", 
                 "https://i.imgur.com/wkJ7JJC.png"
                ];

var pantsLinks = ["https://i.imgur.com/hyAxaOY.png", 
                 "https://i.imgur.com/yk3zFDt.png", 
                 "https://i.imgur.com/mF21MeN.png", 
                  "https://i.imgur.com/ki89EhN.png"
                ];

var shoesLinks = ["https://i.imgur.com/EMbMtDy.png", 
                 "https://i.imgur.com/IZaU3Ls.png", 
                 "https://i.imgur.com/xa3Rrjs.png", 
                 "https://i.imgur.com/S8GJRGa.png"
                ];

//loads images for figure and clothing
var croquis;
var hair = [];
var shirt = [];
var pants = [];
var shoes = [];

//stores clothing objects
var blouse = [];
var bottom = [];
var feet = [];

//positions for figure and clothing
var bodyCenter = 120;
var headCenterY = 87;
var shirtCenter = 224;
var pantsCenter = 389;
var shoesCenter = 544;

//stores colors for clothing
var wheel = ["white", "red", "turquoise", "green"];
//image link for color wheel
var colorLink = "https://upload.wikimedia.org/wikipedia/commons/d/dc/Eight-colour-wheel-2D.png";
//stores color wheel image
var colorWheel;
//positions for wheel
var wheelX = 40;
var wheelY = 140;

//positions for random button
var randomX = 490;
var randomY = 580;

//positions for direction button
var infoX = 560;
var infoY = 580;

//counters for changing hair style and clothing color
var hairClick = 0;
var colorClick = 0;

//reset and random button color
var buttonColor = 255;

//indicate that pants and shoes are not being dragged
var dragBottom = false;
var dragFeet = false;

//array position of shirt on body
var wearing;

//display directions
var showInfo = false;
//------------------------------------------------------------------

//loads images into variables and arrays
function preload() {
    croquis = loadImage(croquisLink);
    colorWheel = loadImage(colorLink);
    for (var i = 0; i < hairLinks.length; i++) {
        hair[i] = loadImage(hairLinks[i]);
        shirt[i] = loadImage(shirtLinks[i]);
        pants[i] = loadImage(pantsLinks[i]);
        shoes[i] = loadImage(shoesLinks[i]);
    }
}


function setup() {
    createCanvas(600, 600);
    //calls function to make clothing objects and arrange on the page
    clothesSetup();
}


//fills shirt, shoes and pants arrays with objects containing images and positions
//serves as a reset function when mix() and reset() are called
function clothesSetup() {
    hairClick = 0;
    for (var i = 0; i < 4; i++) {
        blouse[i] = makeItem(shirt[i], width * 0.48 + 81 * i, 
                             height * 0.15 + 20 * i, shirtCenter);
        bottom[i] = makeItem(pants[i], width * 0.49 + 77 * i, 
                             height * 0.55 + 10 * i, pantsCenter);
        feet[i] = makeItem(shoes[i], width * 0.49 + 77 * i, 
                             height * 0.85 + 5 * i, shoesCenter);
    }
}


function draw() {
    background(206, 255, 181);
    imageMode(CENTER);

    //displays figure
    image(croquis, bodyCenter, height / 2, 225, 600);

    //displays clothing
    for (var i = 0; i < shirt.length; i++) {
        //draws current hair style
        image(hair[hairClick % 4], bodyCenter, headCenterY);
        //draws all pants, shirts and shoes
        bottom[i].draw();
        blouse[i].draw();
        feet[i].draw();

        //if shirt is on the body, store index and make color wheel appear
        if (blouse[i].x == bodyCenter) {
            drawWheel();
            wearing = i;
        }
    }

    //calls function to fit clothing on the figure
    snap(blouse);
    snap(bottom);
    snap(feet);

    //calls reset function
    reset();
    //calls direction function
    directions();

    //If the mouse is not being pressed, reset drag state to false
    //Note: this will be utilized in the mouseDragged function to prevent
    //multiple items from being "picked up" at once
    if (!mouseIsPressed) {
        dragBottom = false;
        dragFeet = false;
    }

    //draw random button
    drawButton("random", randomX, randomY, buttonColor);
    drawButton("directions", infoX, infoY, buttonColor);
}


function mousePressed() {
    //HAIR STYLE----------------------------------------------------
    //distance from mouse to head
    var dHair = dist(mouseX, mouseY, bodyCenter, headCenterY);

    //if hair is clicked, increase counter to display different style
    if (dHair < 60) hairClick++;

    //--------------------------------------------------------------

    var click = false; //tracks if a clothing item has been selected
    var selection; //stores type of selected item

    //SHIRT---------------------------------------------
    //cycle through shirt positions
    for (var i = 0; i < blouse.length; i++) { 
        var dBlouse = dist(mouseX, mouseY, blouse[i].x, blouse[i].y);
        //if shirt is clicked, store the array and index
        if (dBlouse < 75) {
            index = i;
            click = true;
            selection = blouse;
        }
    }

    //PANTS-------------------------------------------
    //cycle through pants positions
    for (var i = 0; i < bottom.length; i++) { 
        var dBottomX = abs(mouseX - bottom[i].x);
        var dBottomY = abs(mouseY - bottom[i].y);
        //if pants are clicked, store the array and index
        if (dBottomX < 60 & dBottomY < 150) {
            index = i;
            click = true;
            selection = bottom;
        }
    }

    //SHOES-------------------------------------------
    //cycle through shoes positions
    for (var i = 0; i < feet.length; i++) { 
        var dFeetX = abs(mouseX - feet[i].x);
        var dFeetY = abs(mouseY - feet[i].y);
        //if shoes is clicked, store the array and index
        if (dFeetX < 60 & dFeetY < 40) {
            index = i;
            click = true;
            selection = feet;
        }
    }

    //if an item is selected, display it on top of other items
    if (click) bringToFront(selection, index);  
    //---------------------------------------------------------------

    //RECOLORING-----------------------------------------
    //distance from mouse to button
    var dTint = dist(mouseX, mouseY, wheelX, wheelY);
    //if button is clicked, recolor item
    if (dTint < 20) recolor(3);

    //RANDOM OUTFIT--------------------------------------
    //distance from mouse to button
    var dRandomX = abs(randomX - mouseX);
    var dRandomY = abs(randomY - mouseY);

    //if button is clicked, assemble a random outfit
    if (dRandomX < 30 & dRandomY < 12) mix();

    //DIRECTIONS-----------------------------------------
    //distance from mouse to button
    var dInfoX = abs(infoX - mouseX);
    var dInfoY = abs(infoY - mouseY);

    //if button is clicked, display info
    if (dInfoX < 30 & dInfoY < 12) showInfo = !showInfo;
}


//if an item is selected, push it to the end of the array
//and remove it from its original position.
//Reordering the array allows item to displayed "on top"
function bringToFront(item, index) {
    item.push(item[index]);
    item.splice(index, 1);   
}


function mouseDragged() {
    //distance between mouse and "most recent" shirt, pants and shoe positions
    var dBlouse = dist(mouseX, mouseY, blouse[3].x, blouse[3].y);
    var dBottomX = abs(mouseX - bottom[3].x);
    var dBottomY = abs(mouseY - bottom[3].y);
    var dFeetX = abs(mouseX - feet[3].x);
    var dFeetY = abs(mouseY - feet[3].y);

    //If mouse is on the shirt and no pants or shoes are 
    //already selected, call function to allow dragging.
    //Establishing items as "true" when they are selected prevents
    //other items from being picked up while the mouse is dragged.
    if (dBlouse < 80 & !dragBottom && !dragFeet) {
        dragItem(blouse, 30);
    }
        // if only shoes are selected, allow them to be dragged
    else if (dFeetX < 60 & dFeetY < 50 && !dragBottom) {
        dragFeet = true;
        dragItem(feet, 0);
    }
    // if only pants are selected, allow them to be dragged
    else if (dBottomX < 60 & dBottomY < 140 && !dragFeet) {
        dragBottom = true;
        dragItem(bottom, 90);
    }
}


//allows selected item to be dragged
function dragItem(item, offset) {
    item[3].x = mouseX;
    item[3].y = mouseY + offset;
}


//snaps items near the body to their fixed positions
function snap(item) {
    //measures distance from item to target position
    var dx = bodyCenter - item[3].x;
    var dy = item[3].center - item[3].y;
    var D = sqrt(dx*dx + dy*dy);

    //when an item is near its target and the mouse is released,
    //snap it into position with a smooth motion
    if (D < 50 & !mouseIsPressed) {
        dirX = dx / max(1, D);
        dirY = dy / max(1, D);
        item[3].x += dirX;
        item[3].y += dirY;
    }
}


//BUTTON FUNCTIONS-------------------------------------

//draw button with label, position, and color parameters
function drawButton(type, x, y, col) {
    //button
    stroke(0);
    strokeWeight(2);
    fill(col);
    rectMode(CENTER);
    rect(x, y, 60, 24, 10);
    //text
    noStroke();
    fill("MAGENTA");
    textAlign(CENTER);
    text(type, x, y + 5);
}


//provides button to reset clothes to original position
function reset() {
    //button position
    var buttonX = 420;
    var buttonY = 580;

    //distance from mouse to center of button
    var dResetX = abs(buttonX - mouseX);
    var dResetY = abs(buttonY - mouseY);

    //if button is clicked, recall setup and draw "clicked" button
    if (mouseIsPressed & dResetX < 30 && dResetY < 12) {
        drawButton("reset", buttonX, buttonY, buttonColor - 80);
        clothesSetup();
    }
    //else, draw button in unclicked state
    else drawButton("reset", buttonX, buttonY, buttonColor);
}


//draw color wheel with an outline
function drawWheel() {
    image(colorWheel, wheelX, wheelY, 40, 40);
    noFill();
    stroke(0);
    strokeWeight(2);
    ellipse(wheelX, wheelY, 37, 37); 
}


//recolors shirt when wheel is clicked
function recolor() {
    //increase color counter and assign tint
    colorClick++;
    blouse[wearing].tint = wheel[colorClick % 4];
}


//provides button to assemble a random outfit
function mix() {
    //selects a random shirt, pants and shoe pairing
    var randBlouse = round(random(3));
    var randBottom = round(random(3));
    var randShoes = round(random(3));

    //draw button in "clicked" mode
    //call setup to remove any clothes on the body
    clothesSetup();
    //selects random hair style
    hairClick = round(random(3));

    //positions random shirt on the body
    blouse[randBlouse].x = bodyCenter;
    blouse[randBlouse].y = shirtCenter;
    //positions random pants on the body
    bottom[randBottom].x = bodyCenter;
    bottom[randBottom].y = pantsCenter;
    //positions random shoes on the body
    feet[randShoes].x = bodyCenter;
    feet[randShoes].y = shoesCenter; 
}


//displays directions for game
function directions() {
    if (showInfo) {
        stroke(0);
        strokeWeight(10);
        fill(255);
        rect(width / 2, height / 2, 400, 150, 30);
        noStroke();
        fill("MAGENTA");
        text("Drag and drop the clothes to make one chic as heck fashion diva", width / 2, height / 2 - 30);
        text("Click her face to change hair styles", width / 2, height / 2 - 5);
        text("Click the color wheel to recolor her shirt", width / 2, height / 2 + 20);
        text("(Press any key to escape)", width / 2, height / 2 + 60);
    }
    //exits directions when a key is pressed
    if (keyIsPressed) showInfo = false;
}

//---------------------------------------------------------------------

//OBJECT CREATION AND CLOTHING DISPLAY

//Creates objects with parameters for
//image, initial position, and center relative to the body.
function makeItem(ipic, ix, iy, icenter) {
    return {pic: ipic, x: ix, y: iy, 
            center: icenter, 
            tint: 255,
            draw: drawItem,
            };
}


//draw image and recolor with specified tint
function drawItem() {
    tint(this.tint);
    image(this.pic, this.x, this.y);
    noTint();
}



Directions: Drag and drop the clothes to make one chic-as-heck fashion diva! Click on the hair to change the style. If you give her a shirt, you can tint it by clicking on the color wheel. Click the random button to generate a random outfit, and click the reset button to put everything back!

Statement: This project was a lot of fun to make and I loved that I was able to incorporate my own drawing style with my code! It ended up being a lot more complicated than I thought to get the click, drag, and drop functions right, but I’m happy with what I was able to do. I’m proud I was able to figure out a way to change the order in which items were displayed on the screen, and I think this level of responsiveness helps my project feel more like a real dress up game. While I’m happy with how the game turned out, I do wish I could have the mouse respond to clicking anywhere on a clothing item rather than estimating its distance from the center.

Eliza Pratt – Looking Outwards 12

For my final project, I’ve drawn inspiration from a handful of game designers that create intuitive, aesthetically pleasing games for web and mobile platforms.

Azalea’s games are known for their intuitive controls and unique artistic style

Since I plan on creating an interactive dress up game, I’ve paid particular attention to the game developer Azalea, an artist known for creating almost a hundred fashion games for girls. She first draws the figures, clothing and backgrounds on Photoshop and then programs the interactive elements in actionscript 3 using Adobe Flash. Not only is Azalea known for maintaining her own site of exclusive games, but she’s gained attention for her unique artistic style and clean, intuitive designs. Since online games that are developed for children often use excessive decals and loud visuals, I admire Azalea’s distinct artistic expression and attention to usability.

The mobile game Badland has received considerable attention for its captivating visuals

While researching games with strong creative voices, I also drew inspiration from Badland, a mobile game developed by Frogmind. Following its release in 2013, Badland has received considerable attention for its captivating visuals, simple controls, and adventurous narrative.

I admire developers such as Azalea and Frogmind for their ability to combine beautiful visuals, strong user interfaces, and programming to create games for the public. While I’m developing my own game for this project, I hope to draw inspiration from these successful elements in my own design.

 

Eliza Pratt – Project Proposal

For my final project, my inner-8-year-old has been begging me to make an interactive dress up game. I’m excited to do this since I plan on drawing all the clothes and then importing them into my code. It’ll have some click and drag features that snap into place when they’re close to the body, as well as accessories and hairdo selections. I also plan on having customizable colors for eyes, hair, lips, and maybe the clothes as well. I’m excited to do this because I’ve always been interested in designing for children and young girls in particular. As a design student, creating things that are fun and playful has always been at the forefront of what I see myself doing in the future. While it’s true that games like this already exist, the prospect of both designing and coding my own validates that I now have the skills to create something that I’ve wanted to since I was little.

Eliza Pratt – Looking Outwards 11

 

The ARC creates generative music by responding to touch sensors in different objects

At the South by Southwest (SXSW) festival in 2016, Deloitte Digital created an interactive space where people could use touch sensors to generate electronic music. Known as the ARC (Audience Reactive Composition), the space holds programmable objects that use sensors to adjust the amplitude, pitch, and other elements of exclusive tracks. According to DJ Baio, an electronic artist with expertise on the project, the installation is controlled using Ableton software. Ableton, which is commonly used in electronic live concerts, can be used to adjust notes, frequency, and samples of audio to create unique versions of tracks so every performance is unique. I admire this project as it allows people with no experience in the computational sound world to create their own generative music. Moreover, adopting responsive technology to make music allows endless opportunities to create that would otherwise be impossible.

Eliza Pratt – Project 11

click to redraw!

/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Project 11
*/

var face = 5; //face size
var faceY = 100; //starting y coordinate for face
var w = 2; //stroke weight
var eye = {LX: 0, LY: 0, RX: 0, RY: 0}; // eye coordinates
var lipX; // lip x position
var lipY; //lip y position

function setup() {
    createCanvas(480, 360);
    frameRate(10);
}

function draw() {
    background("beige");

    for (var i = 0; i < 3; i++) {
      var turt = makeTurtle(90 + i * 150, faceY);
      turt.penDown();
      turt.setColor("black");

      //draw face features
      faceBrowsNose(turt);
      eyes(turt);
      glasses(turt);
      lips(turt);
    }

    noLoop();

}

//redraw face when the mouse is pressed
function mousePressed() {
  draw();
}


//draws face, eyebrows and nose
function faceBrowsNose(ttl) {
  //FACE
  for (var i = 0; i < 180; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 100 + random(-2.5, 2.5));
    ttl.forward(face + random(-face / 3, face / 3));
  }
  ttl.left(20);

  //LEFT EYEBROW
  for (var i = 0; i < 50; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 100);
    ttl.forward(2 + random(-2, 2));
    //save coordinates at top of brow to assign eye position
    if (i == 25) {
      eye.LX = ttl.x;
      eye.LY = ttl.y + random(10, 25);
    }
  }
  //LEFT NOSE
  for (var i = 0; i < 10; i++) {
    turtlepressure(ttl);
    ttl.right(random(-0.5, .5));
    ttl.forward(1);
  }
  //BOTTOM NOSE
  for (var i = 0; i < 50; i++) {
    turtlepressure(ttl);
    ttl.left(360 / 100);
    ttl.forward(0.5 + random(-1, 1));
    //save bottom of nose coordinates for lip position
    if (i == 25) 
      lipY = ttl.y + random (20, 30);
      lipX = ttl.x + random (-30, 10);
  }
  //RIGHT NOSE
  for (var i = 0; i < 10; i++) {
    turtlepressure(ttl);
    ttl.right(random(-0.5, .5));
    ttl.forward(1);
  }
  //RIGHT EYEBROW
  for (var i = 0; i < 50; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 100);
    ttl.forward(2 + random(-2, 2));
    if (i == 25) {
      eye.RX = ttl.x;
      eye.RY = ttl.y  + random(10, 25);
    }
  }
}


//draws eyes
function eyes(ttl) {
    ttl.penUp();
    ttl.goto(eye.LX, eye.LY);
    ttl.penDown();

    //left eye
    for (var i = 0; i < 100; i++) {
      turtlepressure(ttl);
      ttl.right(360 / 50);
      ttl.forward(.5 + random(-0.75, 0.75));
    }

    ttl.penUp();
    ttl.goto(eye.RX, eye.RY);
    ttl.penDown();

    //right eye
    for (var i = 0; i < 100; i++) {
      turtlepressure(ttl);
      ttl.right(360 / 50);
      ttl.forward(.5 + random(-0.75, 0.75));
    }
}


//draws glasses
function glasses(ttl) {
  ttl.penUp();
  ttl.goto(eye.LX + random(10, 18), eye.LY);
  ttl.penDown();

  //lens 1
  ttl.face(90);
  for (var i = 0; i < 100; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 50 + random(-4, 4));
    ttl.forward(2 + random(-0.75, 0.75));
  }

  ttl.penUp();
  ttl.goto(eye.RX - random(10, 18), eye.RY);
  ttl.face(330);
  ttl.penDown();

  //lens 2
  ttl.face(270);
  for (var i = 0; i < 100; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 50 + random(-4, 4));
    ttl.forward(2 + random(-0.75, 0.75));
  }
}


//draws lips
function lips(ttl) {

  ttl.penUp();
  ttl.goto(lipX, lipY);
  ttl.penDown();
  ttl.face(310);

  //TOP LEFT
  for (var i = 0; i < 20; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 100);
    ttl.forward(1 + random(-1, 1));
  }
  ttl.left(50);

  //TOP RIGHT
  for (var i = 0; i < 20; i++) {
    turtlepressure(ttl);
    ttl.right(360 / 100);
    ttl.forward(1 + random(-1, 1));
  }
  ttl.face(180);

  //LINE
  for (var i = 0; i < 30; i++) {
    turtlepressure(ttl);
    ttl.forward(1);
    ttl.right(random(-2, 2));
  }
  ttl.face(90);

  //BOTTOM LIP
  for (var i = 0; i < 50; i++) {
    turtlepressure(ttl);
    ttl.left(360 / 100);
    ttl.forward(1 + random(-1, 1));
  } 
}


//varies stroke weight to create "hand drawn" effect
function turtlepressure(turtle) {
  w += random(-0.4, 0.4);
  if (w <=0) w = 0.4;
  else if (w>= 3) w = 2.7;
  turtle.setWeight(w);

} 

/////////////////////////////////////////////////////////////////
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;
}

Ever since our second variable face assignment where we saw examples of Moka’s generative faces, I’ve wanted to code doodles that look blind contours! I had a lot of fun playing with the turtles and got some pretty great results from randomizing different things. Also, by randomizing the stroke weight for each point I was able to make my own “brush” of sorts. It was challenging to have any control over the randomness factor, but here are some of the beautiful creations that came out of it before I decided to do multiple faces:

friend with hair
derp
sleepy friend
abstract friend

Eliza Pratt – Looking Outwards 10

“Emerald City”, a project developed by a team of women at Intel, explored the use of embedded technology to benefit women in an urban context.

Adelle Lin is a technological designer with a background in math and architecture. In a collaborative project for Intel with Caroline Foster, Reema Upadhyaya and Natalia Pulido, she served as researcher, UX designer, and Technology Prototyper to create “Emerald City,” an exploration of embedded technology in women’s shoes. While this type of research had previously only been tested on menswear, Lin and her team identified issues that were common for professional women in an urban context.

In addition to helping with tasks like navigation, the technology included features to help women feel safe.

In addition to features that would assist with weather alerts and navigation, these “smart boots” also included technology  connected to a crime heat map that could detect unsafe neighborhoods and allow emergency messaging. I believe that considering safety features such as these is essential to why more women are needed in the field of  creative technology. Moreover, as a design major myself, research projects such as these allow me to visualize how I might utilize my skills to help other women in a variety of contexts.

Eliza Pratt – Project 10

sketch

/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Project 10
*/


//array to store craters
var crater = [];
//starting x position of rocket
var rocketX = 540;
//starting y position of rocket
var rocketY = 100;
//starting rocket speed
var rs = 8;
//rocket is not on screen
showRocket = false;
//faulty rocket
var faulty = false;

//creates initial craters with no overlap
function setCrater() {
    //craters that do not overlap are infrequent, so loop
    //runs many times to ensure more craters are drawn
    for (var j = 0; j < 100; j++) {  

        //create a random position
        var pos = {x: random(width), y: random(height * 0.55, height)};
        //assume there is no overlap
        var overlap = false;

        //check new position against all old positions
        //if distance between old and new position is greater than the 
        //maximum size of the crater, assume overlap
        for (var i = 0; i < crater.length; i++) {
            var old = crater[i];
            var d = dist(pos.x, pos.y, old.x, old.y)
            if (d < 180) overlap = true;
        }

        //push position into array if there is no overlap
        if (!overlap) {
            crater.push(pos);
        }
        //make a crater for each position in the array
        for (var w = 0; w < crater.length; w++) {
            crater[w] = makeCrater(crater[w].x, crater[w].y);
        }
    }   
}

function setup() {
    createCanvas(480, 400);
    frameRate(20);

    //create stars with random positions and size
    for (var i = 0; i < STARPOINTS; i++) {
        pX.push(random(0, width));
        pY.push(random(0, height / 2));
        pS.push(random(0.2, 2))
    }

    setCrater();
}


function draw() {
    background(0);
    drawStars();
    //if rocket is prompted, 
    //draw it and move it across screen
    if (showRocket == true) {
        makeRocket(rocketX);
        rocketX -= rs;
    }

    //resets rocket position once it has travelled across screen
    if (rocketX <= -60) {
        showRocket = false;
        faulty = false;
        rocketX = 540;
        rocketY = random(0, height * 0.45);
        rs = random(5, 20);

    }

    //draw terrain
    drawMoon();
    //move craters
    updateCrater();
    removeCrater();
    //add craters and rockets
    addStuff();
}

/////////////ROCKET////////////////
function drawRocket() {
    //flame position
    var fireX = this.x + 25;
    //size of flame
    var fire = 15;

    noStroke();

    //flame
    fill("orange");
    ellipse (fireX, this.y, fire, fire);
    triangle(fireX + 2, this.y + fire / 2, fireX + 2, this.y - fire / 2, 
              fireX + 20, this.y);

    //fins
    fill("red");
    arc(this.x + 10, this.y, 60, 60, HALF_PI, 3 * HALF_PI, CHORD);
    rect(this.x - 10, this.y - 10, 30, 20);

    //body
    fill("blue");
    arc(this.x, this.y, 120, 30, PI / 4, PI * 1.58, CHORD);

    //window
    fill("lightblue");
    strokeWeight(4);
    stroke("darkblue");
    ellipse(this.x - 30, this.y, 15, 15);
}

function makeRocket(rx) {
    //give some rockets a concerningly faulty motion
    if (faulty == true) rocketY += random(-5, 5);

    //create object
     var rocket = {x: rx, y: rocketY, display: drawRocket, speed: rs};
     rocket.display();
}

///////////////STARS////////////////

//number of stars
var STARPOINTS = 300;

//arrays for position and stroke
var pX = [];
var pY = [];
var pS = [];

function drawStars() {
    //draw 300 stars
    for (var i = 0; i < STARPOINTS; i++) {
        // make 'em TWINKLE
        stroke(random(100, 255));
        strokeWeight(pS[i]);
        point(pX[i], pY[i], 10, 10);
    }
}

////////////MOON//////////////////////
function drawMoon() {

    //blue stroke for faint glow
    var w = 5;
    strokeWeight(w);
    stroke("darkblue");

    //draw moon terrain and have it move across screen
    fill(233, 238, 240);
    beginShape();
    for (var x = 0; x < width + w; x++) {
        var t = x * 0.005 + millis() * 0.0001;
        var y = map(noise(t), 0,1, height/3, height * 0.55);
        while (y >= height * 0.6) y = map(noise(t), 0,1, height/3, height * 0.55);
        vertex(x, y)
    }
    vertex(width + w, height + w);
    vertex(-w, height + w);
    endShape();
}

//////////CRATERS///////////////////////////

//draw craters and move them across screen
function updateCrater() {
    for (var i = 0; i < crater.length; i++) {
        crater[i].move();
        crater[i].display();
    }
}

//keep craters that are still on screen and 
//remove the rest from the array
function removeCrater() {
    var keepCrater = [];
    for (var i = 0; i < crater.length; i++) {
        if (crater[i].x + crater[i].w > 0) {
            keepCrater.push(crater[i]);
        }
    }
    crater = keepCrater;
}

//periodically adds elements to screen
function addStuff() {

    //creates new craters and adds them to array
    //every 100 frame counts to prevent overlap
    if (frameCount % 100 == 0) {
        crater.push(makeCrater(width + 90, random(height / 2, height)));
    }

    //infrequently creates a rocket if there is not already one on screen
    var spotRocket = 0.1;
    var faultyRocket = 0.3;
    if (spotRocket > random(0, 1) & showRocket == false) {
        showRocket = true;
        //occasionally creates a faulty rocket
        if (faultyRocket > random(0, 1)) faulty = true;
    }

}

//move craters across screen
function moveCrater() {
    this.x += this.speed;
}

//draws craters
function drawCrater() {
    noStroke();
    //shadow
    fill(this.color - 30);
    ellipse(this.x, this.y - 10, this.w, this.h);
    //crater
    fill(this.color);
    ellipse(this.x, this.y, this.w, this.h);
    stroke(240);
    noFill();

    //outline
    strokeWeight(this.stroke);
    ellipse(this.x, this.y - 5, this.w - 3, this.h + 8);

}

function makeCrater(cx, cy) {
    //maps width, color and stroke so craters appear
    //smaller when they are "farther" away
    var breadth = map(cy, height / 2, height, 55, 180);
    var col = map(cy, height / 2, height, 220, 80);
    var s = map(cy, height / 2, height, 7, 10);

    var crater = {x: cx, y: cy, w: breadth, h: breadth / 4,
                  color: col,  
                  speed: -2.2, 
                  stroke: s,
                  move: moveCrater, 
                  display: drawCrater};
    return crater;

}




This was the most I’ve ever been confused on a project! So many functions! I feel like this is the first time I actually started to understand how functions and objects relate to each other. I was also pleasantly surprised by how some of the elements turned out, like the perspective of the craters and the twinkliness of the stars. I originally wanted the whole thing to be rotating on the axis, but oh man it did not work.

Eliza Pratt – Looking Outwards 09

“Norman,” a 3D drawing tool made by James Paterson, 2017

This week, my interest was piqued by Dani’s Looking Outwards 08. Her post details the work of James Paterson, an animator and software developer who uses javascript and VR technology to create computational art. For Paterson’s project Norman, as seen in the video above, he uses Javascript to create a tool that allows the user to draw in 3D space.  While learning about this artist, I found Dani’s analysis to be very informative in describing his creative process. Moreover, I agree with her remark that creating software such as this makes an intangible artistic concept more accessible to the public. One of the most beautiful aspects of this project is that Paterson has posted the source code for this drawing tool online so he can share this creative experience with others.

Eliza Pratt – Project 09

sketch

/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Project - 09
*/

var pic;
var dev = 50; //starting deviation for coordinate positon

//array of letters to be drawn
var letter = ["A", "B", "C", "D", "E", "F", "G", "H", "I", 
                "J", "K", "L", "M", "N", "O", "P",  "Q", 
                "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];

//loads image
function preload() {
    var friends = "https://i.imgur.com/7k2A67W.jpg";
    pic = loadImage(friends);
}

function setup() {
    createCanvas(360, 480);
    background(235, 184, 16);
    imageMode(CENTER);
    pic.loadPixels();

}

function draw() {

    //selects a random size
    var r = random(6, 10);

    //selects a random angle 
    var angle = random(360);

    //incrementally increases the deviation of coordinates 
    //after a certain number of frames
    if (frameCount > 600) dev = 100;
    else if (frameCount > 1000) dev = 240;

    //randomly assigns position
    var px = randomGaussian(width / 2, dev);
    var py = randomGaussian(height / 2, dev);

    //contrains random values to the canvas
    var picX = constrain(floor(px), 0, width);
    var picY = constrain(floor(py), 0, height);

    //retrieves color from pixel at random coordinate
    var col = pic.get(picX, picY);


    strokeWeight(2);
    stroke(col);
    noFill();
    textSize(r);

    //retrieves a random index for the letter array
    var i = floor(random(25));

    //draws and rotates letter
    push();
    translate(px, py);
    rotate(radians(angle));
    text(letter[i], 0, 0);
    pop();

}


This project was a lot of fun, and I think really helped me understand more about coding with images! I spent a lot of time experimenting with different ways to project the image – vertical lines, spirals, etc. I decided on letters because I thought it would be cool to have a variety of complex shapes to compose a single image. This is an image of my friend Dani that I took last year.

Rendering:

Eliza Pratt – Looking Outwards 08

Eyeo2012 – Shantell Martin from Eyeo Festival on Vimeo.

Shantell Martin is a world-traveled artist who uses digital drawing as means of performance art. Although based as a graffiti artist in England, Shantell originally gained renown for her performances in underground concerts and clubs in Japan. While she claims that her work as a young artist channeled the frustration and disillusion she felt growing up, her time spent engrossed in Japanese culture led her to achieve a sense of zen as she drew. As she was living in Japan, Martin became heavily involved in the “noise” music scene and was hired to draw live as a complement to the bands’ performances. These drawings would be projected on the walls in a way that matched the energy of the music or choreography during these shows. After accumulating fame in Japan, Shantell moved to Brooklyn where she took on projects outside of a venue environment. By creating digital and traditional drawings on cars, rooms, tables, and anything she could access, Shantell proved that drawing could be made into a spatial performance that was accessible to the public.

While watching Shantell’s lecture in the 2012 Eyeo conference, I admired her drive to push the boundaries of how and what drawing should be. I particularly liked her “doodle volkswagen” project, in which she would draw on her friend’s car on the street and bring smiles to faces all throughout Brooklyn. During her presentation, Shantell combined live, digital drawing with pictures and videos of past work and experiences. By adopting a narrative approach, she details the events in her life that influenced her artistic vision and the choices she made. I admire her style of presenting, as it felt very personal without feeling too structured or rehearsed. If I were to give a lecture on my own creative endeavors, I believe I would like to adapt her style of using personal experiences to amplify the emotional connection to my work.