Week 4 Assignment – London Underground

Concept

For this week’s assignment, I was fascinated by the data visualization we did in class, so I wanted to create something similar using that technique. I was browsing the internet for inspiration and came across this website. In the video on the page, one of the data visualization ideas showed the Paris metro activity. This inspired me to visualize the London underground passenger traffic.

I had to create my own CSV file to obtain the data I needed. I used two different datasets from the Transport for London (TFL) website. One of them shows the total number of passengers using stations weekly, and another one shows the coordinates of the stations. I removed all the unnecessary columns and pasted the coordinates with the passenger counts and station names.

I ran into an error where the console said that some of the values it loaded from the CSV file were NaN, even though I made sure to delete any rows with no data. In previous data science classes I took, we always added a check to ensure we were only taking valid values, so I did the same in this sketch. I made new arrays that only add values that are not NaN.

I also added a feature to allow you to check the station name and the number of weekly passengers when you hover the mouse over it.

Reflection

Despite my love for the technique of data visualization, this is not one of my proudest works simply because I was extremely busy this week and could not dedicate as much time as I wanted to on this sketch. In the future, I would definitely like to add a map of London in the background and also to space the circles out in a way where you can actually see each station since there is a lot of overlapping circles and you are not able to properly see each station when you hover your mouse.

Week 4 – Reading Reflection

This reading is probably my favorite reading so far. It triggered me to reflect on various objects we encounter daily that are not very efficient, and have not had a change in their mechanisms for years. When reading about mapping lights to their switches, it reminded me of my own house, where we have a set of switches near the main door.

Even after living in this house for around 10 years, I still flick multiple switches until I find the one I need. The placement of the switches is especially inefficient because some of these switches are for lights outside the house in the front yard, and some are for lights inside the house.

It took me a while to think of something that functions inefficiently besides what was already mentioned in the reading, because I feel like Norman covered some of the core ones. Then, I remembered my electric toothbrush. My electric toothbrush is the most basic Oral-B model, and it only has one button (as do most electric toothbrushes). On top of this button, the word “timer” is written, indicating that this button is a timer. However, this button is also the same button I use to turn on the toothbrush. I was always confused about how to trigger the timer, and I did not have access to the manual to check. It took me around a year to realize that the toothbrush vibrates in a specific pulsing pattern for a short 2 seconds after 2 minutes of being on. I always wondered why the toothbrush would randomly vibrate weirdly mid-brush, and then I connected the dots. Using Norman’s definitions, this is an issue with the feedback of the system. How was I to know that the timer had started? While to me specifically, I think something like a light or a sound would’ve been a better indicator for the timer, I actually think this design is the most accessible design. It means deaf and blind people can still sense the toothbrush’s vibrations to know the timer is up. So, I think sometimes designs can seem inefficient to some people, but in reality they are designed this way to make them functional to everyone no matter their abilities.

This is a clear example of an item that affords timing your brush, but has poor design with signifiers that allow the usage of this feature. Norman’s argument on the importance of designing products keeping in mind the complexity of humans and eliminating the thought that how to use a feature you create will be obvious to its users can be applied to our interactive media projects. Interactive media is all about experience and interactivity. Without clear instructions from the artist on how to interact with their artwork or their game, users cannot maximize their experience. Imagine how frustrating it would be for a user to play a game with no instructions on how to control the game or about the main goal of the game. The game loses its purpose to entertain, because the user is frustrated with figuring out how to work the game.

Week 3 – Reading Reflection

The only thing I was impressed with was Crawford’s ability to write that much about the misuse of the term interactivity. In my opinion, Crawford was being quite exaggerative. While I understand the frustration and agree that people sometimes slap the word “interactivity” on more reactive things, many of the examples Crawford gave were not very common. I have never really heard of a movie being called interactive before, unless it’s a kids’ movie like Dora, nor have I heard someone call opening the fridge interactive.

Following his argument to its logical conclusion, we should change “interactive media” to “reactive media.” After all, interactive media is programmed to trigger a reaction when the user interacts with it, but it does not listen, think, and respond the way Crawford claims interactivity should. However, when I Googled the official definition of interactivity, the Oxford dictionary defines it as “the process of two people or things working together and influencing each other.” According to this definition, everything Crawford claimed was not interactive is indeed interactive, because it involves things influencing each other, not necessarily listening, thinking, and speaking.

That said, I do agree with Crawford that interactivity exists on a spectrum. I believe the characteristics of a strongly interactive system are its ability to listen, think, and speak. Generative AI is the best example of a strongly interactive system we currently have, if not the most interactive. It simulates human conversation and allows for human-like interactions. Other examples of interactivity, such as humans triggering a reaction from computer-based artwork (like the sketches we do in class), fall on a slightly lower scale of interactivity because they are more of a “reaction,” to use Crawford’s terms, but I would still consider them highly interactive.

To improve the degree of user interactivity in my sketches, I could go beyond just the click of a mouse. Using different parts of the human body, including an interactive webcam project, like one of my classmates’ projects for this week, and even allowing for multiple interactions at once – something like a two-player game – can all improve the degree of interactivity of my sketches.

Week 3 Assignment – Simplified Pac-Man

Concept

For this week’s assignment, I decided to draw a bit from the skills I learned in Intro to CS back in my freshman year. I chose to implement a very simplified version of Pac-Man, something I always wanted to recreate.

Here is the final sketch (use the right arrow key to begin moving Pac-Man):

The idea is simple: you use the left and right arrow keys to move Pac-Man, and it eats the ghosts once it approaches them. Once all the ghosts are eaten, and Pac-Man returns to his starting position on the left side of the screen, the ghosts regenerate. This creates a sort of infinite loop.

Pac-Man:

The Pac-Man figure is created using the arc() function. On the p5 reference page for the function, there is a sample code for a biting Pac-Man. So, I used that in my assignment. I used Claude.ai to understand what each line of code was doing, specifically how the sin function works and how it enables the model to open and close its mouth. Building on this knowledge, I was able to adjust the speed at which Pac-Man was biting. I also added a boolean that checks if he is moving, so that he is only biting when he is moving.

Pac-Man’s movements are based on the pressing of the right and left arrow keys. From my Intro to CS class, where we built a sample Super Mario Bros game, I knew there must be a way to trigger movement when a specific key is pressed. With a Google search, I found that you can use

if (keyCode === LEFT_ARROW)

However, this function made it difficult to make Pac-Man move when the key is pressed and stop when the key is released. I had a bug where he would just keep moving on his own. I asked Claude.ai for a different function that is specifically for detecting if a key is held down or not, and it gave me the keyIsDown() function. This function returns true if the key is pressed, and false if not. This function fixed my bug and made Pac-Man stop and go correctly.

Ghosts:

For the ghosts, I found PNG images on Google and uploaded them to the sketch. Then, I found this sketch online, which includes a tutorial on how to load and display images.

I faced some difficulty with getting the ghosts to disappear when Pac-Man eats them. At first, I was just looping through the image names and displaying each image, then checking if the x position of Pac-Man and the image aligned, and deleting the image, but this was not doing anything. I asked Claude.ai why my code was not working, and it pointed out to me that images cannot hold x variables; therefore, I cannot check conditions using them. So, I created a simple Ghost class to store each ghost image’s x and y positions, its size, and image name. I made each ghost image an instance of the Ghost class, and stored them in a ghosts[] array. This allowed me to use the dist() function to see if Pac-Man was close to the ghost and delete that ghost instance from the array, which makes the ghost disappear from the sketch.

I was initially just going to leave the sketch with one iteration of displaying, then eating the ghosts, but then I decided to make it regenerate the ghosts every time they are all eaten. I did this by checking if the ghosts[] array is empty, because that indicates that all ghosts have been eaten. Adding only this condition gave me a small bug where the ghosts do not generate when the sketch first loads. It also would re-display the ghosts as soon as the last ghost is eaten, and since Pac-Man would be in proximity of the last and before last ghosts, it eats them immediately, making all the ghosts disappear as soon as they appear. Therefore, I added a condition that ensures that not only must the array be empty, but Pac-Man must also be on the left side of the screen (back at his starting position).

Code Snippet I am Proud of:

//loop backwards through the ghost objects to delete from the back of the array, otherwise you skip items in the array
 for (let i = ghosts.length - 1; i >= 0; i--) {
   let ghost = ghosts[i];

   //display the ghost image
   image(ghost.imgName, ghost.x, ghost.y, ghost.size, ghost.size);

   //if the distance between the center of pacman and the center of the ghost is smaller than 50
   if (dist(pacman.x, pacman.y, ghost.x + 40, ghost.y + 40) < 50) {
     //delete that ghost object from the array so that it is not displayed
     ghosts.splice(i, 1);
   }
 }

This is the code to display the ghost images and delete them when Pac-Man eats them. I am most proud of it because it took me the longest to figure out, and I made LOTS of edits until I reached the final version that worked.

Reflection

Overall, I am extremely happy with my work. Pac-Man has always been one of my favorite games, and I am thrilled I got the chance to recreate it. Despite running into a lot of bugs, they taught me a lot along the way, helped me discover new functions, and expanded my knowledge on how certain things are done in JavaScript since I have never coded using it before. For the future, I would definitely love to properly implement a full Pac-Man game, maybe for my final project 🙂

References

keyIsDown(): https://p5js.org/reference/p5/keyIsDown/

Image upload tutorial: https://editor.p5js.org/FAAH/sketches/8s1g0vilF 

arc(): https://p5js.org/reference/p5/arc/

Claude AI: https://claude.ai/new

  • Claude was used to understand the biting Pac-Man code from the arc() reference page, for debugging when the ghosts were not disappearing, and for finding the keyIsDown() function. It gave me the solution of creating a ghost class, which I then implemented on my own.

Week 2 – Reading Reflection

Before watching the video, I assumed that randomness = messy or chaotic. I never before thought of controlled randomness, which initially sounds contradictory, but begins to make sense as the video goes on. I was fascinated by the artwork that was produced by programming randomness and it opened my eyes to different ways randomness can be used in my own work. In a way, some of the artworks Reas showed in the video, specifically the music pieces, reminded me of modern AI. The music sounded exactly what it was, random, yet also structured oddly enough. It reminded me of AI generated images and songs because AI tends to create some very messy looking images when you give it a specific prompt, and the randomly generated music somewhat mimics the idea of AI nowadays. More importantly, I was mostly impressed with the artwork that can be produced through computer graphics and code. Coming from a computer science backround, most of my coding involved creating algorithms. So, seeing a whole new world of coding to create abstract art pieces was captivating.

In my own artwork, I definitely plan to incorporate randomness by generating random colors and sizes for objects when needed, and especially for generating random positions and velocities for objects. I believe the optimum balance between total randomness and complete control is having almost complete control yet incorporating some elements of randomness when necessary. The control comes from writing the code yourself and deliberately inserting when you want randomness to be used. This helps create more complex art pieces because sometimes it is difficult to draw each element individually in the sketch and create more abstract pieces. So, the element of randomness allows for the creation of art pieces one might not have completely imagined in their mind.

Week 2 Assignment – Loops

Concept

For this assignment, I took inspiration from the computer graphics pdf attached to this assignment’s description (photo below).

Building on this graphic, I made a simple grid with squares inside it. I initially wanted to create the moving graphics, but I could not figure out how. Therefore, I decided to use some skills we learned in class on changing colors when the mouse is inside the squares. Finally, I ended up with my final design, where the group of squares changes to the colors of the rainbow when the mouse hovers over them, keeping all the other cells still white.

Here is my final sketch:

Code I am Proud of:

for (let r = 0; r < 5; r++) {
    for (let c = 0; c < 7; c++) {
//calculates where each cell should start based on the row and column and shifts by cell size
      let cellX = c * 80;
      let cellY = r * 80;

      square(cellX, cellY, 80);
      square(cellX + 10, cellY + 10, 60);
      square(cellX + 20, cellY + 20, 40);
      square(cellX + 30, cellY + 30, 20);
  }
}

I am particularly proud of my code which creates the grid, because I optimized it. Initially, I set up the grid with four different for() loops, which basically keep printing a grid but make it smaller each time to create the inner squares effect. Then, I realized I could combine them all into a single for loop by storing each outer square’s starting X and Y locations, and then writing multiple square() functions, shifting each one according to how inner the square is. This also allowed me to select a different color for each square when the mouse hovers over it.

Reflection and Future Improvements:

Overall, I am quite happy with my sketch and enjoyed the process of creating it. For the future, I would definitely like to implement some automatic motion into my sketch. I would probably want to recreate the original sketch I took inspiration from, with the moving inner squares. Additionally, I would like to work on a second version of this sketch where the color of the inner squares only changes if the mouse is directly over it, not if the mouse is generally inside any of the squares within that group of squares.

Week 1 Assignment – Self-Portrait

Concept:

For my self-portrait, I was trying to think of a creative way to display my head. I was mainly thinking of a way that would help me avoid drawing my hijab as I was not too sure how to implement that. I also wanted to force myself to use some creativity since I don’t always get the opportunity to do that in my Computer Science classes. I ended up drawing my head in the shape of a cloud using ellipses. I drew this inspiration from my name, which means a rainy cloud in Arabic. I also added the rain effect in the background to complete my name’s translation. As for the tree, I attempted to draw an olive tree, to represent my Palestinian identity.

Implementation:

I mainly used ellipses and rectangles to create everything in the sketch. I used a rectangle for the tree’s trunk, and circles for the bushes and olives. For the cloud, I drew one ellipse in the centre and then drew multiple ellipses around it, placing them in a way that would create a cloud shape. For the smile, I later realized I could have used the arc() function, but for this specific implementation I drew an ellipse and then put a rectangle over it in the same color as the cloud to create a semi-circle. The nose used the line() function, the eyes are ellipses, and the eyebrows are drawn using the arc() function.

For the rain in the background, I watched this YouTube tutorial on how to add it. Considering my computer science background and my familiarity with using classes and functions, I was able to understand the code and implement it.

Code I am Proud of:

//eyebrows
  stroke(0);
  arc(254, 220, 20, 3, radians(180), radians(355));
  arc(315, 220, 20, 2, radians(180), radians(355));

Despite its simplicity, the eyebrows were definitely the most difficult part to implement. I watched a YouTube video to understand further how it works, as I was a little confused. Through this video, I discovered you can typecast from degrees to radians, which made the function much easier to use since radians are a bit difficult to work with.

//array to store all created raindrops
drops = []

class RainDrop{
  constructor(x, y){
    this.pos = createVector(x, y)
    this.vel = createVector(0, random(8, 11))
    this.length = random(20, 40)
    this.strength = random(255)
  }
  
  //displays each rain drop
  show(){
    stroke(255, this.strength)
    line(this.pos.x, this.pos.y, this.pos.x, this.pos.y-           this.length)
  }
  
  //makes the rain fall
  update(){
    this.pos.add(this.vel)
    if (this.pos.y > height + 100){
      drops.shift()
    }
  }
}

function setup() {
  createCanvas(400, 400);
  p = createVector(random(width), 200)
}

function draw(){
  background(173,212,247);
  
  //loop to create many raindrops and store them in an array
  for (let i = 0; i < 5; i++){
    drops.push(new RainDrop(random(width), 0, 0))
  }
  
  //show each rain drop
  for (let d of drops){
    d.show()
    d.update()
  }
}

The other code snippet I am proud of is the rainfall. Despite using lots of help from YouTube, I was proud of coming up with the idea and having it implemented exactly how I wanted it.

Reflection:

Overall, I am quite happy with the final result and truly enjoyed the process of making this. Despite coding frequently in my CS classes, this type of coding felt different and more enjoyable, less algorithmic. It also feels more rewarding as you create your final sketch because you can see results as soon as you type the code. For the future, I would definitely like to explore more with adjusting strokes so that they only outline certain parts of a shape, especially for parts of the sketch developed by layering multiple shapes.