Reading Response 5 – Design & Foresight (Week 8)

Reading 1: “Attractive Things Work Better” by Don Norman
I really liked Norman’s idea that attractive things don’t just look good—they actually change how we feel and behave. Before reading this, I used to think usability was all that mattered, but now I see how a beautiful design can make me more patient and forgiving. For example, there’s an app on my phone with a super sleek interface. Even when it glitches, I’m willing to give it another chance because it looks so appealing. On the other hand, if an app looks outdated or dull, I find myself deleting it right away. It’s fascinating how aesthetics can create a kind of emotional “cushion” that keeps us calm and curious, which then helps us solve problems more easily.

Reading 2: Margaret Hamilton and the Apollo 11 Mission
Margaret Hamilton’s story reminded me that critical work often happens behind the scenes and doesn’t always get the attention it deserves. Her software literally helped save the Apollo 11 mission by planning for things that might go wrong—something no one else seemed to think about at the time. I love how she pushed for software to be taken seriously as an engineering field. Back then, many people saw coding as less important than other parts of spaceflight, but her hard work proved otherwise. It’s really inspiring to see how her ability to anticipate mistakes changed everything for the mission. I think we can all learn from that: even if other people don’t immediately see the value in what we do, persistence and foresight can make a huge impact—sometimes, it can even save the day.

Week 8 – Unusual Switch

Concept

The idea is straightforward: use the AirPods case itself as a physical mechanism to connect or disconnect two wires.

  • When the AirPods are open: The two green wires make contact. This allows current to flow in such a way that the LED turns on.

  • When the AirPods are closed: The two green wires are pushed apart (or pulled apart), so the circuit is broken, and the LED turns off.

Of course, your exact implementation may depend on how you place the wires on the AirPods case—some people prefer taping them near the hinge or using a small piece of foam to press them apart. But the principle remains the same: open case = wires connected, closed case = wires disconnected (or vice versa).

What You’ll Need

  • Arduino Uno

  • Red wire (5V supply)

  • Black wire (GND)

  • Blue LED

  • 330 Ω resistor

  • Two green wires (these become the AirPods “switch” leads)

    Demo:

Midterm Project

Concept

Retro-style 2D shooters have always been a favorite among gamers. Their simplicity, fast-paced action, and pixel-art aesthetics create an engaging experience. I set out to create my own Pixel Shooter Game using p5.js, adding dynamic enemy interactions, ammo management, health pickups, and immersive sound effects.

The idea was simple:

  • The player moves around the screen and shoots at approaching enemies.
  • The enemies chase the player and deal damage upon collision.
  • The player must manage ammo and collect pickups to survive.
  • The game ends when the player’s health reaches zero.

With these mechanics in mind, I designed a game that combines action, strategy, and survival elements.

I used a lot of sound effects from popular shooter games (Half Life, Counter Strike, some soundtracks from Red Faction II) and sandbox games like Minecraft.

I also used free, open-source sprites from different forums, God bless open-source!

How It Works

The game follows a state-based system, transitioning between:

  1. Loading Screen – Displays a progress bar while assets are loading.
  2. Start Menu – Shows the title, “Start Game” and “Instructions” buttons.
  3. Instructions Page – Displays movement, shooting, and gameplay tips.
  4. Play Mode – The core gameplay where enemies chase the player.
  5. Game Over Screen – Displays the final score and an option to restart.

Core Mechanics

  • Player Movement: Uses WASD or arrow keys to move.
  • Shooting: Press Space to fire bullets.
  • Enemy AI: Enemies spawn and move toward the player.
  • Health System: The player starts with 3 HP and dies after three enemy hits.
  • Ammo System: The player has 20 bullets max and must pick up ammo to reload.
  • Pickups: Random enemies drop ammo or health packs.

Code Highlights:

1) State-Based Game Flow

To keep the game organized, I used a state-based approach to control transitions:

function draw() {
  background(20);

  if (gameState === "loading") {
    showLoadingScreen();
    if (assetsLoaded >= totalAssets && loadingCompleteTime === 0) {
      loadingCompleteTime = millis();
    }
    if (loadingCompleteTime > 0 && millis() - loadingCompleteTime > loadingDelay) {
      gameState = "start";
    }
  } 
  else if (gameState === "start") {
    showStartScreen();
    startButton.show();
    instructionsButton.show();
    backButton.hide(); // Ensure Back button is hidden
    
    if (!startMusic.isPlaying()) {
      startMusic.loop();
      startMusic.setVolume(0.5);
    }
  } 
  else if (gameState === "instructions") {
    showInstructionsScreen();
    startButton.hide();
    instructionsButton.hide();
    backButton.show();
  } 
  else if (gameState === "play") {
    runGame();
    showScore();
    startButton.hide();
    instructionsButton.hide();
    backButton.hide();
    
    if (startMusic.isPlaying()) {
      startMusic.stop();
    }
    
    if (!gameMusic.isPlaying()) {
      gameMusic.loop();
      gameMusic.setVolume(0.5);
    }
  } 
  else if (gameState === "dead") {
    showDeadScreen();
    startButton.hide();
    instructionsButton.hide();
    backButton.hide();
  }
}

Each function (showLoadingScreen(), runGame(), etc.) controls what is displayed based on the current state.


2) Player Shooting Mechanic

The player can shoot bullets, but with an ammo limit:

class Player {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.speed = 4;
    this.movementDist = 0; // we update this in update()
    this.ammo = 20;  
    this.health = 3;
    this.lastDamageTime = 0;  // Track last time the player took damage


  }

  update() {
   ...
  }

  show() {
    push();
    translate(this.pos.x, this.pos.y);

    // Face the mouse (common in top-down shooters).
    let angle = atan2(mouseY - this.pos.y, mouseX - this.pos.x);
    rotate(angle);
    scale(0.25);


    // Decide idle or move frames
    let moving = (this.movementDist > 0.1);

    // Pick frame index
    let frameIndex;
      imageMode(CENTER);

    if (moving) {
      frameIndex = floor(frameCount / 6) % playerMoveSprites.length;
      image(playerMoveSprites[frameIndex], 0, 0);
    } else {
      frameIndex = floor(frameCount / 12) % playerIdleSprites.length; 
      image(playerIdleSprites[frameIndex], 0, 0);
    }

    pop();
    
    this.showHealthBar();

  }
  
    showHealthBar() {
    ...
  }

  shoot() {
    // Fire only if enough time has passed since last shot AND we have ammo left
    if (this.ammo > 0 && millis() - lastShotTime > 200) {
      bullets.push(new Bullet(this.pos.x, this.pos.y));
      lastShotTime = millis();
      this.ammo--;  // reduce ammo by 1
    }
    
      if (gunSound) 
        gunSound.play();
  }
}

This ensures players can’t spam bullets, adding a strategic element to gameplay.

3) Enemy AI and Collision Handling

Enemies move toward the player, and if they collide, the player takes damage:

// Enemy-player collisions (Fixed)
for (let enemy of enemies) {
  let dPlayer = dist(player.pos.x, player.pos.y, enemy.pos.x, enemy.pos.y);
  
  // Only take damage if enough time has passed (e.g., 1 second)
  if (dPlayer < 30 && millis() - player.lastDamageTime > 1000) {
    player.health--;  
    player.lastDamageTime = millis(); // Update last hit time
    
    if (hitSound) {
      hitSound.play();
    }
    
    if (player.health <= 0) {
      if(playerDeathSound) {
        playerDeathSound.play();
      }
      gameState = 'dead';
    }
  }
}

This prevents instant death by implementing a damage cooldown.

4) Dynamic Background Music

Different background tracks play in menu and play modes:

else if (gameState === "play") {
  runGame();
  showScore();
  startButton.hide();
  instructionsButton.hide();
  backButton.hide();
  
  if (startMusic.isPlaying()) {
    startMusic.stop();
  }
  
  if (!gameMusic.isPlaying()) {
    gameMusic.loop();
    gameMusic.setVolume(0.5);
  }
}

This immerses the player by dynamically switching music.

Challenges and Improvements

1) Handling Enemy Collisions Fairly

Initially, enemies instantly killed the player if they were touching them. To fix this, I added a damage cooldown, so players have 1 second of immunity between hits.

2) Centering Buttons Properly

Buttons were misaligned when resizing the canvas. Instead of manually placing them, I used dynamic centering.

3) Preventing Accidental Game Starts

Initially, pressing any key started the game. To fix this, I made keyPressed() work only in play mode.

Final Thoughts

This Pixel Shooter Game was a fun challenge that combined:

  • Game physics (enemy movement, shooting mechanics)
  • User experience improvements (better UI, centered buttons)
  • Audio immersion (different music for each state)
  • Optimization tricks (cropping backgrounds, limiting bullet spam)

Possible Future Improvements

  • Add power-ups (e.g., speed boost, rapid fire)
  • Implement different enemy types
  • Introduce a high score system
  • Introduce multiplayer using socket.io (websocket server connection, so two different clients could play on separate machines)

This project demonstrates how p5.js can create interactive, engaging 2D games while keeping code structured and scalable.

Sketch (Click Here to Open Full Screen)

 

Week 5 – Midterm Progress

Inspiration

The idea is creating a top-down shooter game. I was inspired by  Nuclear Throne, where players control a character in a confined space and must shoot incoming enemies. The thrill of dodging enemies while strategically shooting at them creates an engaging and fast-paced gameplay experience. The goal was to recreate this immersive feeling while keeping the implementation simple and beginner-friendly using p5.js.

Concept and User Interaction

The game concept revolves around a player-controlled character that moves around the screen and shoots at enemy units that spawn randomly and chase the player. The user can interact with the game in the following ways:

  • Movement: The player uses the arrow keys or WASD to move in different directions.
  • Shooting: The player shoots bullets towards the mouse cursor by pressing the spacebar.
  • Enemies: Randomly spawned enemies move towards the player and can be destroyed by bullets.
  • Survival Challenge: The player must continuously avoid enemies while shooting them down.

This simple yet engaging mechanic ensures a dynamic game experience where quick reflexes and strategic positioning are key to survival.

Designing the Code Structure

Before diving into the code, I designed a modular approach to keep the project manageable and scalable. The core elements of the game were broken down into:

  1. Player Class: Handles movement, shooting, and rendering.
  2. Bullet Class: Manages bullet behavior, movement, and collision detection.
  3. Enemy Class: Controls enemy spawning, movement, and interaction with bullets.
  4. Game Loop: Updates and renders all game elements in each frame.
  5. Collision Handling: Detects when bullets hit enemies and removes them from the game.
  6. Enemy Spawning System: Ensures a steady challenge for the player.

By structuring the game this way, each component is easy to manage and modify.

Example – Player Class:

class Player {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.speed = 4;
  }

  update() {
    if (keyIsDown(UP_ARROW) || keyIsDown(87)) this.pos.y -= this.speed;
    if (keyIsDown(DOWN_ARROW) || keyIsDown(83)) this.pos.y += this.speed;
    if (keyIsDown(LEFT_ARROW) || keyIsDown(65)) this.pos.x -= this.speed;
    if (keyIsDown(RIGHT_ARROW) || keyIsDown(68)) this.pos.x += this.speed;
    
    this.pos.x = constrain(this.pos.x, 0, width);
    this.pos.y = constrain(this.pos.y, 0, height);
  }

  show() {
    fill(0, 255, 0);
    ellipse(this.pos.x, this.pos.y, 30, 30);
  }

  shoot() {
    if (millis() - lastShotTime > 200) {
      bullets.push(new Bullet(this.pos.x, this.pos.y));
      lastShotTime = millis();
    }
  }
}

Identifying and Addressing Key Challenges

One of the most challenging parts of the project is collision detection between bullets and enemies. Ensuring that fast-moving bullets accurately register hits on enemies can be tricky, especially in a game with rapid movement and frequent object interactions. Also, I wanted to add a multiplayer gameplay experience, so 2 players could play in the same session. However, I do not think it is possible without the use of socket.io.

Next Steps

Moving forward, possible improvements could include:

  • Adding different enemy types with unique behaviors.
  • Implementing a score system to track progress.
  • Introducing power-ups to enhance gameplay variety.
  • Multiplayer Mode: Implementing real-time multiplayer gameplay using Socket.IO so that two players can play together from different machines. This would involve syncing player movement, bullets, and enemies across connected clients through a Node.js server.

By integrating multiplayer functionality, the game could become even more engaging and interactive. Using real-time communication, players could strategize together, compete for the highest score, or even introduce cooperative play against waves of enemies. Setting up server-side logic to handle multiple players efficiently is a challenge but would greatly enhance the gaming experience.

Reading Response 4 – Computer Vision for Artists and Designers (Week 5)

In his article, Levin delves into the relationship between code and creative expression, illustrating how coding and computation offer a unique medium for artists to explore new forms of interactivity and non-verbal communication. This perspective was particularly eye-opening for me, as it shed light on how computation is not just a tool for efficiency or automation but also a canvas for artistic exploration.

One of the most fascinating aspects discussed in the article was computer vision. While the term itself is somewhat new to me, I was surprised to learn that efforts to advance this field began over half a century ago. It is remarkable to realize that machines can now collect visual data and “interpret” it, mimicking human perception in ways that were once the realm of science fiction. Computer vision models allow computers to identify human features, recognize expressions, and even infer emotions—all of which have groundbreaking implications, not only for fields like surveillance and security but also for art. In interactive media, for instance, artists are using computer vision to create installations that respond dynamically to human presence, movement, or even facial expressions, transforming passive spectators into active participants in digital art.

However, despite its exciting artistic applications, computer vision carries an eerie undertone due to its origins. The fact that this field was initially a military endeavor makes its transition into the realm of creative expression feel somewhat uncanny. The same technology that was once developed for warfare—such as guiding missiles or identifying enemy targets—is now being used to make art installations more immersive. This contrast raises an unsettling question: can a technology born from conflict and control ever be fully dissociated from its original intent?

Beyond its history, the rapid advancement of computer vision presents an undeniable threat to human privacy. Today, no one is truly safe from being recognized, analyzed, and cataloged by ubiquitous surveillance cameras, facial recognition systems, and AI-powered security networks. What was once considered futuristic is now an everyday reality—public spaces are filled with CCTV cameras that can track individuals in real time, while social media platforms use facial recognition to tag people in photos automatically. While some of these applications serve practical or even artistic purposes, they also blur the boundaries between technological progress and ethical concerns. When does interactivity cross into intrusion? At what point does an artistic exploration of human expression become indistinguishable from surveillance?

Reading Response 3 – Design of Everyday Things or Why I Hate Smart Watches (Week 4)

In “Design of Everyday Things”, Don Norman brings his perspective on the challenges of design of the daily tech. stuff. While I was reading the chapter, the example of a watch with four buttons really resonated with me. 

Don discusses how the excessive design features of the mentioned watch makes the overall user experience less enjoyable as a watch that has 4 different buttons brings extra functionality to something that was supposed to show time and time only. Even though the idea of a device with multiple buttons and functionality is quite progressive and optimistic, such a redundant feature bomb confuses the users of such a watch. It distracts the user from the initial purpose of a watch: time display.

I resonate with Don’s frustration with this product as I have experienced this firsthand when I got my hands on my first Apple watch. At the beginning, it was really fun to use: switching music tracks on the go, replying to messages and even using Siri to essentially Google anything was amazing, as if I had a mini companion on my hand. However, as time went on, I started to realize that I do not really use my Apple watch for checking time. Now it was another distraction that kept my feeble brain from work and kept me from focusing on the task in front of me. The constant notifications, messages and other features became hateful to me. At times, I didn’t even charge my own watch to work in silence.

Ever since I got my Apple Watch, I feel even more attached to my phone. The small screen, limited performance, and awkward interaction with tiny buttons make it frustrating to use. Plus, it’s packed with features I’ll likely never need, echoing the usability challenges Norman described. Having to charge it daily only adds another layer of inconvenience.

So, I believe watches shouldn’t try to be multifunctional gadgets but rather remain focused on a single purpose with a sleek, intuitive design. That’s what truly defines a watch. When overloaded with features, they lose their essence and become just another mini-smartphone—one that’s harder to use and more of a hassle to maintain. A watch should enhance convenience, not add to the digital clutter we already navigate daily.

Week 4 – Loading Data, Displaying text

Concept

I wanted to experiment with ASCII art in a dynamic way, using Perlin noise and interactive effects to create an evolving text-based visualization (I got inspired by the Coding Train videos on Perlin noise and this image manipulation + ASCII density coding challenge by him).

Each character is selected based on noise values, and their colors shift over time. As the mouse moves, it creates a ripple effect by “pushing” nearby characters away, giving a fluid and organic motion to the grid.

Demo (Click on canvas)

Code Highlight:

This part of the code uses Perlin noise to smoothly select characters from the density string and generate dynamic colors for each character.

// Using Perlin noise for smoother character selection
let noiseVal = noise(i * 0.1, j * 0.1, frameCount * 0.02) * density.length;
let charIndex = floor(noiseVal);
let char = density.charAt(charIndex);

// Generate color based on Perlin noise
let r = noise(i * 0.05, j * 0.05, frameCount * 0.05) * 255;
let g = noise(i * 0.07, j * 0.07, frameCount * 0.05) * 255;
let b = noise(i * 0.09, j * 0.09, frameCount * 0.05) * 255;

fill(r, g, b);
text(char, newX, newY);

How it works:

  • noiseVal determines the ASCII character by mapping noise to the density string length.
  • r, g, and b are also mapped to Perlin noise, creating a smooth, organic color transition over time.

Reflection & Improvements for Future Work

This experiment opened up some interesting possibilities for ASCII-based generative art. I’d love to refine the animation by adding more layers of motion, perhaps introducing gravity-like effects or different interaction styles. Another idea is to use real-time audio input to influence the movement, making the piece reactive to sound. Definitely a fun one to explore further!

Week 3 – Functions, Arrays, and Object-Oriented Programming

Concept

In this p5.js sketch, my main objective was to practice the use of classes and arrays. In my sketch, little objects called “walkers” wander randomly across the canvas, leaving behind the trail that slowly fades away. Each walker has its properties (see below in Code Highlight part), which are determined randomly at the moment of creation (user click).

Demo (Click on canvas)

Code Highlight:

The core of this sketch is the Walker class. It encapsulates everything each walker needs to function:

// Walker class definition
class Walker {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    // Give each Walker a random color
    this.col = color(random(255), random(255), random(255));
    // Control how quickly it moves around
    this.stepSize = random(1, 3);
  }

  update() {
    // Randomly move the walker in x & y directions
    this.x += random(-this.stepSize, this.stepSize);
    this.y += random(-this.stepSize, this.stepSize);

    // Keep the walker within the canvas boundaries
    this.x = constrain(this.x, 0, width);
    this.y = constrain(this.y, 0, height);
  }

  show() {
    noStroke();
    fill(this.col);
    ellipse(this.x, this.y, 8, 8);
  }
}

Inside this class, the update() method adjusts the walker’s position in small random increments, while show() draws a small ellipse at its current location.

The background(0, 13) call in the draw() loop is also important because it uses transparency to slowly erase the walkers’ paths, creating the glowing trails of each walker (I think it looks kinda cool).

Reflection & Improvements for Future Work

First of all, it was really entertaining to watch each walker wander around, leaving a trail. By simply changing parameters like number of walkers, their step size, or fade value in the background, one could produce unique versions of this piece.

In the future, I would love to make sure that the walkers of the same color would interact with each other (mixing together and creating a bigger walker). Another interesting idea would be to incorporate music in this piece (maybe 90s like Jungle beat) -> this way each walker would change its size/movement speed/direction based on the song.

If one would think long enough, the possibilities for making this piece more immersive and dynamic are essentially limitless.

Maybe one could make a game out of this piece, who knows?

Reading Response 2 – What Exactly Is Interactivity? (Week 3)

Chris Crawford’s idea of interactivity as a conversation between two participants came as a novelty to me. Before reading this, I assumed that any program that reacted to user input was interactive in its nature, but after reading this I was convinced that an interactive system must possess these three elements; listening, thinking and responding/speaking. 

I feel like Crawford’s example of the refrigerator light was brilliant, it made me rethink what it means for a system to be truly interactive. I began examining the apps and websites I use every day and noticed that many of them only react to user input without actually processing information in a meaningful way. They operate on predefined rules, responding to clicks and taps but not truly engaging with the user. This made me question whether these systems, despite their responsiveness, can really be considered interactive in the way Crawford describes. 

This reading also made me reflect on how I can make my own p5 sketches feel more interactive. Right now, they mostly respond to simple inputs like mouse clicks, but what if I could design interactions that feel more like a two-way conversation?

Instead of just reacting instantly, the system could analyze patterns in user input, adapt its responses based on context, or even introduce an element of unpredictability to keep the interaction dynamic. For example, it could recognize different drawing styles over time and subtly adjust its behavior to match the user’s preferences. Of course, achieving this level of interactivity would likely require more advanced tools than p5.js (Maybe use of LLMs/AI).

I would love to create something beyond basic cause-and-effect responses and explore ways to create a more engaging.

Reading Response 1 – Chance Operations (Week 2)

In his talk, Casey Reas explores the theme of order and chaos in art, emphasizing the role of randomness in creative processes. He also focuses on the notion of “controlled randomness” , where artists establish specific rules and parameters within code, allowing for unexpected outcomes while maintaining the overall coherence.

First of all, I really enjoyed listening to Reas’ talk. I appreciated the way he showcased his work and explained his philosophy on creativity and art. Reflecting on his insights, I aimed to incorporate the concept of controlled randomness in my most recent p5.js sketch, which I titled randomness. The overall structure of the artwork is straightforward—featuring a 10×10 grid of circles. However, the element of controlled randomness comes into play when the user interacts with the piece. Each time the user clicks on the canvas, the circles in the grid change in shape and size, creating a dynamic balance between order and unpredictability. While users can grasp the overall structure, every interaction (mouse click) generates a unique and evolving pattern. I wouldn’t go so far as to claim that my artwork revolutionizes the concept of generative art, but I believe it is an engaging and enjoyable piece to explore.

That being said, Reas’ perspective on art and the creative process encourages me to explore the potential of chance in my work. With every new p5.js sketch I create, I will keep the notion of “controlled randomness” in mind.