Final Project – Jihad Jammal

P5.js Code:

let fsrVal = 0;  // Force Sensitive Resistor Value
let smoothfsrVal = 0; // Global Variable to not have jitter for image 

let backgroundImage;  // Classroom Image
let teachImageHappy;  // Play state teacher Image
let teachImageMad;    // Win State teacher Image
let teachImageProud // Lose State teacher Image

let gameStarted = false;  // Flag for Game Start 
let gameOver = false;     // Flag for Game Over
let gameWon = false;      // Flag for Game won
let gameStartTime;  // Variable for timer
let dogBarkSound; // Variable for Dog barking 
let barkTimeout; // Variable for when the dog cannot bark 
let lastBarkTime = 0; // Variable to hold when dog stopped barking
let winSound; // Variable to hold the win sound
let gameOverSound; // Variable to hold the game over sound
let winSoundPlayed = false; // Variable to track if win sound has been played
let gameOverSoundPlayed = false; // Variable to track if game over sound has been played
let gameMusic; // Variable to hold the game music sound
let gameMusicPlayed = false; // Variable to track if game music has been played
let showingInstructions = false; // Flag to track if we are currently showing instructions

// It is necessary to preload the images in 
function preload() {
    backgroundImage = loadImage('class.jpeg');  
  
    teachImageHappy = loadImage('teacher_woman_happy.png');  
  
    teachImageMad = loadImage('teacher_woman_mad.png');  
  
    teachImageProud = loadImage("teacher_woman_teaching.png")
    dogBarkSound = loadSound('dog_bark.mp3');  
  
    winSound = loadSound('win.mp3'); 
  
    gameOverSound = loadSound('gameover.mp3');  
  
    gameMusic = loadSound('gameMusic.mp3'); 
}

function setup() {
    createCanvas(window.innerWidth, window.innerHeight);
    textSize(18);

    // Serial Point button logic
    const connectButton = createButton('Connect to Serial');
    connectButton.position(width / 2 - connectButton.width / 2, height / 2 - connectButton.height / 2);
    connectButton.mousePressed(setUpSerial);


    // Play button logic
    const playButton = createButton('Play');
    playButton.position(width / 2 - playButton.width / 2-15, height / 2 - playButton.height / 2);
    playButton.mousePressed(startGame);
    playButton.hide();
    styleButton(playButton);

    // Instruction button logic
    const instructionsButton = createButton('Instructions');
    instructionsButton.position(width / 2 - instructionsButton.width / 2 -20, height / 2 +40);
    instructionsButton.mousePressed(displayInstructions);
    instructionsButton.hide();
    styleButton(instructionsButton);

    // Restart button logic
    const restartButton = createButton('Restart Game');
    restartButton.position(width / 2 - restartButton.width / 2 -25, height / 2 +15);  // Positioned below the "Play" button
    restartButton.mousePressed(restartGame);
    restartButton.hide();
    styleButton(restartButton);
  
    // Main Menu button logic 
    const mainMenuButton = createButton('Main Menu');
    mainMenuButton.position(width / 2 - mainMenuButton.width / 2 -25, height / 2 + 75);
    mainMenuButton.mousePressed(goToMainMenu);
    mainMenuButton.hide();
    styleButton(mainMenuButton);

    // Button branding for further use
    window.connectButton = connectButton;
    window.playButton = playButton;
    window.instructionsButton = instructionsButton;
    window.restartButton = restartButton;
    window.mainMenuButton = mainMenuButton;


    // Background game music was intially too loud
    gameMusic.setVolume(0.035); 

    noLoop();  // Stop drawing until the game starts
}

// Buttons needed to be style 
function styleButton(button) {
    button.style('background-color', '#FFFFFF'); // White background
    button.style('color', '#000000'); // Black text
    button.style('border', '2px solid #000000'); // Black border
    button.style('padding', '10px 20px'); // Larger padding for bigger size
    button.style('font-size', '16px'); // Larger font size
    button.style('cursor', 'pointer'); // Cursor pointer on hover
}

function draw() {
    if (serialActive) {
      // After connection I prefer the button to no longer be present
        window.connectButton.hide(); 

        if (showingInstructions) {
            // Instruction state needed these buttons hidden
            window.playButton.hide();
            window.instructionsButton.hide();
        } else {
            window.playButton.show();    //If not in instruction state the play button can be shown 
            window.instructionsButton.show(); // And the instructions button can be shown
        }
        // button logic/visibility during/post-game
        if (gameStarted && !gameOver && !gameWon) {
            window.playButton.hide();
            window.instructionsButton.hide();
            updateGame();
        } else if (gameOver) {
            displayGameOver();
        } else if (gameWon) {
            displayGameWin();
        }
    } else {
        displayClassCrashOutScreen();
    }
}



function updateGame() {
    // Tracking time logic (CHATGPT USED TO HELP SET THIS UP)
    let elapsedTime = (millis() - gameStartTime) / 1000;  
  
    // Start playing game music when the game starts
    if (!gameMusicPlayed && gameStarted) {
        gameMusic.play();
        gameMusic.loop(); // if game music ends early loop it 
        gameMusicPlayed = true; // Set the flag to true after playing the music
    }

    // Stop game music when the game ends
    if ((gameOver || gameWon) && gameMusic.isPlaying()) {
        gameMusic.stop();
    }
  
    // Check win condition (CHATGPT WAS USED)
    if (fsrVal >= 250 && !gameWon) {
        gameWon = true;
        dogBarkSound.stop(); // Stop the dog bark sound if it's playing
        winTime = elapsedTime; // Record the time taken to win
    }

    // Check game over condition (CHATGPT WAS USED)
    if (elapsedTime >= 45) {
        gameOver = true;
        dogBarkSound.stop(); // Stop the dog bark sound if it's playing
        return;
    }

    background(backgroundImage);  // Set the loaded background image
    displayGameElements(elapsedTime);
}

// Code credit to Professor AARON SHERWOOD (Thank you for your help professor)
function displayGameElements(elapsedTime) {
    scaleFactor = 1;
    smoothfsrVal += (fsrVal - smoothfsrVal) * 0.01;
    push();
    imageMode(CENTER);
    let teachWidth = (teachImageHappy.width / 2) + smoothfsrVal * scaleFactor;
    let teachHeight = (teachImageHappy.height / 2) + smoothfsrVal * scaleFactor;
    image(teachImageHappy, width / 2, height / 2, teachWidth, teachHeight);
    pop();

    fill(255);
    textStyle(BOLD)
    stroke(0)
    strokeWeight(4)
    text("Connected", 90, 30);
    text('Pages = ' + fsrVal, 100, 70 );
    textSize(30);
    text('Time: ' + elapsedTime.toFixed(2) + 's', width - 150, 30);
}

function displayGameOver() {
    stopBarking();
    background(backgroundImage);
    fill(255);
    textSize(27);
    text("Game Over", width / 2, height / 2 - 45);
    textSize(22);
    text("Teacher's Pet :(", width / 2, height / 2 - 5);
    //code to indicate which buttons to hide and show 
    window.restartButton.show();
    window.playButton.hide();
    window.mainMenuButton.show(); 
    window.instructionsButton.hide();

    // Teacher Image scaling and position
    let scaledWidth = teachImageProud.width * 0.5;
    let scaledHeight = teachImageProud.height * 0.5;
    image(teachImageProud, width / 2 + 130, height / 2 - 125, scaledWidth, scaledHeight);


    if (!gameOverSoundPlayed && !gameOverSound.isPlaying()) {
        gameOverSound.play();
        gameOverSoundPlayed = true; 
    }

    if (gameMusic.isPlaying()) {
        gameMusic.stop();
    }
}

function displayGameWin() {
    stopBarking();
    background(backgroundImage);
    fill(255);  
    textSize(27);
    text("You Got Detention!!!", width / 2, height / 2 - 45);
    textSize(22);
    // Display the time taken to win
    text("Time Taken: " + winTime.toFixed(2) + "s", width / 2, height / 2 - 5);
    
    // Teacher Image scaling and position
    let scaledWidth = teachImageMad.width * 0.5;
    let scaledHeight = teachImageMad.height * 0.5;
    image(teachImageMad, width / 2 + 130, height / 2 - 125, scaledWidth, scaledHeight);
  
    //code to indicate which buttons to hide and show 
    window.restartButton.show();
    window.playButton.hide();
    window.mainMenuButton.show(); 
    window.instructionsButton.hide()


    if (!winSoundPlayed && !winSound.isPlaying()) {
        winSound.play();
        winSoundPlayed = true;
      
    }

    if (gameMusic.isPlaying()) {
        gameMusic.stop();
    }
}

function displayClassCrashOutScreen() {
    background(backgroundImage);
    fill(255);
    stroke(0)
    strokeWeight(4)
    textStyle(BOLD)
    textAlign(CENTER);
    textSize(27)
    text("CLASS CRASH OUT", width / 2, height / 2 - 35);
}

// Play Through Logic (CHATGPT WAS USED)
function startGame() {
    gameStarted = true;
    gameOver = false;  
    gameWon = false;   
    gameStartTime = millis();  
    gameMusicPlayed = false; 
    showingInstructions = false; 
    playDogBark(); 
}

function restartGame() {
    gameStarted = true;
    gameOver = false;  
    gameWon = false;   
    fsrVal = 0;        
    smoothfsrVal = 0;  
    gameStartTime = millis();  
    window.restartButton.hide();  
    window.mainMenuButton.hide();
    stopBarking(); 
    gameMusicPlayed = false; 
    winSoundPlayed = false;  
    gameOverSoundPlayed = false;  
  
    playDogBark(); 
    loop();  
}

function goToMainMenu() {
    stopBarking();
    gameStarted = false;
    gameOver = false;
    gameWon = false;
    gameMusic.stop(); 
    gameMusicPlayed = false;
    winSoundPlayed = false;
    gameOverSoundPlayed = false;
    showingInstructions = false; 

    stopBarking(); 
    
    loop(); 
  //code to indicate which buttons to hide and show 
    window.restartButton.hide();
    window.mainMenuButton.hide();
    window.playButton.show();
    window.connectButton.show(); 
   
    background(backgroundImage); 
    fill(255);
    textStyle(BOLD)
    textAlign(CENTER);
    textSize(27)
    text("CLASS CRASH OUT", width / 2, height / 2 - 35); 
}


function displayInstructions() {
    background(backgroundImage);
    fill(255);
    textSize(27);
    textAlign(CENTER, CENTER);
    text("Your objective: Prank your friend", width / 2, height / 2 -75); 
  text("Time Limit: 45 seconds", width/2, height/2 -35)
  text("Feed the dog 250 HW pages", width/2, height/2)

    //code to indicate which buttons to hide and show 
    window.mainMenuButton.show();

    
    window.playButton.hide();
    window.instructionsButton.hide(); 
    window.restartButton.hide();

    showingInstructions = true; 
}

// Dog bark Logic 
function playDogBark() {
    dogBarkSound.play();
    // Dog barks at random intervals
    let nextBarkIn = random(5000, 7500); 
    barkTimeout = setTimeout(playDogBark, nextBarkIn); // Schedule the next bark
}

function stopBarking() {
    clearTimeout(barkTimeout); 
}


// This function will be called by the web-serial library
// with each new *line* of data. The serial library reads
// the data until the newline and then gives it to us through
// this callback function
function readSerial(data) {
  ////////////////////////////////////
  //READ FROM ARDUINO HERE
  ////////////////////////////////////

  if (data != null) {
    // make sure there is actually a message
    // split the message
    let fromArduino = split(trim(data), ",");
    // if the right length, then proceed
    if (fromArduino.length == 1) {
      // only store values here
      // do everything with those values in the main draw loop
      
      // We take the string we get from Arduino and explicitly
      // convert it to a number by using int()
      // e.g. "103" becomes 103
      fsrVal = int(fromArduino[0]);
    
    }

    //////////////////////////////////
    //SEND TO ARDUINO HERE (handshake)
    //////////////////////////////////
    let sendToArduino = 0 + "\n";
    writeSerial(sendToArduino);
  }
}

Concept:

My final project concept initially centered on creating a controller for my midterm video game project. However, after a discussion with my professor, I was inspired to shift towards a design imbued with deeper thematic meaning and enhanced interactivity. This push led me to thoroughly repackage and rework my midterm project. Through multiple iterations, I developed a concept that stands distinctly apart from its predecessor. In this new version, players engage in a real-world task—feeding a dog—which in turn affects the game by enlarging the teacher on screen. This innovative interaction model is something I am proud to call largely original and distinct from my previous work.”

Include some pictures / video of your project interaction

*Disclaimer had trouble uploading images so I compiled images into a youtube video

How does the implementation work?

In implementing my project concept using Arduino and p5.js, I utilized the lab’s resources to construct a Force Sensitive Resistor (FSR). This involved using Velostat, a folded piece of paper, two strips of copper tape, and ordinary tape. Once assembled, I connected the FSR to the Arduino using crocodile clips attached to jumper cables. For the visual component, I crafted the “dog” from the SparkFun kit box, using three cardboard pieces (two triangles and one rectangle) to form its structure, and added a cartoon dog’s face for a playful touch. The ‘HW’ blocks, integral to the game’s interactivity, were made from wooden blocks wrapped in paper and secured with tape.

Description of interaction design

For the interactivity aspect of my project, under Professor Aaron’s guidance, I established a serial connection enabling the Force Sensitive Resistor (FSR) to communicate with my p5.js sketch. The interface in p5.js features an image of a cartoon teacher that increases in size as the FSR value rises. To address the issue of the image size increasing too rapidly, I introduced a global variable, smoothFsrVal, and applied the formula smoothFsrVal += (fsrVal - smoothFsrVal) * 0.01 to moderate the growth. To ensure the game remained engaging and not overly prolonged, I set a specific FSR value goal of 250, which, when reached, triggers a win state. Additionally, a timer limits the gameplay to 45 seconds, after which a game over state is activated if the goal isn’t met. The p5.js sketch also includes standard interactive elements such as a ‘Connect to Serial’ button, main menu, play, instructions, and restart buttons—all designed with engaging graphics and set against a classroom-themed background

Arduino Code:

void setup() {
  // Start serial communication so we can send data
  // over the USB connection to our p5js sketch
  Serial.begin(9600); 

  // Blink them so we can check the wiring


  // start the handshake
  while (Serial.available() <= 0) {
    Serial.println("0");

    delay(50);
  }
}

void loop() {
  // wait for data from p5 before doing something
  while (Serial.available()) {

    int handshakeRead = Serial.parseInt();
   
    if (Serial.read() == '\n') {

      int sensor = analogRead(A0);
      delay(5);

      Serial.println(sensor);
    }
  }

}

Description of Arduino code:

In the setup function of the Arduino code, serial communication is initiated at 9600 baud to enable data transfer over the USB connection to the p5.js sketch. This setup includes a procedure introduced in class by Professor Aaron called starting a ‘handshake’—a method used to ensure that the connection is established before proceeding. The Arduino sends a zero (‘0’) repeatedly every 50 milliseconds until it receives a response from the p5.js sketch, indicating that the serial connection is ready. In the main loop, the code continuously checks for incoming data from the p5.js sketch. Once data is received, it reads the data to complete the ‘handshake’, ensuring that each transmission begins only after the previous has been fully processed. It then reads the analog value from pin A0, where the Force Sensitive Resistor (FSR) is connected. This sensor value is briefly paused (a delay of 5 milliseconds is introduced for stability), and then sent back over the serial connection to the p5.js sketch, which uses this data to influence the game dynamics, such as adjusting the size of the cartoon teacher’s image based on the FSR readings

Embedded Sketch:

 

Description of p5.js code:

  1. Initialization and Preloading: Variables are declared for game state management (like gameStarted, gameOver, gameWon), user interface elements (buttons), sounds, and images. The preload() function loads these resources (images and sounds) to ensure they’re available before the game starts.
  2. Setup Configuration: The setup() function creates the game canvas and initializes interface elements such as buttons. Each button is positioned and styled, and their visibility is managed based on game states. Notably, the game music’s volume is adjusted, and the canvas’s draw loop is paused until the game starts.
  3. Game State Management: Buttons trigger changes in game states. For example, the ‘Play’ button starts the game and triggers gameplay logic encapsulated within other functions like startGame(). Buttons like ‘Restart’ and ‘Main Menu’ facilitate game flow by resetting states or navigating the user interface.
  4. Dynamic Content Rendering: The draw() function acts as the central loop where game logic is continuously checked and updated based on the game’s state. It manages what is displayed on the screen, updates gameplay elements like the timer, and reacts to changes in game state (e.g., transitioning to a win or lose screen).
  5. Game Interactivity and Feedback: Interaction with the physical hardware (FSR value) is integrated into the game logic. The value from the sensor influences the gameplay, affecting visual elements like the teacher’s image size based on the smoothed sensor values. Audio cues are played corresponding to game events like winning or losing, and game music loops during gameplay.
  6. Auxiliary Functions: Functions like displayGameOver() and displayGameWin() manage the display elements during these states, showing appropriate messages and images, and managing audio playback. Utility functions like styleButton() apply consistent styling to buttons across the game.
  7. Serial Communication: The readSerial(data) function handles incoming data from the Arduino. It parses this data to update the force sensor value, which in turn affects the game logic and visuals.

Description of communication between Arduino and p5.js:

If the paragraphs mentioned above do not paint a clear enough picture here is the bullet point representation on how my Final project is communicating between p5.js and Arduino

Part 1:
  1. Arduino Setup:
    • The Arduino initiates serial communication at 9600 baud rate using Serial.begin(9600);. This sets up the Arduino to send and receive data over the USB connection to the computer where the p5.js script runs.
    • A handshake mechanism is implemented in the setup() function where the Arduino continually sends a zero (‘0’) until it receives any serial data from p5.js, ensuring that both sides are ready to communicate before proceeding.
  2. p5.js Setup:
    • In p5.js, the serial connection setup is implied within functions like setUpSerial(), which would be responsible for establishing this link, although the specific implementation details aren’t provided in the snippet. The script is prepared to handle incoming data through a callback function that processes each line of data received.
Part 2:
  1. Data Sending (Arduino to p5.js):
    • Inside the loop() function on the Arduino, there’s a check for any available serial data (Serial.available()). If data is available, it reads the next integer from the serial buffer, which is part of the handshake or command from p5.js.
    • After the handshake is confirmed (a newline character is detected), the Arduino reads an analog value from pin A0 (connected to the Force Sensitive Resistor) and sends this value back to p5.js using Serial.println(sensor);.
  2. Data Receiving and Sending (p5.js to Arduino):
    • In p5.js, the received data is handled by the readSerial(data) function. This function parses incoming serial data to update the force sensor value (fsrVal), which is then used within the game logic to modify game elements, such as the size of the teacher image in the interface.
    • The script also sends data back to Arduino, likely as part of a continual handshake or control commands, maintaining synchronization between the hardware inputs and the software responses.
Part 3:
  • Game Element Updates: The fsrVal from the Arduino directly impacts game dynamics. For example, an increase in the FSR value causes the teacher image to grow in size, visually representing the game’s progress based on real-world actions (like pressing the FSR).
  • Dynamic Adjustments: The smoothfsrVal variable in p5.js smooths out the rapid changes in the sensor value to ensure the game’s visual feedback doesn’t appear jittery or overly responsive to noise in sensor readings.

What are some aspects of the project that you’re particularly proud of?

I’m particularly proud of the DIY Force Sensitive Resistor (FSR) sensor that I constructed for this project. Building the primary component of my project from scratch, using only the resources available in the lab and guidance from various YouTube tutorials, was immensely fulfilling. There was no pre-built FSR sensor available that fit my needs, which presented a significant challenge. Tackling this obstacle head-on, I was able to problem-solve and innovate under pressure. This not only enhanced my technical skills but also boosted my confidence in handling and overcoming complex engineering problems on my own. The successful integration of this self-made sensor into the project stands as a testament to the creative and technical prowess that I developed throughout this endeavor.

What are some areas for future improvement?

One of the primary areas for future improvement in my project is the gameplay loop. While it successfully fulfills its basic purpose, it currently lacks sustained entertainment value. Introducing more sound effects and enhanced user feedback could significantly enrich the gaming experience, making it more engaging and dynamic for players. Additionally, the build quality of the interactive controller needs reinforcement. Given that the gameplay involves objects frequently being thrown at the controller, constructing a sturdier framework is essential—especially since the dog’s face component is particularly vulnerable. Another critical area for improvement is the sensitivity of the FSR value. Currently, balancing the sensor’s responsiveness so that it is neither too sensitive nor too unresponsive is a significant challenge. This aspect of the project requires a deeper understanding and more refined coding skills, but I am confident that with time and continued learning, I can develop a more robust and precise response mechanism for a better gameplay experience.

Final Project User Testing – Jihad Jammal

The journey of transforming a concept into a tangible, functional reality is an exhilarating experience, with challenges and discoveries at every turn. The most enjoyable part of this adventure for me was definitely the user-testing phase of my final project. It’s one thing to nurture an idea in your mind or sketch it on paper, but watching real people interact with your creation adds a layer of excitement and invaluable insights.

A significant hurdle I faced was with the servos intended to be a key component of the project. Despite my efforts, I struggled immensely with integrating and programming them. The complexity proved to be beyond the scope of what could be managed within the time and resource constraints of the project I had to make the difficult decision to pivot and remove the servos entirely from the project. This decision, though tough, was necessary to maintain the project’s viability and ensure a smoother user experience.

Pivoting away from using servos forced me to rethink and simplify the design, focusing on what was most essential and functional. This redesign, though less complex, brought its own set of challenges and learning opportunities.

The insights gained from user-testing were invaluable. Observing how users interacted with the revised version of the project without the servos helped me understand the practicality and user-friendliness of my design. The feedback was instrumental in shaping the final tweaks:

Timer needs to be bigger: Users found the timer too small, highlighting the need for a more visible and accessible design. (Alongside that I believe I will increase the size of all text)
Add instructions page: User suggested that there be an instructions page to clarify the objective
Fix dog barking glitch: Dog barking would play over itself causing an awkward sound (potential solution is to increase the delay time between sounds

Week 12 Reading – Jihad Jammal

The reading offers a profound examination of the role design plays in the realm of disability, challenging the conventional perception that design for disability must focus solely on functionality. The discussion centers around the transformative potential of integrating aesthetic and cultural elements into the design of disability aids, proposing that these elements are not merely supplementary but integral to redefining these aids within broader societal contexts.

Historical examples, such as Charles and Ray Eames’s plywood leg splints, serve as a foundation for arguing that design constraints related to disability can catalyze broader innovations in design practice. The Eames’s ability to transform a functional object like a leg splint into a design that influenced their later iconic furniture pieces illustrates how solutions born out of necessity can transcend their origins to impact broader design disciplines. This notion is further reinforced through the transformation of eyewear from a stigmatized medical necessity into a fashionable accessory, which underscores the potential for disability aids to evolve beyond their functional inception towards cultural significance.

However, this integration of aesthetics raises questions about the balance between form and function, reflecting a potential bias towards design that may overlook practical user needs like accessibility and affordability. While the reading persuasively invites a rethinking of disability aids as elements of personal identity and expression, it also prompts critical reflections on ensuring these designs remain accessible and practical. The challenge lies in achieving a harmonious integration where design innovations in the disability sector do not compromise on functionality, ensuring that these aids are not only culturally resonant but also remain true to their primary purpose of serving the needs of the disabled community.

Final Proposal_Week_12 – Jihad Jammal

Final Proposal for End of Semester Project

Instead of a  joystick-controlled P5.js game, this project will have a slight twist with what can be considered a “joystick” by using a physical device shaped like a “clam”, which will interact with a digital environment displayed via P5.js. The core idea is to gamify the task of throwing wooden blocks (metaphorically representing tasks or challenges) into the clam, with the difficulty and visual feedback varying according to the intensity of the interaction.

Design and Functionality of the Arduino Setup

Inputs:

The Arduino will be equipped with pressure sensors embedded in the clam-like contraption. These sensors will detect the force exerted by the wooden blocks thrown into the “clam”. The primary input for the Arduino will thus be the varying pressure from these blocks.

Outputs:

The Arduino will control a motor mechanism responsible for opening and closing the “clam”. The speed at which the “clam” opens and closes will be directly proportional to the pressure sensed by the sensors – more pressure will result in faster movement.

Interaction with P5.js:

The Arduino will send data to the P5.js program indicating the current pressure level detected by the sensors. This will inform the P5.js application about how quickly to adjust the visuals accordingly.

Design and Functionality of the P5.js Program

Inputs:

The P5.js program will receive data from the Arduino about the pressure levels. This input will determine the rate at which the in-game visual elements change.

Outputs:

The main output of the P5.js program will be the visual representation on the screen. The size of a dog character in the game will increase as more pressure is applied to the “clam” sensors. This size increment and the speed of the “clam’s” movements will serve as visual feedback to the player, creating a dynamic gaming experience.

Interaction with Arduino:

Apart from receiving pressure data from the Arduino, the P5.js program will also reset all functions (i.e. “clam” speed, size of the dog) on the Arduino and the sketch  once the game is over and the limit of not send any information back to the Arduino.

Conclusion

By integrating robust physical components with dynamic digital responses, the game not only becomes more engaging but also introduces a novel method of interaction in digital gaming environments. Through user testing and iterative design, this project will evolve into an innovative and enjoyable experience for users, showcasing the potential of hybrid physical-digital interaction platforms.

Week 11 Reading – Jihad Jammal

Reflecting on the author’s critique of what is dubbed “Pictures Under Glass,” I find a compelling challenge to our current acceptance of interface norms. The disparity highlighted between the tactile richness of our everyday physical interactions and the simplified, touch-based interfaces that dominate our devices urges us to question whether we are curbing our innovative potential. By adhering so strictly to touchscreen technology, we risk neglecting developments in interfaces that could better harness human physicality and sensory feedback.

This critique serves as a springboard for considering alternative interaction paradigms that prioritize enhancing our sensory and physical engagement with technology. While touchscreens undoubtedly provide accessibility and ease, there’s a significant opportunity to explore more immersive and intuitive interfaces. Such technologies would not only extend our capabilities but also deepen our interaction with the digital world, suggesting a future where technology complements rather than constrains our interactions with our environment. This shift could pave the way for more meaningful and natural user experiences that align closely with human behavior and physicality.

Arduino-Powered Joystick Controller Concept

The project’s primary goal is to design and construct a custom joystick game controller using Arduino. This controller will enhance player interaction with a browser-based video game developed in p5.js, offering a more intuitive and engaging gameplay experience compared to standard keyboard or mouse controls.

Controller Features:
  1. Joystick for Directional Control:
    • The joystick will allow players to control movement within the game with greater precision and fluidity. It will capture analog input to provide a smoother response compared to digital keys.
  2. Tactile Feedback Buttons:
    • Additional buttons will be incorporated for game-specific actions (e.g., jumping, shooting). These will use tactile switches to give a satisfying click feel, ensuring immediate and comfortable response.
  3. Vibration Feedback:
    • Incorporate vibration motors that activate during specific game events, such as collisions or other significant interactions, to provide physical feedback that enhances the immersion.
  4. LED Feedback System:
    • LEDs will be programmed to react to different situations in the game, such as game alerts, low health, or achievement notifications, adding another layer of feedback and interaction.
Technical Components:
  • Arduino Board: Acts as the central processing unit for the joystick controller, reading inputs from the joystick and buttons, and managing outputs like LED indicators and vibration motors.
  • Analog Joystick Module: Captures detailed directional inputs from the player, translating them into game movements.
  • Vibration Motors: To provide immediate tactile feedback during critical game events, enhancing the physical experience of the gameplay

Week 11_Music – Saeed, Khalifa, Jihad

Concept:

The concept of this project was to create a mini drum pad, or what is equivalent to one, with the hardware we have available. The device would use buttons to trigger different buzzer sounds, mimicking the functionality of a traditional drum pad. Each button on the device would correspond to a different sound, with the frequency of these sounds adjustable via a potentiometer. This allows the user to modify the pitch of the tones.

Code:

// Defining pins assignments for buttons and buzzers
const int buttonPin1 = 2;
const int buttonPin2 = 3;
const int buttonPin3 = 4;
// Coded with the Aid of ChatGPT
const int buttonPin4 = 5; // Monitoring and playbacks button
// Coded with the Aid of ChatGPT
const int buzzerPin1 = 8;
const int buzzerPin2 = 9;
const int buzzerPin3 = 10;
const int potPin = A0; // Potentiometer connected to A0 for frequency control

// Variables to manage button states and debounce timing
int buttonState1 = 0;
int lastButtonState1 = 0;
int buttonState2 = 0;
int lastButtonState2 = 0;
int buttonState3 = 0;
int lastButtonState3 = 0;
int buttonState4 = 0;
int lastButtonState4 = 0;

unsigned long lastDebounceTime1 = 0;
unsigned long lastDebounceTime2 = 0;
unsigned long lastDebounceTime3 = 0;
unsigned long lastDebounceTime4 = 0;
unsigned long debounceDelay = 50; // Debounce delay in milliseconds

// Struct to hold buzzer activation data including the pin and frequency
struct BuzzerAction {
  int buzzerPin;
  int frequency;
};

// Coded with the Aid of ChatGPT
BuzzerAction record[100]; // Array to store each buzzer activation
int recordIndex = 0; // Index for recording array
//Coded with the Aid of ChatGPT

void setup() {
  // Initialize all button and buzzer pins
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
// Coded with the Aid of ChatGPT
  pinMode(buttonPin4, INPUT);
// Coded with the Aid of ChatGPT
  pinMode(buzzerPin1, OUTPUT);
  pinMode(buzzerPin2, OUTPUT);
  pinMode(buzzerPin3, OUTPUT);
  pinMode(potPin, INPUT); // Setups potentiometer pin as input
}

void loop() {
  // Reads current state of buttons
  int reading1 = digitalRead(buttonPin1);
  int reading2 = digitalRead(buttonPin2);
  int reading3 = digitalRead(buttonPin3);
// Coded with the Aid of ChatGPT
  int reading4 = digitalRead(buttonPin4);
// Coded with the Aid of ChatGPT
  int potValue = analogRead(potPin); // Reads potentiometer value
  int frequency = map(potValue, 0, 1023, 200, 2000); // Maps potentiometer value to frequency range

  // Handle button 1 press and recording
  debounceAndRecord(reading1, &lastButtonState1, &buttonState1, &lastDebounceTime1, buzzerPin1, frequency);

  // Handle button 2 press and recording
  debounceAndRecord(reading2, &lastButtonState2, &buttonState2, &lastDebounceTime2, buzzerPin2, frequency);

  // Handle button 3 press and recording
  debounceAndRecord(reading3, &lastButtonState3, &buttonState3, &lastDebounceTime3, buzzerPin3, frequency);

  // Handles button 4 for playback
  if (reading4 != lastButtonState4) {
    lastDebounceTime4 = millis();
  }
  if ((millis() - lastDebounceTime4) > debounceDelay) {
    if (reading4 != buttonState4) {
      buttonState4 = reading4;
      if (buttonState4 == HIGH) {
        for (int i = 0; i < recordIndex; i++) {
          // Play each recorded buzzer action with the specific frequency recorded
          tone(record[i].buzzerPin, record[i].frequency, 200);
          delay(250); // Short delay between each buzzer action for clarity
        }
        recordIndex = 0; // Resets record index after playback
      }
    }
  }

  // Update last button states for next loop iteration
  lastButtonState1 = reading1;
  lastButtonState2 = reading2;
  lastButtonState3 = reading3;
  lastButtonState4 = reading4;
}
// Coded with the Aid of ChatGPT
// Function to handle button debouncing and recording buzzer actions
void debounceAndRecord(int reading, int *lastButtonState, int *buttonState, unsigned long *lastDebounceTime, int buzzerPin, int frequency) {
  if (reading != *lastButtonState) {
    *lastDebounceTime = millis(); // Reset debounce timer
  }
  if ((millis() - *lastDebounceTime) > debounceDelay) {
    if (reading != *buttonState) {
      *buttonState = reading; // Updates button state
      if (*buttonState == HIGH && recordIndex < sizeof(record) / sizeof(record[0])) {
        record[recordIndex++] = {buzzerPin, frequency}; // Records the buzzer activation
        tone(buzzerPin, frequency, 200); // Plays buzzer at recorded frequency
      }
    }
  }
  *lastButtonState = reading; // Updates last button state for debouncing
// Coded with the Aid of ChatGPT
}

 

Hardware Configuration: The system is designed with four button inputs and three buzzer outputs. Additionally, a potentiometer is used to control the frequency of the buzzer sounds.

Button Functionality: Buttons 1 to 3 are connected to buzzers and are responsible for triggering sounds with variable frequencies determined by the potentiometer. Button 4 is designated for playback. It plays back a sequence of sounds that have been recorded based on earlier interactions with buttons 1 to 3.

Frequency Control: The frequency of the sounds is dynamically adjusted using a potentiometer. The analog value from the potentiometer is mapped to a specified frequency range (200 Hz to 2000 Hz), which determines how the buzzers sound.

Debouncing: To ensure reliable button press detection without noise interference, the code implements debouncing logic. This involves measuring the time since the last button state change and updating the state only if this interval exceeds a predefined threshold (50 milliseconds).

Recording and Playback (Aided by Chatgpt)

Recording: When a button (1 to 3) is pressed, the action (which buzzer is activated and at what frequency) is recorded in an array. This includes storing both the pin of the buzzer and the frequency at which it was activated.

Playback: When button 4 is pressed, the system iterates over the recorded actions and plays them sequentially. Each action triggers the corresponding buzzer to sound at the recorded frequency for a short duration.

Loop and Functions : The main loop continuously checks the state of each button and the potentiometer, updating the frequency accordingly. A helper function, debounceAndRecord, is used to handle the logic for both debouncing and recording the buzzer actions associated with each button press.

 

Video of Project:

Reflection and ideas for future work or improvements:

Integrating a small display screen would significantly improve its functionality, further enhancing the project. This screen would provide real-time visual feedback on button presses and frequency outputs, allow users to scroll through and select different sounds or presets, and serve as a simple interface for directly programming the device. The potential for further development and refinement holds exciting prospects. The integration of a display screen and the addition of more customizable buttons are immediate steps that will enhance the device’s usability and versatility. Further innovations could include wireless connectivity for easy integration with other music production software or the addition of sensors
to enable gesture-based controls, which would offer an even more dynamic and immersive user experience. Several key insights stand out after reflecting on what this project has taught us. First, the practical challenges of hardware interfacing taught us the importance of robust design and a
solid plan for creating it. There is also a need for effective wire management and physical housing to enhance device durability and aesthetics.

Week 10: Analog/Digital – Jihad Jammal

Concept:

For this Arduino class project, I set out to create a straightforward yet multifunctional night light. The design includes an automatic feature where the light adjusts its brightness based on the room’s lighting conditions, ensuring the perfect level of illumination at all times. Additionally, it features a manual override button that allows users to adjust the brightness to their preference through a different LED at any moment.

A highlight of some code that you’re particularly proud of:

const int lightSensorPin = A0; 
const int buttonPin = 2;
const int redLED = 8;         // Red LED on digital pin 8 for on/off control
const int yellowLED = 9;      // Yellow LED on digital pin 9 for analog control
const int lightThreshold = 500;  // Light level threshold for the yellow LED
int lastButtonState = HIGH;
bool redLEDState = LOW;

void setup() {
  pinMode(lightSensorPin, INPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(redLED, OUTPUT);
  pinMode(yellowLED, OUTPUT);
}

void loop() {
  int lightLevel = analogRead(lightSensorPin);
  int buttonState = digitalRead(buttonPin);

  // Button controls the red LED
  if (buttonState == LOW && lastButtonState == HIGH) {
    // Toggle the red LED state
    redLEDState = !redLEDState;
    digitalWrite(redLED, redLEDState); // Set the red LED according to the toggled state
    delay(50); // Debounce delay
  }

  // Light sensor controls the yellow LED
  if(lightLevel < lightThreshold) {
    // If it's dark, set the yellow LED to a brightness proportional to the darkness
    int brightness = map(lightLevel, 0, lightThreshold, 255, 0); 
    analogWrite(yellowLED, brightness);
  } else {
    // If it's light, turn off the yellow LED
    analogWrite(yellowLED, 0);
  }

  // Update last button state
  lastButtonState = buttonState;
}

 

Video of Project:

Reflection and ideas for future work or improvements:

Reflecting on this Arduino night light project, I initially hoped to make the visual structure more intriguing and implement the design in a more creative way. However, I’ve come to realize that I’m still in the process of getting comfortable with the actual wiring and coding aspects of the project, which consumed the majority of my time. Despite these challenges, I’m proud of the work I’ve accomplished. If I had more time to devote to this project, I would focus on better integrating the button’s functionality with the light sensor to create a more seamless interaction between user input and the device’s automatic responses. In the future, I aim to explore more sophisticated design and programming techniques that could enhance both the aesthetic and functional elements of projects like this, ensuring they are not only practical but also visually appealing.

Week 10 Reading Response – Jihad Jammal

Jihad Jammal

Intro to IM

Professor Aaron Sherwood

Reading Reflection Week 10

April. 15, 2024

 

 

Re-evaluating Creativity

 

Tom Igoe’s perspectives on physical computing and interactive art present a compelling reevaluation of how creativity is often framed, particularly the expectation of producing entirely novel works. He argues persuasively for the value of revisiting and reinterpreting existing themes, thus challenging the traditional pursuit of absolute novelty in both art and technology. This approach strikes me as both practical and liberating, suggesting that innovation can flow from iteration—a continuous dialogue with established ideas—rather than emerging ex nihilo. This notion that revisiting familiar concepts can be a rich soil for personal expression and originality really resonates with me, encouraging a more inclusive and sustainable model of creative practice.

 

Building on Igoe’s redefined approach to creativity, his analogy of interactive art to a stage set for audience participation further deepens the dialogue about the creator-audience relationship. This model, which advocates for minimal intervention by the artist after the artwork’s initial presentation, challenges traditional notions of artistic control and opens up new possibilities for viewer engagement. Personally, I find this perspective transformative; it shifts the completion of an artwork’s meaning to the realm of audience interaction, thereby changing how art is consumed and interpreted. This democratization not only makes art more accessible but also enhances its depth by welcoming a multitude of interpretations.

 

Citations:

www.tigoe.com. (n.d.). Physical Computing’s Greatest Hits (and misses) – hello. [online] Available at: https://www.tigoe.com/blog/category/physicalcomputing/176/.

 

Anon, (n.d.). Making Interactive Art: Set the Stage, Then Shut Up and Listen – hello. [online] Available at: https://www.tigoe.com/blog/category/physicalcomputing/405/.

Week 9_Creative Switch – Jihad Jammal

Concept:

The requirement was clear: devise an alternative that bypasses the conventional hand-operated mechanism. Recognizing that our feet are just as capable when it comes to applying force in a precise manner—much like how we use them to operate pedals in a car—I decided to explore this avenue. I constructed a prototype using cardboard for the pedal, taking advantage of its availability and ease of manipulation, and copper for its conductive properties, essential for transferring the switch’s command.

A highlight of some code that you’re particularly proud of:

const int ledPin = 13; // LED connected to digital pin 13
const int touchSensorPin = 2; // Touch sensor (white wires) connected to digital pin 2

void setup() {
  pinMode(ledPin, OUTPUT); // Set the LED pin as output
  pinMode(touchSensorPin, INPUT_PULLUP); // Set the touch sensor pin as input with internal pull-up resistor
}

void loop() {
  // Check if touch sensor is touched (wires are connected)
  if (digitalRead(touchSensorPin) == LOW) {
    digitalWrite(ledPin, HIGH); // Turn on the LED
  } else {
    digitalWrite(ledPin, LOW); // Turn off the LED
  }
}

Video of Project:

Reflection and ideas for future work or improvements:

Reflecting on the process of creating my foot-operated light switch, I initially envisioned using aluminum for its excellent conductivity and lightweight properties. However, practical limitations often steer the course of innovation, and this project was no exception. With aluminum out of reach, I adapted to the materials available to me, selecting copper tape as a suitable alternative. This choice was not without its merits; copper’s conductivity is remarkable, and its flexibility proved invaluable during the assembly process.

The simplicity of the code was my saving grace, making the integration of electrical components less daunting than anticipated. Yet, every project presents its challenges. One such challenge was securing the wires in such a manner that they consistently made contact with the copper tape. Due to their placement, there were occasions when the connection was missed, disrupting the switch’s functionality. I recognized that increasing the copper tape’s surface area could potentially mitigate this issue, providing a more forgiving target for the wires to connect with.