jknip-Final-Project-SectionA

sketch

/*Jessica Nip
Section A
jknip@andrew.cmu.edu
Project-12
*/

//define global variables------------------------------------------------------
var x;
var y;
var dx;
var dy;
var current_block;
var old_blocks = [];
var blockw = 90;
var blockh = 70;
var clicked = false;
var score = 0;
var gameover = false;
var windowmargin = 10;
var start_speed;
var bground = ["https://i.imgur.com/gZ7wNWJ.png"];
var intro = "STACK THE HIGHEST TOWER.";

//colors
var darkblue;
var lightpink;
var lightred;
var grey;
var grey2;
var grey3;
var grey4;
var canvasw;
var canvash;


//---------------------------------------------------------------------------
function preload() {
    //background skyline
    bground = loadImage(bground[0]);
}


//---------------------------------------------------------------------------
function setup() {
    //define initial canvas settings
    createCanvas(350, 600);
    x = width/2;
    y = 10;
    dx = 1;
    dy = 0;
    frameRate(30);
    canvash = height;
    canvasw = width;
    start_speed = 1;

    //define color RGB
    darkblue = color(44,62,80);
    lightpink = color(252,146,179);
    lightred = color(252,67,73);
    grey = color(225);
    grey2 = color(215,218,219);
    grey3 = color(160);
    grey4 = color(200);

    //call object function
    current_block = new blockFeeder(width/2, 10, blockw,blockh,start_speed);
}


//---------------------------------------------------------------------------
function draw() {
    background(grey2);

    //skyline
    fill(darkblue);
    image(bground, 0, height*(3/5)-25, width, height/3);
    rect(0,height*(8/10), width, height);

    //sun
    fill(lightred);
    ellipse(width*(3/4),200,70,70);

    //gameover screen
    if (gameover){
        fill(darkblue);
        rect(0,0,width,height);
        fill(255);
        textSize(22);
        textStyle(BOLD);
        text("GAME OVER", width/4, height/2-height/30);
        textStyle(NORMAL);
        textSize(14);
        text("Your tower was " + score + "/F.", width/4, height/2);
    } 

    //stacking blocks correctly
    else {
        current_block.draw();
        current_block.update();

        for (var i = 0; i < old_blocks.length; i++) {
            if (score > 3){
                old_blocks[i].y += 2;
            }
            old_blocks[i].draw();
        }

        //gameover if blocks not stacked in same column
        if (score > 0){
            if (old_blocks[score-1].y > height){
                gameover = true;
            }      
        }

        countScore();

        //if block hits bottom of canvas, push block into old blocks array
        if (current_block.hitbottom) {
            old_blocks.push(current_block);
            start_speed += 1;
            current_block = new blockFeeder(width/2, 10, blockw,blockh,start_speed);
        }
    }
}


//create object-------------------------------------------------------------
function blockFeeder(x, y, width, height, speed) {
    this.x = x;
    this.y = y;
    this.dx = speed;
    this.dy = 0;
    this.width = width;
    this.height = height;
    this.isclicked = false;
    this.hitbottom = false;
    this.draw = function() {
    
    //crane (make it not fall with clicked block)
    if (!this.isclicked){
        fill(darkblue);
        noStroke();
        rect(this.x + this.width/2, this.y - windowmargin, this.width/6, this.height/6); 
    }

    //floor
    fill(grey3);
    stroke(grey);
    rect(this.x, this.y, this.width, this.height);

    //block window decor
    fill(grey);
    rect(this.x + windowmargin, this.y + windowmargin*2, this.width/3, this.height/2);
    rect(this.x + windowmargin*5, this.y + windowmargin*2, this.width/3, this.height/2);
    fill(grey4);
    stroke(grey);
    rect(this.x + windowmargin, this.y + windowmargin*2, this.width/3, this.height/3);
    rect(this.x + windowmargin*5, this.y + windowmargin*2, this.width/3, this.height/3);
    }

    //create horizontal crane movement
    this.update = function() {
        this.x += this.dx;
        this.y += this.dy;
        if ((this.x + this.width) > canvasw) {
            this.dx = -this.dx;
            } else if (this.x < 0) {
            this.dx = -this.dx;
        }

        //make new block stack on previous height boundary
        if (score == 0){
            if (this.y + this.height > canvash) {
                this.dy = 0;
                this.hitbottom = true;
                this.y = canvash - this.height;
            }
        }

        //check if new block collides with bottom block accordingly
        else {
            if (this.y + this.height > old_blocks[score-1].y) {
                if (abs(this.x-old_blocks[score-1].x) < blockw/2){
                    this.dy = 0;
                    this.hitbottom = true;
                    this.y = old_blocks[score-1].y - this.height;
                }
                else {
                    this.dy = 0;
                    this.hitbottom = true;
                    this.y = old_blocks[score-1].y - this.height;
                    gameover = true;
                }

            }
        }
    }

    //move block to bottom of canvas when clicked
    this.pressedButton = function(){
        this.isclicked = true;
        if (!this.hitbottom){
            this.dx = 0;
            this.dy = 10;
        }
    }

}


//---------------------------------------------------------------------------
function countScore(){
    //define type settings
    strokeWeight(1);
    fill(255);
    noStroke();
    textSize(20);
    textStyle(NORMAL);
    text(score + "/F", width - 45, height - 20);
    textSize(13);
    textStyle(BOLD);
    text(intro, windowmargin*2, height-20);

    //when block stacks, add score
    if (current_block.hitbottom) {
        score += 1;
    }

}


//---------------------------------------------------------------------------
function mousePressed() {
    //follow block rules when mouse is pressed
    current_block.pressedButton();
    //remove intro when mouse pressed
    intro = " ";
}


Instructions
Stack the highest tower by aligning blocks with at least 50% accuracy! The horizontal and vertical speed increases will make the level harder over time. Your tower height will also be recorded.

Description
Inspired by classic tower stack mobile games, I wanted to create an alternative version of it using a simple horizontal “crane”, with pressure given to the player from its increased speed over time. As the player begins to stack a higher tower, original blocks also begin to slide downwards, creating more time pressure for players. I also wanted to explore creating minimalistic graphics for a challenging, interactive game.

jknip-SectionA-LookingOutwards-12

The two projects I identified are David Yen’s “Fantastic Elastic” and Sasj’s “Geometric Animations”.

Fantastic Elastic Video

Yen’s Fantastic Elastic (2017)

Yen’s work features a combination of processing, PBox2D, and Geomerative, where he creates a program that draws fritzy letters that react to user key input. The letters he creates also dance to the rhythm of the music. I really enjoy the fun nature of his work and would love to incorporate forms of user input in my own project. An interesting opportunity would be for them to play with color and orientation of letters more, which would have made for a more dynamic interaction.

Geometric Animation

Sasj’s Geometric Animation (2017)

Sasj is a dutch interaction visual designer that posts geometric animations daily. She uses processing and enjoys working with geometric forms — multiplying, dividing and colliding them. The animations she creates run on their own pace with no user input.

The differences between her work and Yen’s are the control over user input, along with the type of sensory experience you would expect to have — Sasj’s may be more visual, whereas Yen’s may be both visual and auditory. This may be an opportunity Sasj could have investigated in — incorporating input or sound into her work to make it more dynamic.

http://halfconscious.com/interactive
http://sasj.tumblr.com/

jknip-Project-12-Proposal

Updated Project Proposal

For my final project, I am carrying out an individual project of a simple game inspired by the app, Tower Stack. Instead of a swaying crane, my game will utilize horizontal movement with varying speeds for my refreshing/’feeding’ building block. Players can use mouse click to release the building block, stacking them as tall as possible. The stacked tower also moves down and out of the canvas by the second, creating some time pressure on the player to stack blocks efficiently.

Sketches of Game

Project Proposal
For our final project, we were inspired by simple graphical illustrations of everyday moments – specifically in food handling activities. We want to create clickable interactions that prompt user input. For example, a scene may be pancake making, and the user would have to consider an image of its ‘ideal state’ in the top left corner while considering the timer on the screen, in determining when is the best time to flip the pancake. These interactions hope to create simple, satisfying moments for users when they are able to achieve its ideal scenario. These interactions will also mostly surround kitchen activities from pouring the perfect amount of coffee, baking a cake, etc.

Proposed Collaborator
Alvin Luk (akluk)

Sketches & Inspiration

Inspiration

jknip-Project-11-Composition

sketch

/*Jessica Nip
Section A
jknip@andrew.cmu.edu
Project-11
*/
var t6;
var start;
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;
}

//--------------turtle API above-------

//design simple pattern
function pattern(t6) {
    t6.forward(60);
    t6.left(90);
    t6.forward(40);
    t6.left(90);
    t6.forward(30);
    t6.left(90);
    t6.forward(40);
    t6.left(90);
    t6.forward(20);
    t6.right(90);
    t6.forward(20)
    t6.right(90);
    t6.forward(30);
    t6.right(90);
    t6.forward(40);
    t6.right(90);
    t6.forward(50);
    t6.right(90);
    t6.forward(50);
    t6.left(90);
}


function setup() {
    createCanvas(300,300);
    background(0);
    //define given parameters
    strokeJoin(MITER);
    strokeCap(PROJECT);
    //set row one position
    start = 30;
    t6 = makeTurtle(0,start);
    //determine initial color and weight
    t6.setColor(0);
    t6.setWeight(1); 
}

function draw() {
    //maximize width and height across canvas
    while(t6.y < height){
        while(t6.x < width) { 
            pattern(t6);
        }
        //redefine starting position for other rows
        t6.penUp();
        start = start + 100;
        t6.goto(0,start);
        t6.penDown();
    }
}

//when mouse is pressed, rndomize color and thickness
function mousePressed(){
    t6.x = mouseX;
    start = mouseY;
    t6.y = mouseY;
    t6.setColor(color(200, random(0,100),random(0,100)));
    t6.setWeight(random(1,3));
}

Here are some possible abstract gradient compositions that can be created with my sketch. I wanted to utilize a simple pattern created in black and white below, and transform that into warm hues represented by varying thicknesses of the repetition.

jknip-SectionA-LookingOutwards-11

Atlas app’s visual style

Atlås by Agoston Nagy (2017)

Atlås is an “anti game [app] environment” where music is generated via a conversational cognitive space — users answer questions surrounding presence, human cognition and imagination, while also playing simple game mechanics that create sound. I really admire the visual aesthetic of this app, and the minimal interactions it has with the users — making users feel like music generation is a simple task for anyone. The app is developed using open source tools, specifically using p5js/javascript. The artist aims to use the experience to investigate the autonomy of algorithms and machine learning. Nagy was able to showcase his artistic sensibilities through interactivity and machine learning — he started developing this as part of his PhD thesis, and was especially interested in combining sound, visual, and literary analogies sensitively and in a visually pleasing manner.

http://www.creativeapplications.net/processing/atlas-guided-generative-and-conversational-music-experience-for-ios/

http://www.binaura.net/atlas/

jknip-Project-10-Landscape

sketch

/*Jessica Nip
Section A
jknip@andrew.cmu.edu
Project-10
*/

var buildings = [];
var bgroundpic = ["http://i.imgur.com/CSDbcLh.jpg"];
var peopleLinks = [
    "https://i.imgur.com/skan1Dj.png",
    "https://i.imgur.com/0U2pZMm.png",
    "https://i.imgur.com/ImJcxpz.png",
    "https://i.imgur.com/Rn3TxL7.png",
    "https://i.imgur.com/Ei7SzTG.png",
    "https://i.imgur.com/GTNpulP.png",
    "https://i.imgur.com/nn3qkQ7.png",
    "https://i.imgur.com/ue5JB8v.png",
    "https://i.imgur.com/mCbm0jb.png",
    "https://i.imgur.com/ZumluD7.png",
    "https://i.imgur.com/LuoUZNc.png",
    "https://i.imgur.com/Jv4Nw6g.png"];

var peoplepics = [];

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

function preload() {
    bground = loadImage(bgroundpic[0]);
    //preload photos from links
    for (i=0; i<peopleLinks.length; i++) {
        peoplepics.push(loadImage(peopleLinks[i]));
    }
}

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

function setup() {
    createCanvas(400, 400); 
    //randomize people order
    // create an initial collection of buildings
    for (var i = 0; i < 10; i++){
        var rx = random(width);
        buildings[i] = makeBuilding(rx);
    }
    frameRate(10);
}

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

function draw() {
    background(0); 

    image(bground,0, 0, width,height-height/7);

    updateAndDisplayBuildings();
    removeBuildingsThatHaveSlippedOutOfView();
    addNewBuildingsWithSomeRandomProbability(); 

    //draw escalator platform
    fill(color(243,245,241));
    noStroke();
    rect(50,370,300,10);

    //draw railings
    strokeWeight(6);
    stroke(color(112,168,166));
    noFill();
    rect(30, 326, 340, 55, 40, 365, 30, 355);
    noStroke();

}

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

function updateAndDisplayBuildings(){
    // Update the building's positions, and display them.
    for (var i = 0; i < buildings.length; i++){
        buildings[i].move();
        buildings[i].display();
    }
}

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

function removeBuildingsThatHaveSlippedOutOfView(){
    var buildingsToKeep = [];
    for (var i = 0; i < buildings.length; i++){
        if (buildings[i].x + buildings[i].breadth > 0) {
            buildingsToKeep.push(buildings[i]);
        }
    }
    buildings = buildingsToKeep; // remember the surviving buildings
}

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

function addNewBuildingsWithSomeRandomProbability() {
    // With a very tiny probability, add a new building to the end.
    var newBuildingLikelihood = 0.007; 
    if (random(0,1) < newBuildingLikelihood) {
        buildings.push(makeBuilding(width));
    }
}

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

// method to update position of building every frame
function buildingMove() {
    this.x += this.speed;
}
    

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

// draw the building and some windows
function buildingDisplay() {
    var floorHeight = 20;
    var bHeight = this.nFloors * floorHeight; 
    fill(255); 
    stroke(0); 
    push();
    translate(this.x, height - 40);
    image(peoplepics[this.type],0, -bHeight+24, this.breadth,bHeight);
    pop();
}

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

//define type as random to randomize people in flow
function makeBuilding(birthLocationX) {
    var bldg = {x: birthLocationX,
                breadth: 90,
                speed: -3.0,
                nFloors: 8,
                type: floor(random(12)),
                move: buildingMove,
                display: buildingDisplay}
    return bldg;
}

For this project, I wanted to recreate the scene of a moving sidewalk and passengers at an airport — through the use of a simple background, a silhouette of the sidewalk and found images of people. This was one of the first inspirations I had from seeing the reference material of the slow-paced horizontal movement. I went with a simple color palette with cooler hues to create consistency between the black, shades of blue in contrast with the color variety of people. I thought the most difficult part of implementation was shuffling the images randomly and getting them to display correctly in sync with motion.

jknip-SectionA-LookingOutwards-10

Yael Braha’s Project Mapping

Yael Braha is a creative director working at Obscura Digital, who has a lot of experience designing projection mapping shows for large scaled buildings and facades. One of the projects I really enjoyed was the show for AHA, a multi-day festival of lights celebrating Cleveland. Her team at Obscura tends to approach imagery through a very hands-on approach, which I admire, as they brainstorm, create and record slow-mo footage from big to small. The project transformed a 370 foot by 70 foot tall building into an animated canvas, and created high engagement with the community who gather to enjoy the facades. Yael Braha has a degree in Graphic Design and a masters in Fine Arts in Cinema.

Transformations, 2014, Yael Braha

Video from Obscura Digital

http://www.yaelbraha.com/

http://obscuradigital.com/work/aha-cleveland/

jknip-Project-09-portrait

sketch

/*Jessica Nip
Section A
jknip@andrew.cmu.edu
Project-09
*/


var img;

//--------------------------
function preload() {
    //preload grandma's image
    img = loadImage("https://i.imgur.com/G6dnwgf.jpg");

}
 //-------------------------
function setup() {
    createCanvas(342,480);
    img.loadPixels();
    frameRate(200); //set fast frame rate
}
 
 //-------------------------
function draw() {
    //define X and Y pixels of image, randomize appearance position
    var Xpixel = constrain(floor(random(width)), 0, width-1);
    var Ypixel = constrain(floor(random(height)), 0, height-1);
    //image color = grab pixels from image
    var imgcolor = img.get(Xpixel, Ypixel);
    var randomSize = random(5,15);

    //set ellipse color to image pixel color
    fill(imgcolor);
    noStroke(); //remove border
    //set ellipse X and Y to randomized pixel positions
    ellipse(Xpixel, Ypixel, randomSize, randomSize); 
}



For this project, I wanted to create a fun randomized ellipse-based filter generated based on a photo of my grandmother. Below you will find some screenshots at different points of the rendering process. As the colors in the original image were fairly limited and grouped in simple forms, I wanted to use randomized ellipses to suggest those specific colors across the canvas from the beginning — the overall image also becomes more apparent early on due to the high visibility of these core forms.

jknip-SectionA-LookingOutwards-09

Ryoji Ikeda’s piece at Park Avenue Armory

Ryoji Ikeda’s “The Transfinite” (2011)

I chose to read into Monica’s post on Ryoji Ikeda’s “The Transfinite” installation. I agree with her comments on how the piece is definitely a piece for all ages, as it’s hard not to enjoy the strong visual and auditory sensations effects. Ikeda is able to manipulate scientific data, taking the continuous streams of 0s and 1s to create abstract visuals along with synchronized beats. What’s interesting beyond her analysis is how the artist also leverages 9 small screens mounted around the large installation to allow for free-play by visitors with endless scrolling data. I think this is able to create more context for the viewer and truly allow data to consume them as the artist and space suggests.

http://www.ryojiikeda.com/project/thetransfinite/

http://www.nytimes.com/2011/05/27/arts/design/ryoji-ikeda-the-transfinite.html

https://www.fastcodesign.com/1663965/art-installation-big-as-a-warehouse-turns-data-into-a-trippy-other-world-video

jknip-SectionA-LookingOutwards-08

Could you be a medalist? Animation Design by Santos.

Mariana Santos

Mariana Santos is currently the CEO of Unicorn Interactive, an independent media startup working on digital storytelling. She graduated from the University of Lisbon with a bachelors in communication and industrial design. Then completed a masters in digital media while working at Hyper Island. Santos describes herself as a visual storyteller, and began her career as a motion animator and post-production editor at Universal Music Berlin.

Santos creates a wide range of work from interactive, animation, film, design, to books. I admire the interactive work she creates, as they tend to follow a similar personal style that’s very straight-forward and colorful. Her style works well specifically with maps and guides. The project I admire the most is the piece ‘Could you be a medallist’, as she took on a retro/gameboy aesthetic that made a super user-friendly piece that was fun and engaging.

Through her portfolio, she presents her work effectively by having automated slideshows with high fidelity visuals at each clickable album. Visuals are also followed with a paragraph description which is consistent throughout. The page is also adaptive, which is something I could implement for my own presentation.

http://marysaints.com/
http://marysaints.com/Could-you-be-a-medallist
https://www.youtube.com/watch?v=U8jcbl4erq