Week 10 Production

For this week’s assignment, I used potentiometer as an analogue sensor, and a tactile button as a digital sensor (switch) and two LEDs. For the LED that is controlled by the tactile button, I made it so that it blinks twice and the potentiometer for brightness control.

Code:

int led = 11;
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(A2, INPUT);
}

// the loop function runs over and over again forever
void loop() {
  int button1State = digitalRead(A2);
  int sensorValue = analogRead(A1);
  
  Serial.println(sensorValue);

  analogWrite(led, sensorValue/4);
  delay(30);

  if (button1State == HIGH) {
    digitalWrite(8, HIGH);
    delay(1000);
    digitalWrite(8, LOW);
    delay(1000);
    digitalWrite(8, HIGH);
    delay(1000);
    digitalWrite(8, LOW);
    delay(1000);

  } else if (button1State == LOW){
    digitalWrite(8, LOW);
  }

}

Video:

Week 10: Reading Response

Physical Computing’s Greatest Hits (and misses)

Among the physical computing projects, Fields of Grass piqued my interest the most. Thinking about it, I believe that the sensors could be arranged in various ways so that the output changes based on not only the position of the hand, but also the pressure applied. Imagine creating a virtual landscape where the terrain shifts depending on how firmly you press your hand! Delicate touches could reveal hidden paths or trigger calming sounds, while heavier presses might activate bolder visuals or more dramatic effects. This additional layer of interaction would add a whole new dimension to the experience. Beyond pressure, the sensor arrangement could be tweaked to respond to other hand interactions. For instance waving your hand across the field to control the movement of virtual birds, or gently cupping your hand to scoop up shimmering virtual butterflies. Moreover, Fields of Grass could be adapted to respond to footsteps, creating a truly immersive experience where walking through the installation ripples the virtual landscape. In a museum setting, the project could be transformed into an educational tool. Visitors could “grow” different virtual plants by placing their hands in designated areas and manipulating pressure or movement to influence factors like sunlight or water. The applications could even reach the field of physical therapy, with the virtual world responding to specific hand motions or muscle control, providing a visually engaging way to track progress.

Making Interactive Art: Set the Stage, Then Shut Up and Listen

Integrating this reading’s notion into the Fields of Grass projects, the users will be free to interact with the grass, but the output will be in the prescribed yet non-deterministic way. If we assume each user’s interaction to be a performance, we can also assume collaborative performances between 2 users generating new form of performance between multiple users and the project. Their combined hand movements and pressure could trigger entirely new visual and audio responses, fostering a collaborative performance unlike anything seen before. The project becomes a bridge, translating individual actions into a shared, ever-evolving experience. This opens doors for fascinating possibilities. Friends could create synchronized “dances” with the field, therapists could use it for collaborative movement exercises, or even strangers could stumble upon unexpected moments of artistic synergy.

Week 9: Blow Switch

“A switch is nothing more than a mechanism to bring two pieces of conductive material together and separate them. ” Since we are not allowed to use hands, I wanted to make a switch that works using a movement of an object through wind. Which is why I thought that I would stick one wire to a some conductor, and other wire would touch the conductor by moving to it.

The following materials were needed:

  • 330-ohm resistor
  • 1 LED light
  • Jumper wires
  • Breadboard
  • Arduino board
  • Scotch tape

Process:

First, I taped on of the wires connecting to the breadboard to an iron top of a cup. Then, I taped another wire that is connected to the breadboard to the hole of a round bottle (the object that would move by blowing). So, by blowing on the horizontal bottle in the direction of the iron top of the cup, the wires touch this conductor, therefore turning the LED on.

Video Link:https://youtube.com/shorts/U-Gy1GvoFjY?feature=share

Reflection:

I had a hard time brainstorming about ways to not utilize my hands and finding suitable conductors. I had different conductors than the ones I used in mind, but maybe because of the material itself, the LED was blinking dimly, so I had to change them. I expected taping process to be difficult considering the wires have to be put in place, but thanks to the conductor having a big surface area, it was not as difficult as I imagined.

Week 8 Reading Response

Emotion & Design: Attractive things work better

While reading this passage, one of the aspects that piqued my interest was the discussion of the affective system. The affective system seems to awfully relate to utilitarianism in the sense that it judges and classifies aspects of life to binary entities of positive and negative. As utilitarianism is highly contextual and can be proven null based on certain contexts, I believe that affective system can also prove to be useless in certain contexts. There could be scenarios where the affective system judges something to be positive and yet the cognitive system could not make sense of it, which would imply that there are not enough information to make sense of it based on the contextual information alone.

Her Code Got Humans on the Moon—And Invented Software Itself

As a software engineer enthusiast, Margaret Hamilton has always been an idol to me. The way she not only contributed significantly to Apollo, but also paved the way for the present software engineers when she was the minority in the field. As stated by the passage, there have been numerous denials and harsh comments about her regarding her situation as a mother and also the situation regarding the P01 program, but ultimately she have proven many doubters wrong. I distinctly remember the picture of her where she held a stack of papers her height which consisted of her handwritten codes. To be writing such important codes without any IDE s, compilers or helper tools is beyond me.

The nexus between software engineering and design is profound, with user interface and system design serving as pivotal components. Margaret Hamilton’s contributions to Apollo and the broader field of software engineering exemplify this intricate relationship. Her remarkable ability to craft critical code manually, without the aid of modern tools, underscores the fundamental principles of design thinking in software development. This highlights the paramount importance of intertwining technical proficiency with human-centric design considerations to create impactful and user-friendly software solutions.

Midterm Assignment: Knighthood Arcade

Concept:

https://editor.p5js.org/tt2273/sketches/FyrgY5Ivv

“Knighthood Arcade” immerses players in an exciting quest where they take on the role of a valiant knight tasked with eliminating menacing slimes infesting the kingdom. Set in a vibrant 2D environment, the game unfolds as players navigate challenges, strategize attacks, and seek victory against relentless slime adversaries.

The primary objective is for players to eliminate a specified number of slimes, with a set kill count serving as the victory condition. The game intricately balances combat, movement, and decision-making, requiring players to engage with the environment and enemies strategically.

Players achieve victory by successfully defeating predetermined number of (five in this case) slimes. Each slime defeated contributes to the player’s kill count. The dynamic gameplay evolves as the knight progresses, presenting increasingly challenging encounters with the slimes. The game introduces a perilous scenario where the knight faces defeat under specific circumstances:
– If the knight succumbs to slime attacks due to inadequate defensive maneuvers.
-If one of the slimes gets to the other side without being slain.

Implementation and Parts I am Proud of:

In crafting “Knighthood Arcade”, several key implementations have shaped the gaming experience. The strategic integration of combat dynamics allows players to tactically time attacks, emphasizing the significance of thoughtful engagement with the slimes. Navigating the knight through diverse terrains and overcoming movement challenges showcases the finesse required for successful progression. Furthermore, the integration of a subtle narrative layer, albeit minimal, contributes context and motivation to the knight’s quest. Personally, I take pride in the balance achieved between combat, movement, and decision-making elements, providing players with a challenging yet enjoyable gaming experience. This delicate equilibrium is complemented by the implementation of varying slime behaviors, adding depth and nuance to the adversaries. Adding idle animations to the sprite movement, which makes the game more similar to an arcade game, I believe was an excellent touch. I integrated p5play using cdn, but using the p5play documentation was rather difficult as the user interface was not good. Another aspect of the game that I am proud of is the checkDistance function, which determines whether the sprites are close to each other or not. Overall, the game not only delivers on its primary goal of strategic combat but also offers a dynamic and immersive environment that I find particularly gratifying as a developer and an arcade enthusiast.

Challenged faced:

Throughout the development journey of “Knighthood Arcade” various challenges were encountered, each contributing to the learning and growth of the project. Implementing effective collision detection and response mechanisms presented a significant hurdle, demanding meticulous fine-tuning to ensure seamless interactions between sprites. Managing the complexity of sprite animations, particularly synchronizing the knight’s actions with the game’s logic, posed another formidable challenge.  Addressing unexpected bugs and glitches, inevitable in any development process, demanded a systematic debugging approach. Integrating sound elements, specifically synchronizing background music with in-game events, proved to be a nuanced challenge, adding an auditory layer to the gaming experience. Overcoming these difficulties not only refined technical skills but also underscored the iterative nature of game development. Moreover, managing the sprite animations in the preload function was difficult at first, since the difference between the adjacent sprites were minimal, therefore detecting if the sprite animations were implemented into the array was hard.

Further Improvements:

Looking ahead, “Knighthood Arcade” presents ample opportunities for further refinement and expansion. One key area of improvement involves incorporating a more intricate combat system, introducing diverse enemy behaviors, and enhancing the strategic depth of engagements. Introducing additional levels with progressive difficulty could elevate the overall gaming experience, providing players with a sense of accomplishment as they navigate increasingly challenging scenarios. Implementing a scoring system and perhaps integrating an online leaderboard could foster a competitive element, encouraging players to strive for higher scores and fostering a sense of community around the game. The visual aesthetics and overall presentation could benefit from additional polish, including more detailed background art and refined character animations. Exploring the integration of power-ups, character upgrades, or even new characters could introduce fresh dynamics and keep players engaged over extended gameplay sessions.  These potential enhancements lay the foundation for the game’s evolution, promising an even more captivating and immersive experience for players in future iterations.

Code Snippet:

slimeMovement(slimeSprite);
 
      if (checkDistance(slimeSprite, mySprite, 100) && isAttack) {
        if (!slimeSprite.dead){
          slimeSprite.dead = true;
          slimeSprite.changeAnimation("dead");
          setTimeout(() => {
            slimeSprite.animation.stop();
            slimeSprite.animation.changeFrame(3);
          }, 500)
          killed++;
          console.log(killed);

        setTimeout(() => {
          slimeSprite.position.x = width+100;
          slimeSprite.position.y = random(50, height-50);
          slimeSprite.dead = false;
        }, 1000);
        slimeMovement(slimeSprite);
      }
    } else if (checkDistance(slimeSprite, mySprite, 50) && !isAttack){
          slimeSprite.changeAnimation("attack");
          mySprite.changeAnimation("dead");
          setTimeout(() => {
            slimeSprite.changeAnimation("idle");
            mySprite.position.x = -100;
            mySprite.position.y = -100;
          }, 1500)
          gameState = "end-lose";
      }

Final Sketch:

 

Week 5 Reading Response

The exploration of computer vision in interactive artworks is truly fascinating, especially considering its roots in Myron Krueger’s Videoplace from the late 1960s. The idea that the entire human body should be involved in interactions with computers was revolutionary at the time. Videoplace’s ability to digitize a participant’s silhouette and synthesize graphics based on their posture and gestures was ahead of its time. I believe that the notion of involving human body with computer interaction through computer vision to be an essential yet dangerous idea. While it does produce valuable possibilities like the Videoplace or Sorting Daemon, but there could be dangerous implications for our society. For instance, computer vision algorithms may exhibit bias, leading to discriminatory outcomes, especially if the training data is not representative of diverse populations. Biases in such algorithms can result in unfair and discriminatory decisions, affecting individuals in areas like hiring, law enforcement, and financial services. While this can be considered as a interactivity through computer vision, the consequences of this in this contemporary society could affect the lives of many in serious ways.

While reading the computer vision techniques, the notion of semantic understanding piqued my interests. Upon further research I found that unlike text-based data, which inherently carries semantic and symbolic information, digital video, in its raw form, consists of streams of rectangular pixel buffers with no intrinsic meaning therefore making the case for this problem. This lack of inherent semantics hinders a computer’s ability to interpret or extract meaningful information from the video content without additional programming. Bridging the semantic gap seems to be important for developing computer vision algorithms that can discern and interpret the content of video streams, enabling applications to answer even elementary questions about the presence of objects or individuals and the contextual details within a given scene.

Midterm Progress: Knighthood Arcade

From a young age, I always loved playing arcade games with my brother. We would get around 20 gold coins from the cashier and spend all of it on different games. Which is why for a midterm project, I have decided to make a small arcade game called Knighthood using sprites. I am using p5play library and incorporating it to p5js using cdn. For now, I have one character called knight who stay idle, walk, jump, and attack. Although I have not implemented it yet, I am planning to make the game seem as vintage as possible. Design wise, I am also planning to incorporate a background music and movement sounds as well. For instance, there will be sound when the knight attacks or when enemies die.

As for game logic, I am planning to make 3 types of difficulties so the number of enemies change alongside their life bar. As the user chooses the difficulty, the number of enemies with different life bars will be pre loaded and will spawn in random location is set interval and attack the character. the Character will die after 3 hits.

I believe that the challenging aspect of this project will be implementing the way in which the knight hits the enemies. The condition is that the enemy should be near the knight with the margin of 10 px and the key ‘K’ should be pressed. To mitigate this problem, I am planning making boolean variable is Attacking to check if the K key is pressed and if it is pressed, checks if the enemy is nearby and if they are, they will change animation to dead state and then vanish after few seconds. Another potential problem might be the interactive problem of indicating that the knight was hit. User has to know besides the health count that the knight has been hit. For this, I am thinking of implementing knock back effect for the knight when he is hit by an enemy.

function keyPressed() {
  if (keyCode === 66) {
    // 'B' key pressed, hide instructions
    showInstructions = false;
  }
  if (keyCode === 87) {
    mySprite.setSpeed(3, 270);
    mySprite.changeAnimation("walk");
    setTimeout(() => {
      mySprite.changeAnimation("stand");
    }, 500);
  } else if (keyCode === 83) {
    mySprite.setSpeed(3, 90);
    mySprite.changeAnimation("walk");
    setTimeout(() => {
      mySprite.changeAnimation("stand");
    }, 500);
  } else if (keyCode === 65) {
    mySprite.setSpeed(3, 180);
    mySprite.changeAnimation("walk");
    setTimeout(() => {
      mySprite.changeAnimation("stand");
    }, 500);
  } else if (keyCode === 68) {
    mySprite.setSpeed(3, 0);
    mySprite.changeAnimation("walk");
    setTimeout(() => {
      mySprite.changeAnimation("stand");
    }, 500);
  } else if (keyCode === 13) {
    mySprite.position.x = width / 2;
    mySprite.position.y = height -100;
    mySprite.setVelocity(0, 0);
    mySprite.changeAnimation("stand");
  } else if (keyCode === 32 && !isJump) {
    mySprite.changeAnimation("jumping");
    isJump = true;
    mySprite.velocity.y = -8;
    // Set a timeout to reset the jumping flag after a short duration
    setTimeout(() => {
      mySprite.velocity.y = +5;
      mySprite.changeAnimation("stand");
      isJump = false;
    }, 500); // Adjust the duration as needed
  } else if (keyCode === 75 && !isAttack) {
      mySprite.changeAnimation("attack");
      isAttack = true;
      setTimeout(() => {
        mySprite.changeAnimation("stand");
        isAttack = false;
      }, 500) ;
  }
}

 

Reading Response Week 4

One of the aspects that piqued my interest in the reading was the paradox of technology. It is without a doubt that things tend to get replaced as newer and better technology emerges. As the complexity increases alongside it, I believe there is certain fragility that comes with as well. In the case of watches, as it evolves to maximize efficiency there could be certain capabilities that are sacrificed in order to achieve that. These sacrifices are what causes these fragilities. This leads to the question of whether there should be balance between them, as this could lead to lower efficiency. I think that there are many examples of products that is made with this in mind, but they are not particularly regarded as better in this society’s standards.

In regards to design, I often noticed that when something has a good design, it is rarely notices, but if it has a bad design, the annoyances are highlighted much easily. When the design is good, there seems to be a certain smoothness within the system, but if the design is bad, certain redundancy or annoyances are to be found. With a good conceptual model, the communication between the design and the user becomes less confusing. With complex operating systems like Microsoft, it contains numerous manuals but when there are certain errors, troubleshooting it becomes more and more vague in some cases therefore requiring additional help, which I believe is large but inevitable design flaw.

Week 4: Hangman

The concept for this week’s assignment, I wanted to make a hangman word game. The code consists of helper functions such as keyPressed, startNewGame, checkGuess etc. Firstly, it creates a number of empty dashes  based on the number of letters in the chosen word. As a letter is pressed, dashes are changed to a letter if the letter is in the word, and the body of the hangman is drawn if it is not. At the end of the game, it checks if the user guessed the word correctly, and shows corresponding texts.

Further on, I would like to add randomized word generation or read from csv or text file large pool of words.

code:

let word;
let guessedWord;
let maxAttempts = 6
let attemptsLeft = maxAttempts;
let guessedLetters = [];

function setup() {
  createCanvas(400, 400);
  textAlign(CENTER, CENTER);
  startNewGame();
}

function draw() {
  background(220);

  // Display hangman
  drawHangman();

  // Display guessed word
  textSize(32);
  text(guessedWord.join(' '), width / 2, height / 2 - 20);

  // Display attempts left
  textSize(16);
  text(`Attempts left: ${attemptsLeft}`, width / 2, height - 20);

  // Display guessed letters
  text(`Guessed letters: ${guessedLetters.join(', ')}`, width / 2, height - 40);

  // Check for game over
  if (attemptsLeft === 0 || guessedWord.indexOf('_') === -1) {
    gameOver();
  }
}

function keyPressed() {
  if (keyCode === ENTER) {
    startNewGame();
  } else if (key >= 'a' && key <= 'z' && !guessedLetters.includes(key)) {
    checkGuess(key);
  }
}

function startNewGame() {
  // List of possible words
  let words = ["apple", "banana", "simulation", "problems", "reaction"];

  // Choose a random word
  word = random(words).split('');

  // Initialize guessedWord with underscores
  guessedWord = Array(word.length).fill('_');

  // Reset attempts
  attemptsLeft = maxAttempts;

  // Reset guessed letters
  guessedLetters = [];
}

function checkGuess(letter) {
  // Add guessed letter to the list
  guessedLetters.push(letter);

  // Check if the letter is in the word
  let correctGuess = false;
  for (let i = 0; i < word.length; i++) {
    if (word[i] === letter) {
      guessedWord[i] = letter;
      correctGuess = true;
    }
  }

  // Decrease attempts if the guess is incorrect
  if (!correctGuess) {
    attemptsLeft--;
  }
}

function drawHangman() {
  stroke(0);
  
  line(width / 2 - 100, height /2 - 80 ,width /2 - 50, height /2 -80)
  line(width / 2 - 75, height / 2 -80, width / 2 -75, height /2 - 180)
  line(width / 2 -75, height / 2 - 180, width / 2, height / 2 - 180)
  line(width / 2, height / 2 - 180, width / 2, height / 2- 160)
  
  // Head
  if (attemptsLeft < maxAttempts) {
    ellipse(width / 2, height / 4 - 50, 20, 20)
  }

  // Body
  if (attemptsLeft < maxAttempts - 1) {
    line(width / 2, height / 4 - 40, width / 2, height / 2 - 80);
  }

  // Left arm
  if (attemptsLeft < maxAttempts - 2) {
    line(width / 2, height / 4 -30, width / 2 - 20, height / 4-10 );
  }

  // Right arm
  if (attemptsLeft < maxAttempts - 3) {
    line(width / 2, height / 4 -30, width / 2 + 20, height / 4 -10);
  }

  // Left leg
  if (attemptsLeft < maxAttempts - 4) {
    line(width / 2, height / 2 - 80, width / 2 - 20, height / 2 -60);
  }

  // Right leg
  if (attemptsLeft < maxAttempts - 5) {
    line(width / 2, height / 2 -80, width / 2 + 20, height / 2 -60);
  }
}

function gameOver() {
  // Display game over message
  textSize(16);
  if (guessedWord.indexOf('_') === -1) {
    text("You guessed the word!", width / 2, height / 2 + 60);
  } else {
    text("Game over! The word was " + word.join(''), width / 2, height / 2 + 60);
  }

  // Display new game prompt
  textSize(16);
  text("Press ENTER for a new game", width / 2, height/ 2 + 100);
}

the game:

Week 3 Assignment: Closer Look

The overall concept for this week’s assignment is that I wanted to portray what things look like in a closer look. The vibrating movements of various atoms and molecules based on the interactivity of the user is what i wanted to make. Based on mouse pressing and mouse dragging, there are different actions for each of them. If the mouse is pressed, a random shape subclass will be painted on the canvas, while if mouse is dragged, the background color, size changes and the shapes gain erratic movement. I used a parent class Shape and subclass for different shapes with move, display, and update methods. Although I encountered no visible problems, it was refreshing to make color and interactive artwork.

Shapes class Code:

class Shape {
  constructor(x, y, size, color) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.color = color;
    this.offsetX = random(-1, 1);
    this.offsetY = random(-1, 1);
  }
  
  display() {
    // Abstract method 
  }
  
  update(x, y) {
    // Abstract method 
  }
  
  move(){
    // Abstract method 
  }
}
//star subclass
class Star extends Shape {
  constructor(x, y) {
    super(x, y, random(20, 100), color(random(255), random(255), random(255), 100));
  }
  
  display() {
    fill(this.color);
    beginShape();
    for (let i = 0; i < 10; i++) {
      let angle = TWO_PI * i / 10;
      let r = this.size * (i % 2 === 0 ? 0.5 : 1);
      let x = this.x + cos(angle) * r;
      let y = this.y + sin(angle) * r;
      vertex(x, y);
    }
    endShape(CLOSE);
  }
  
  update(x, y) {
    let d = dist(this.x, this.y, x, y);
    this.size = map(d, 0, width, 20, 100);
  }
  
  move() {
    // Vibrate the molecule in place
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }
}

//diamond subclass
class Diamond extends Shape {
  constructor(x, y) {
    super(x, y, random(20, 100), color(random(255), random(255), random(255), 100));
  }
  
  display() {
    fill(this.color);
    beginShape();
    vertex(this.x, this.y - this.size / 2);
    vertex(this.x - this.size / 2, this.y);
    vertex(this.x, this.y + this.size / 2);
    vertex(this.x + this.size / 2, this.y);
    endShape(CLOSE);
  }
  
  update(x, y) {
    let d = dist(this.x, this.y, x, y);
    this.size = map(d, 0, width, 20, 100);
  }
  
  move() {
    // Vibrate the molecule in place
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }
}

//atom subclass
class Atom extends Shape {
  constructor(x, y) {
    super(x, y, random(20, 100), color(random(255), random(255), random(255), 100));
  }
  
  display() {
    fill(this.color);
    ellipse(this.x, this.y, this.size, this.size);
    fill(255);
    ellipse(this.x - this.size / 4, this.y - this.size / 4, this.size / 2, this.size / 2);
  }
  
  update(x, y) {
    let d = dist(this.x, this.y, x, y);
    this.size = map(d, 0, width, 20, 100);
  }
  
  move() {
    // Vibrate the molecule in place
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }
}

//molecule subclass
class Molecule extends Shape {
  constructor(x, y) {
    super(x, y, random(20, 100), color(random(255), random(255), random(255), 100));
  }
  
  display() {
    fill(this.color);
    ellipse(this.x, this.y, this.size, this.size);
    fill(255);
    ellipse(this.x - this.size / 4, this.y - this.size / 4, this.size / 2, this.size / 2);
    ellipse(this.x + this.size / 4, this.y + this.size / 4, this.size / 2, this.size / 2);
  }
  
  update(x, y) {
    let d = dist(this.x, this.y, x, y);
    this.size = map(d, 0, width, 20, 100);
  }
  
  move() {
    // Vibrate the molecule in place
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }
}

//water molecule subclass
class WaterMolecule extends Shape {
  constructor(x, y) {
    super(x, y, random(20, 100), color(0, 0, 255, 100)); // Blue color for water
  }
  
  display() {
    fill(this.color);
    ellipse(this.x, this.y - this.size / 4, this.size / 2, this.size / 2); // Oxygen atom
    fill(255);
    ellipse(this.x - this.size / 4, this.y + this.size / 4, this.size / 3, this.size / 3); // Hydrogen atom 1
    ellipse(this.x + this.size / 4, this.y + this.size / 4, this.size / 3, this.size / 3); // Hydrogen atom 2
  }
  
  update(x, y) {
    let d = dist(this.x, this.y, x, y);
    this.size = map(d, 0, width, 20, 100);
  }
  
  move() {
    // Vibrate the molecule in place
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }
}

//Co2 subclass
class CarbonDioxideMolecule extends Shape {
  constructor(x, y) {
    super(x, y, random(20, 100), color(255, 0, 0, 100)); // Red color for carbon dioxide
  }
  
  display() {
    fill(this.color);
    ellipse(this.x, this.y - this.size / 4, this.size / 2, this.size / 2); // Carbon atom
    fill(255);
    ellipse(this.x - this.size / 3, this.y + this.size / 4, this.size / 3, this.size / 3); // Oxygen atom 1
    ellipse(this.x + this.size / 3, this.y + this.size / 4, this.size / 3, this.size / 3); // Oxygen atom 
  }
  
  update(x, y) {
    let d = dist(this.x, this.y, x, y);
    this.size = map(d, 0, width, 20, 100);
  }
  
  move() {
    // Vibrate the molecule in place
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }

}