Week 4 – Reading Reflection

Reading the first page of chapter one, I almost thought I was doing a reading on wayfinding–essentially the study of how we navigate our environment. Afterall, the push-pull dilemma of a door is pretty much universal regardless of what background and culture you come from. However, this chapter would continue to prove much more broad and discuss real world UX beyond putting handles on one-way push doors.

Norman comes from a background in engineering, so naturally interacting with machinery is something he has a vast perspective on. Let’s talk about where Norman says “When people fail to follow these bizarre, secret rules, and the machine does the wrong thing, its operators are blamed for not understanding the machine, for not following its rigid specifications.” In Crawford’s reading last week, he compared interaction to having a conversation, which I agree with for the most part. However, I do find it interesting that when a machine fails on us we understand the burden of successful “communication” is undoubtedly on us. This takes me away from the conversation analogy as there is always realistically no one solely at fault for a misunderstanding between two humans.

One of my favorite points of the reading is that we should strive for human-centered design(HCD). As Norman says, “Good design starts with an understanding of psychology and technology.” Realistically, how can there be design without a greater understanding of human cognition? For example, we all know what an arrow has a side it’s pointing at– the way its edges align to a sharp point naturally makes our brain look at the sharp point and what follows it.

That transitions nicely to how this applies to us interactive media majors. When it comes to applying Norman’s principles of design to interactive media, I believe we need to not only invite both like-minded and nonlike-minded friends to test our projects, but consider all their perspectives equally. As Norman says, “Engineers are trained to think logically. As a result, they come to believe that all people must think this way, and they design their machines accordingly.” We ideally should engage those who aren’t also “engineers.”

As for something that drives me crazy and how it could be improved, I really want to rework certain parts of highline pathing. There are certain areas especially near the staircases down to the ground floor that have such poor pathing. You would need to either walk over the grass or detour by a good 5 meters just to follow the intended path rather than your desired path. This semester they even added a bush on the grass area to block you from cutting through the grass– talk about remedial design…

Week 3: PING (Objects & Arrays)

(up to two players! WASD for top side and IJKL/arrow keys for bottom side)

I thought about how I wanted to build upon what I had last week and I arrived at the idea of using something to interact with the bouncing ball mechanic. At first, I thought about making an air hockey game where you could drag the paddle but I didn’t know how to create an opponent that could respond to what you do. And it couldn’t be multiplayer since there’s only one mouse, which led me to using keyboard keys to control the paddles.

I began to build two separate objects that can be controlled by wasd and arrow keys respectively– a lot like the old web games I would secretly play in my computer science class with my classmates back in elementary school.

Using Classes and this.

Last week when I presented my project to professor Aya, she suggested that I learn how to use class so I could make it easier on myself to organize my code and objects. So this week I delved into classes and have a pretty good grasp on it now. Here are two classes I made– the ball and the top paddle.

class ball { //class creates a re usable template: let ball1 = new ball(x,y,r)
  constructor(xPos, yPos, radius){ //creates the initial state
    //this referes to the object currently being created
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
    
    this.ballXspeed = ballXspeed;
    this.ballYspeed = ballYspeed;
    this.ballMoving = false; //boolean to help reset ball
    
  }
  move() { //this is a method, a function that belongs to just one object
    if (!this.ballMoving) return; //if ball is still then do nothing
    
    this.xPos += constrain(ball1.ballXspeed, -maxSpeed, maxSpeed)
    this.yPos += constrain(ball1.ballYspeed, -maxSpeed, maxSpeed)
    
    //BOUNCE: CHECKS LEFT AND RIGHT EDGE
    if (this.xPos > width - this.radius || this.xPos < 0 + this.radius) { 
      this.ballXspeed *= -1;
    }  
  }
  
  reset(){
    this.xPos = width/2;
    this.yPos = height/2;
    this.ballMoving = false;
    
    //setTimeout(function, delay) delay is in milliseconds
    setTimeout(() => { //the arrow =>
      this.ballXspeed = random([-ballXspeed, ballXspeed]);
      this.ballYspeed = random([-ballYspeed, ballYspeed]);
      this.ballMoving = true;
    }, 2000);
  }
  
  scoreDetection(){
    //CHECKS TOP AND BOTTOM EDGES
    if (this.yPos > height - this.radius) {
      adjustScore(1,0); //top side scores 1
      this.reset();
    }
    if (this.yPos < 0 + this.radius) {
      adjustScore(0,1); //bottom side scores 1
      this.reset();
    }
  }//closes score detection
  
  display(){
    ellipse(this.xPos, this.yPos, this.radius *2);
  }
} //ends class ball
class topPaddle {
  constructor (xPos, yPos, paddleWidth, paddleHeight, xSpeed, ySpeed){
    this.xPos = xPos;
    this.yPos = yPos;
    this.baseY = yPos; //initial yPos 
    this.paddleWidth = paddleWidth;
    this.paddleHeight = paddleHeight;
    this.xSpeed = xSpeed;
    this.ySpeed = ySpeed;
  }
  
  display(){
    fill(255)
    rect(this.xPos,this.yPos,this.paddleWidth,this.paddleHeight);
  }
  
  move(){
    /* Keycodes
    W = 87
    A = 65
    S = 83
    D = 68
    */
    if (keyIsDown(87)){ //TOP
      this.yPos += this.ySpeed * -1; //negative because 0 counts down
    }
    if (keyIsDown(65)){ //LEFT
      this.xPos += this.xSpeed * -1;
    }
    if (keyIsDown(83)){ //BOTTOM
      this.yPos += this.ySpeed ;
    }
    if (keyIsDown(68)){ 
      this.xPos += this.xSpeed;
    }

    //RESTRICTIONS 
    this.xPos = constrain(this.xPos, xBoundary, width-xBoundary)
    this.yPos = constrain(this.yPos, this.baseY-yBoundary, this.baseY+yBoundary)
    
  } //closes move()
}

I really enjoyed using methods to help organize my code and operate on an object-oriented basis. 

 

Not too far into writing the classes for the paddles, I realized I was recreating the game pong. This is literally how pong was made– someone wanted to test bouncy ball physics and moving paddle collision and made pong.

 

Implementing Arrays

I already experimented with arrays last week when dealing with for() loops so this week I wanted to use them in a different way: to track scores for each side. I made two arrays– one called topCounter and one called bottomCounter. If the top side won round 1, they would have 1 added to their array and have it console.log’d into the console.

 

Designing with Variables

Since we learned push() and pop() in class last week, I’ve been wanting to use these techniques to make more organized stroke() and strokeWeight() functions. 

 

Beyond that, I used a lot of variables to help with the numbers so changing the variable number in the top of the code would change all of the related values throughout the code conveniently and often symmetrically. For instance, I would get the midpoints between the two ends of the lines to have the score number displayed there.

//LEFT CENTER LINE
    line(
      0,height/2, 
      0+sideLineMargin,height/2
    )
    //CENTER LINE
    line(
      (width/2)-centerLineMargin,height/2, 
      (width/2)+centerLineMargin,height/2
    )

//lots of code inbetween

// TOP SIDE SCORE
    text(topScore, 
        ((width/2)-centerLineMargin + 0+sideLineMargin)/2,
        height/2
        )

I also found the rectMode() and textAllign() functions to be incredibly helpful.

 

Adjust Gameplay Parameters

Initially, the back and forth between the two players felt very predictable and un-engaging. It was slow and ran at a consistent speed, which also meant there was only so many things you could do to change the trajectory of the bounce.

 

So I did two things, I made the paddles have way more vertical movement than it did initially, and I added a speed multiplier that really shaked the game at its core. 

 

Every time a player would collide their paddle with the ball now, the ball would speed up by 4%, which is seemingly small, but builds up very quickly to overwhelm players.

//BALL ATTRIBUTE
let ballXspeed = 6;
let ballYspeed = 5;
let speedUpFactor = 1.04; //105% each time it collides with paddle
let maxSpeed = 14; //limits the speed of the ball

//lots of code inbetween

if (ballCollidePaddle(ball1,topPaddle1,"Bottom")){
    ball1.ballYspeed *= -1;
    ball1.ballXspeed *= speedUpFactor;
    ball1.ballYspeed *= speedUpFactor;
}

However, it would get to a point where p5js wouldn’t really render it at a high enough fps for it to be fair to the players, so I added a max speed cap of 14-ish into the move() method for the ball to make sure it would be fast but not too the point of absurdity.

 

Difficulties Endured

 

Thankfully p5js didn’t crash half a dozen times during the development like it did last week, but I had some technical struggles.

 

When I built the second paddle object in the bottom, I completely forgot to constrain the y-value of the paddle which created quite a humorous moment when my girlfriend wanted to test the paddle movement with me.

 

The math behind colliding a circle with a rectangle was pretty confusing to figure out, but I also didn’t want to use circles as paddles so I tried a lot of methods until I made it work by checking the x-edges overlapping.

let xOverlap = 
    (ball.xPos + ball.radius > paddle.xPos - paddle.paddleWidth/2) &&
    (ball.xPos - ball.radius < paddle.xPos + paddle.paddleWidth/2);
  
  if (!xOverlap) return false; //checks if ball collided with paddle early

When I tried to embed it onto wordpress, the arrow keys kept trying to scroll the embed for me so I had to add another set of controls on IJKL.

Gameplay Strategy & Technique

In testing my friends and I found a few strategies and techniques that help with winning rounds. One of the strategies is to back up as the ball approaches max speed; this really helps by giving you more time to react and save the ball. 

 

Another technique we accidentally found out was double-tapping the ball to have it gain the speed multiplier several times on the same receive.

 

My friends and I had jolly fun playing against each other even if they thought the game was incredibly difficult.

 

Conclusion

I had a lot of fun making this project and learning how to use more tools in JavaScript. Making classes felt like an essential part of JS coding that I finally understood today. I can really feel my progress growing every week with every assignment.

 

I really hope I can repurpose the work I did in this project sometime in the future or even just play it with my friends whenever I open my p5js account.

Week 3 – Reading Reflection

I was very surprised by the opening sentence of this week’s reading as I had an Understanding IM class with Professor Shiloh just this Thursday discussing how the word “interactivity” loses so much meaning when applied to works that are at most immersive and not at all actually interactive.

“Here’s a key point about the interactive process: There are two actors, not one” was a quote from page 5 that I noted down. Some of my fellow classmates in UIM defended the popular claim that the Mona Lisa is interactive because her eyes “follow you” as you admire the artwork; they defended it because they themselves feel the magic of their favorite paintings. However, I think interactivity as a term often gets confused with “immersion” yet seems to almost be used interchangeably for so many people.

Another thing I noted down from the reading was “We tend to think of interactivity as a Boolean like virginity. But why not think of interactivity as a continuous variable with relative measures?” Although the phrasing of this comparison was a little bizarre on my first read, I actually found myself agreeing with it a lot. Crawford’s three emphasis on three characteristics of Listening, Thinking, and Speaking may naturally apply to human conversation more, but could apply to our artworks as well.

I really liked this next section on the thirteenth page– where Crawford essentially provokes the reader on the topic of books as an interactive medium. Crawford says that if you think books should be considered an interactive medium then say the word, although he’s possibly thousands of miles away and unable to ever perceive your opinion, oops! “…if you’re frustrated, you are welcome to throw this across the room, but even then, there still won’t be anybody listening to your frustrations or thinking about them.”

Overall, I thought Crawford had some good points with great ways of expressing how frustrating the nothingness burger the word “interactivity” has become and will become. And to answer his question listed at the end– “Are rugs interactive? Explain in your own words why or why not?” – I believe that rugs fall near low-interactivity at best on the interactivity spectrum. This is because some party games, such as twister, could use a rug with complex designs to form a set of rules and a gameplay loop.

In response to “What do you consider to be the characteristics of a strongly interactive system? What ideas do you have for improving the degree of user interaction in your p5 sketches?”, I think the strongest characteristic of an interactive system is a feedback loop that rewards curiosity and engagement. As for ideas for improving the degree of user interaction in my sketches, I believe variability is vitally important to the repeatability of an experience. 10 people could interact with the same interactive sketch and each of them would experience something noticeably different.

Week 2: Corner Contact (Production)

 

(You can wait until it hits the corner naturally or hold Mouse1 to Speed it Up)

Before what I have here, this project started with me really curious to experiment with 3D objects, but the WEBGL system got terribly confusing with all sorts of new functions and ways I had to approach drawing shapes. I gave up on that and decided to first focus on 2D for this assignment.

I had a real tough time coming up with an idea after that. I thought about it over the weekend and I landed on the idea that I wanted whatever I made to feel satisfying, so I started thinking of things that are visually satisfying. This reminded me of a YouTube short I recently saw about how the DVD screensaver can ever only touch two opposite corners and NEVER the corner adjacent to them. This fact really lived in my head rent-free for a bit but it also made me wonder if I could create simple physics in p5js to recreate a DVD screensaver with the little JavaScript that I understood.

I started with just a ball and a simple if statement that detected whether the x position of the ball was greater than the width minus the radius, essentially allowing me to cause things to happen when the borders of the ball touched the edge. Once I had both the X and Y movements done, I needed to check for corner contacts.

function edgeBounce(i) {
  if (xPos[i] > width - radius[i] || xPos[i] < radius[i]) {
    xSpeed[i] *= -1;
  }
  if (yPos[i] > height - radius[i] || yPos[i] < radius[i]) {
    ySpeed[i] *= -1;
  }
}

Also, I know these are two dimensional circles but I will continue to refer to them as balls.

The time it would take for the ball to hit one of the corners took a really long time so I wanted to add the ability to speed up the ball animation! At first I tried to use the while() to detect when mouseIsPressed but after a lot of confusion I realized it had to be and if() function instead. However, I learned two important things today: the first was that while-else() was not a thing like if-else() is, and how to return variables from a function. It was such a natural way of learning through trial and error and it felt quite satisfying.

I eventually figured out how to do it by assigning a function, speedUp(), to return a value straight into the multiplier variable.

//somewhere in draw()
 for (let i = 0; i < xPos.length; i++) {
    // move ball
    multiplier = speedUp(i);

//..lots of code inbetween

function speedUp(i){
  if (mouseIsPressed){
    return timeMultiplier;
  } else{
    return 1;
  }
}

While I was here, I felt like the background looked a little bland at first so I decided to have a faint text in the background that would say the current speed multiplier. I made sure to have it drawn first so it’s always layered underneath the circles.

//MULTIPLIER TEXT 
textSize(400);
textAlign(CENTER,CENTER);
noStroke();
fill(multiplierColor);
text(speedUp() + "x", width/2, height/2);

And of course the main highlight of this assignment was to use loops. I was actually quite proud of how quickly I got the hang of the for loops and using arrays to take advantage of each loop.

for (let i = 0; i < xPos.length; i++) {
  // move ball
  multiplier = speedUp(i);

  
  xPos[i] += xSpeed[i] * multiplier;
  yPos[i] += ySpeed[i] * multiplier;

  edgeBounce(i); //checks for edge touch
  cornerBounce(i) //checks for corner touch, creates a new ball if successful

  // draw ball
  let c = ballColors[i];

  fill(c[0], c[1], c[2]); //RGB values of c
  stroke(c[0]-20, c[1]-20, c[2]-20); //-20 shifts it a little darker
  strokeWeight(8);
  ellipse(xPos[i], yPos[i], radius[i] * 2);
}//end of for loop
Difficulties Endured

A lot of tutorials I followed would introduce things I was not familiar with at all so I did workarounds that were probably a lot less efficient.

But most importantly, I crashed so many times and had to redo so much of my work so many times.

I originally wanted to have the new balls come out from the corner that the “motherball” contacted but when I tested my code it ended up spawning an infinite number of balls and caused my tab to completely crash and required me to redo almost 20 minutes of work.

I remember I had to write and rewrite the cornerBounce() function twice and it was really frustrating especially because of how long the if() statement was.

function cornerBounce(i){
    if ((xPos[i] <= radius[i] || xPos[i] >= width - radius[i]) &&
    (yPos[i] <= radius[i] || yPos[i] >= height - radius[i])) {
      console.log("Corner Contact Confirmed")
      if(ballCount < maxBallCount){ 
        console.log("Ball #" + xPos.length + " was Created")
        xPos.push(width/2); //PUSH adds to an array
        yPos.push(height/2); //if spawn in the corner it creates infinite balls
        xSpeed.push(random(-8, 8));
        ySpeed.push(random(-8, 8));
        
        //assigns a random color
        let newColor = random(colorOptions); 
        ballColors.push(newColor);
        
        radius.push(50);
        ballCount += 1;
      } else if (ballCount == maxBallCount){
        console.log("Max Ball Count Reached") 
      }//ends the ballcount if()
        
    }//ends the if()
}
Conclusion

Even thought my web editor crashed half a dozen times and disheartened me throughout the process, the trial and error felt like a satisfying loop of learning that will certainly help me navigate JavaScript a little more easily with each passing week.

Week 2 – Reading Reflection

Many of the featured patterns and algorithms Casey Reas made are very elaborate and very satisfying to see the construction of. Some of them looked like something you might find in the default wallpaper collection you get from purchasing a new touchscreen device. From my perspective, a lot of these pieces could be implemented as a compliment to another primary work to elevate it. For instance with the colorful cancer cell visualization in the video– if I was a cancer cell researcher and I needed to present my research in a presentation I could use visualizations of my data as a design motif throughout my presentation template.

Halfway through the video he talks about chance in art and I was very surprised to see it appear as early as 1916. I think the most notable part of this section is Duchamp’s woodwork involving randomly dropping a piece of string to determine the line of hit cuts and ultimately the shape of the wooden planks.

I find it incredibly fascinating that before the random number game was an accessible computer-generated concept, it was first printed onto paper as a collection of deviatives. The fact that there was a whole book for random strands of numbers really changed my perspective on random numbers. Before watching this video, random numbers were entirely synonymous with random number generation(RNG) through computing. I think this is largely due to my exposure to RNG in video games, which can take many forms in video games from determining the chance of landing a critical hit on an enemy in an RPG to opening a fancy cosmetic in a live service first-person shooter.

Speaking of video games, I thought the featured example using “Fractal Invaders” was really cool and kinda shows how symmetry can turn nonsense into something that you would think had a deeper purpose. It looked like a really interesting idea with the mirroring so it made me wonder what results I could achieve if I did a similar coin toss black/white color decider for a 4×4 grid and mirrored it both vertically and horizontally. I imagine this would probably come up with some really interesting pixel art that could even inspire a more intricate hand drawn illustration based on that pattern.

Overall, I was really impressed with how people would obtain random numbers without computing them– from Duchamp dropping string to decide the line of his cuts to using a flipping through a page filled with random numbers. I think my perspective on chance operations has greatly broadened.

Week 1: Made this While I was Hungry (Self-Portrait)

(Try Clicking on the Mouth when it’s Open!)

I had a few ideas of how I wanted to depict myself, none of which included a real depiction of my face, but more or less characters that I resonated with. I quickly scrapped that idea when I felt like it wouldn’t really be challenging me if I drew a depiction of an already existing illustration.

With my limited coding experience it would be certainly difficult to go from concept into actualization using just my keyboard and the funny colored words on screen, but I was committed to making something worth looking at.

One of the first things I tried to understand coming from a long photoshop/graphic design background was how layers would work on p5.js. Understanding this early gave me a lot of confidence that I wasn’t going to make something uncanny-looking. I made each body segment its own function and called it in the order from the lowest layer to the highest layer in draw()

function draw() { //draw runs on loop 60/sec
  background(110,40,80);//change later?
  
  //Draws Body Parts in Layers
  drawHair();
  drawTorso(90);
  drawHead();
  drawLeftEye(6.7);//parameter is for gap between lines
  drawRightEye(6.7)
  drawMouth();
  drawHands();
  drawBangs();
}

As I learned more about p5.js through tutorials, I wrote down lots of notes and reminders to myself. One tip that really helped me out initially was putting fill() before the shape I wanted to draw. When I was listening to the demonstration in class I thought it would make more sense for fill() to have parameters for what you wanted to fill, but after working with the shapes today I realized that would’ve caused a big confusing wall of text very quickly. Putting notes next to how many parameters and what each parameter did for each function was also really helpful in my learning process.

I wasn’t quite sure how to depict the face at first with just simple geometry but by removing the outline “strokes” and blending shapes I started sculpting some much nicer shapes.

I really wanted my avatar’s arms to be interactable with the user’s mouse values so I initially allowed the top Y-positions of the arm segments to be controlled using the mouse. I obviously didn’t want it to go out of bounds so I looked through the p5js reference until I found the constrain() function. This was a huge lifesaver for both this aspect of the self-portrait and some other aspects I worked on after this.

let armY = constrain(mouseY, 430, 500); //restricted value, min, max
  let armX = constrain(mouseX, 200, 350); 
  
  //LEFT
  quad( 
    armX-60, armY, //top left 220~
    armX-10, armY+20, //top right 280~
    220, 600, //bottom right
    100, 600  //bottom left
  );
  //RIGHT ARM
  quad( 
    armX+110, armY, //top left 380~
    armX+60, armY+20, //top right 320~
    width-220, 600, //bottom right
    width-100, 600  //bottom left
  );

This snippet was taken as I was working out the arm animation and tracking. Mini-me was very deprived of any type of hair back then. He was also very gray.

Fig 1. Snapshot Right After Figuring Out Arm Animations

I feel like the hand movements made the avatar feel so much more alive and responsive, making good use of p5.js in ways beyond just turning code into still images. This would go a step beyond when I added the cookie into mini-me’s hands then another step beyond when the mouth would respond to having a cookie in front of it.

//COOKIE
fill(210, 180, 140);
stroke(190, 160, 120);
cookieX = armX+25
//main cookie area
if (cookieEaten) {
  arc(cookieX,armY,150,75,5.7,3.5) //cookie missing the top corner
  console.log("Cookie was Eaten")
} else {
  arc(cookieX,armY,150,75,0,2*PI) //a full cookie
}
//chocolate chips
fill(90, 60, 40);
noStroke();
//top left to bottom right
ellipse(cookieX-50,armY-10,19,14)
ellipse(cookieX-21,armY-2,16,10)
ellipse(cookieX-37,armY+10,12,7)
ellipse(cookieX+3,armY+8,17,12)
ellipse(cookieX+22,armY-6,12,8)
ellipse(cookieX+29,armY+20,15,10)
ellipse(cookieX+38,armY+2,18,13)

At first I didn’t have any chocolate chips on the cookie and my friend thought it was holding an empty plate so I decided to add some chocolate chips even though the way I did it was probably not very efficient. I considered using random variables like I’ve seen some previous projects utilize for their backgrounds but the choco chips needed to avoid a very specific area of the cookie that would be “bitten” into while looking well balanced.

One of my goals with the cookie in hand was to let the user be able to eat it by clicking on the mouth of mini-me, but I didn’t know how to program a bite mark into the ellipse so I decided to change it into an arc() halfway through and use the arc’s unique properties to cut out a portion of it near the mouth, making it appear like it had been bitten into. I was pretty proud of how I worked with my limited knowledge here.

cookieEaten = false
function mouseClicked() {
    console.log(mouseX,mouseY)
    if (mouseX > 280 && mouseX < 320 && mouseY > 330 && mouseY < 400){
      cookieEaten = true; 
      console.log("clicked mouth");
     }  
  }

//lots of stuff here in between in the real code...

if (cookieEaten) {
    arc(cookieX,armY,150,75,5.7,3.5) //cookie missing the top corner
    console.log("Cookie was Eaten")
  } else {
    arc(cookieX,armY,150,75,0,2*PI) //a full cookie
  }

By far the most unsatisfying part to me was definitely the way I did my hair. There were just so little polygons to work with to properly express what type of hairstyle I wanted for mini-me. However, a lot of my friends said they actually really liked how I depicted the hair so perhaps I’m fixating on it too much.

My biggest regret was that I only learned after I was nearly done with my self-portrait that I could’ve changed the angleMode() to degrees the whole time… I spent so much time trying to remember middle school math just to work out the PI angles for certain arcs.

//the upper lip
arc(cenX - 210/4, faceCenY, 150, 150, PI/4, PI/2); //left side
arc(cenX + 210/4, faceCenY, 150, 150, PI/2, 3*PI/4);//right side

If I were to do this exercise again, I would probably create more variables to make certain parameters look a little more organized and efficient. I changed a few parts to stuff like “width-X” rather than calculating it myself but there was definitely more I could’ve done to make everything look cleaner.

Overall for my first experience with p5.js and my limited experience with JavaScript , I think I would be proud of myself even later down the line.