Categories
INTERACTON LAB

Processing code

import processing.sound.*; import processing.serial.*; int endTime; // Variable to store the end time int startTime; SoundFile sound1; SoundFile sound2; Serial serialPort; boolean gameEnded = false; float characterSize = 150; // Size of the character square float characterX, characterY; // Position of the character float characterSpeed = 25; // Speed of the character (increase this value for faster speed) float bubbleSize = 200; // Size of the bubbles float bubbleSpeed = 3; // Speed of the bubbles int numBubbles = 20; // Number of bubbles int score = 0; // Player's score float[] bubbleX; // Array to store bubble positions float[] bubbleY; // Array to store bubble positions String[] words; // Array to store bubble text float[] starX = new float[3]; float[] starY = new float[3]; float[] starSpeed = new float[3]; boolean openingScene = true; // Flag to indicate if the opening scene is being displayed PImage Image2;  ArrayList<String> chosenWords = new ArrayList<String>(); void addChosenWord(String word) { chosenWords.add(word); } void setup() { fullScreen(); characterX = width / 2; characterY = height / 2; PImage Image; Image = loadImage("star.png"); // Load star image Image2 = loadImage("galaxy.jpg"); sound1 = new SoundFile(this, "arcade_sound.wav" ); sound2 = new SoundFile(this, "drive.mp3"); sound2.loop(); bubbleX = new float[numBubbles]; bubbleY = new float[numBubbles]; words = new String[numBubbles]; for (int i = 0; i < numBubbles; i++) { bubbleX[i] = random(width); // Randomize starting X position bubbleY[i] = -bubbleSize * i; // Set starting Y position above the screen //bubbleText[i] = "Text " + i; // Set bubble text words[0] = "CREATIVE"; words[1] = "MINDFUL"; words[2] = "RELAXED"; words[3] = "EXPLORE"; words[4] = "TRAVEL MORE"; words[5] = "HEALTH"; words[6] = "HUMBLE"; words[7] = "PRODUCTIVE"; words[8] = "FORGIVE"; words[9] = "CONSISTENT"; words[10] = "HAVE FUN"; words[11] = "EMBRACE"; words[12] = "BE BRAVE"; words[13] = "APPRECIATE"; words[14] = "BALANCE"; words[15] = "INSIPRE"; words[16] = "IMPROVE"; words[17] = "BRIGHT"; words[18] = "SELF-LOVE"; words[19] = "FIND LOVE"; } String portName = "/dev/cu.usbmodem14201"; // Specify the correct port name int baudRate = 9600; // Must match the Arduino baud rate serialPort = new Serial(this, portName, baudRate); } void draw() { if (openingScene) { displayOpeningScene(); } else { playGame(); } //println(millis()); } void displayOpeningScene() { background(0, 0, 51); // Set dark blue background for (int i = 0; i < 100; i++) { float x = random(width); float y = random(height); float starSize = random(10, 15); float alpha = random(150, 255); fill(255, 255, 0, alpha); noStroke(); ellipse(x, y, starSize, starSize); } float shootingStarX = -1000; float shootingStarY = random(height / 2); float shootingStarSpeed = random(5, 10); shootingStarX += shootingStarSpeed; shootingStarY += shootingStarSpeed / 2; // Draw shooting star fill(255, 255, 0); noStroke(); triangle(shootingStarX, shootingStarY, shootingStarX - 50, shootingStarY - 20, shootingStarX - 50, shootingStarY + 20); // Set text properties fill(254, 255, 70); textAlign(CENTER, CENTER); textSize(110); float textX = width / 2; float textY = height / 2; text("CHOOSE YOUR 2024 GOAL", textX, textY); if (millis() > 18000) { openingScene = false; } } void playGame() // Resize the background image to match the full screen size { Image2.resize(displayWidth, displayHeight); // Set the resized image as the background background(Image2); // Rest of your code... // Rest of your code... fill(#6B9EB4); rectMode(CENTER); rect(characterX, characterY, characterSize, characterSize); for (int i = 0; i < 100; i++) { float x = random(width); float y = random(height); float starSize = random(3, 6); float alpha = random(150, 255); fill(255, 255, 0, alpha); noStroke(); ellipse(x, y, starSize, starSize); } float shootingStarX = -1000; float shootingStarY = random(height / 2); float shootingStarSpeed = random(5, 10); shootingStarX += shootingStarSpeed; shootingStarY += shootingStarSpeed / 2; fill(255, 255, 0); noStroke(); triangle(shootingStarX, shootingStarY, shootingStarX - 50, shootingStarY - 20, shootingStarX - 50, shootingStarY + 20); // Draw stars for (int i = 0; i < numBubbles; i++) { fill(#FEFF46); drawStar(bubbleX[i], bubbleY[i], bubbleSize); bubbleY[i] += bubbleSpeed; // Move the star downwards // Check if the star has reached the bottom of the screen if (bubbleY[i] > height + bubbleSize / 2) { fill(255); bubbleX[i] = random(width); // Randomize X position bubbleY[i] = -bubbleSize; // Reset Y position above the screen } // Check collision with the character if ((dist(characterX, characterY, bubbleX[i], bubbleY[i]) < characterSize / 2 + bubbleSize / 2) && !gameEnded) { score++; addChosenWord(words[i]); fill(255); bubbleX[i] = random(width); // Randomize X position bubbleY[i] = random(-bubbleSize*2, -height*2); // Reset Y position above the screen sound1.play(); } // Display text inside stars fill(0); textAlign(CENTER, CENTER); textSize(30); text(words[i], bubbleX[i], bubbleY[i]); } // Display score fill(255); textAlign(LEFT); textSize(80); text("Word counts: " + score, 30, 80); // Read serial data from Arduino while (serialPort.available() > 0) { String data = serialPort.readString().trim(); if (data.equals("1")) { characterX -= characterSpeed; // Move character to the left } else if (data.equals("0")) { characterX += characterSpeed; // Move character to the right } } characterX = constrain(characterX, characterSize / 2, width - characterSize / 2); characterY = constrain(characterY, characterSize / 2, height - characterSize / 2); // Check if the game should end if (score >= 10) { if (endTime == 0) { endTime = millis() + 2000; // Set the end time 2 seconds (2000 milliseconds) from now } else if (millis() >= endTime) { endGame(); // Call the endGame() function when the specified time has elapsed } } } void drawStar(float x, float y, float size) { float angle = TWO_PI / 10; float halfAngle = angle / 2.0; float radius1 = size / 2.0; float radius2 = radius1 / 2.5; beginShape(); for (float a = 0; a < TWO_PI; a += angle) { float sx = x + cos(a) * radius1; float sy = y + sin(a) * radius1; vertex(sx, sy); sx = x + cos(a + halfAngle) * radius2; sy = y + sin(a + halfAngle) * radius2; vertex(sx, sy); } endShape(CLOSE); } void endGame() { sound1.stop(); gameEnded = true; background(#000033); // Set dark blue background for (int i = 0; i < 3; i++) { starX[i] = random(width); starY[i] = random(height); starSpeed[i] = random(3, 6); } for (int i = 0; i < 3; i++) { starX[i] += starSpeed[i]; if (starX[i] > width) { starX[i] = 0; starY[i] = random(height); starSpeed[i] = random(3, 6); } float starSize = random(10, 20); float alpha = random(100, 200); fill(#FFFF66, alpha); ellipse(starX[i], starY[i], starSize, starSize); } fill(#FEFF46); textAlign(CENTER, CENTER); textSize(95); text("YOU GAINED "+ score + " AFFIRMATIONS ", width / 2, height / 5); textSize(70); text("MAY ALL YOUR WISH COME TRUE IN 2024", width / 2, height / 2); String[] tempwordlist = chosenWords.toArray(new String[chosenWords.size()]); String combinedString = join(tempwordlist," "); text(combinedString, width/2,height/1.5); } void keyPressed() { if (keyCode == 32) { // Space bar key code if (openingScene) { openingScene = false; // Start the game here } else { openingScene = true; // Restart the game here score = 0; chosenWords.clear(); // Clear the chosenWords list for (int i = 0; i < numBubbles; i++) { bubbleX[i] = random(width); bubbleY[i] = -bubbleSize * i; } startTime = millis(); } } } void endGame2() { if (openingScene) { // Display the opening scene background(0); fill(255); textSize(50); textAlign(CENTER, CENTER); text("Game Over", width / 2, height / 2 - 100); text("Score: " + score, width / 2, height / 2); text("Press SPACE to restart", width / 2, height / 2 + 100); } else { // Ending scene with chosen words background(Image2); fill(#6B9EB4); rectMode(CENTER); rect(characterX, characterY, characterSize, characterSize); // Display the chosen words in a list fill(255); textSize(20); textAlign(LEFT, TOP); float wordListX = 30; float wordListY = 150; for (int i = 0; i < chosenWords.size(); i++) { text(chosenWords.get(i), wordListX, wordListY + i * 30); } for (int i = 0; i < 100; i++) { float x = random(width); float y = random(height); float starSize = random(3, 6); float alpha = random(150, 255); fill(255, 255, 0, alpha); noStroke(); ellipse(x, y, starSize, starSize); } float shootingStarX = -1000; float shootingStarY = random(height / 2); float shootingStarSpeed = random(5, 10); shootingStarX += shootingStarSpeed; shootingStarY += shootingStarSpeed / 2; fill(255, 255, 0); noStroke(); triangle(shootingStarX, shootingStarY, shootingStarX - 50, shootingStarY - 20, shootingStarX - 50, shootingStarY + 20); // Draw stars for (int i = 0; i < numBubbles; i++) { fill(#FEFF46); drawStar(bubbleX[i], bubbleY[i], bubbleSize); bubbleY[i] += bubbleSpeed; // Move the star downwards // Check if the jstar has reached the bottom of the screen if (bubbleY[i] > height + bubbleSize / 2) { fill(255); bubbleX[i] = random(width); // Randomize X position bubbleY[i] = -bubbleSize; // Reset Y position above the screen } // Check collision with the character if ((dist(characterX, characterY, bubbleX[i], bubbleY[i]) < characterSize / 2 + bubbleSize / 2) && !gameEnded) { score++; fill(255); bubbleX[i] = random(width); // Randomize X position bubbleY[i] = random(-bubbleSize*2, -height*2); // Reset Y position above the screen sound1.play(); } // Display text inside stars fill(0); textAlign(CENTER, CENTER); textSize(30); text(words[i], bubbleX[i], bubbleY[i]); } // Display score fill(255); textAlign(LEFT); textSize(80); text("Word counts: " + score, 30, 80); // Read serial data from Arduino while (serialPort.available() > 0) { String data = serialPort.readString().trim(); if (data.equals("1")) { characterX -= characterSpeed; // Move character to the left } else if (data.equals("0")) { characterX += characterSpeed; // Move character to the right } } characterX = constrain(characterX, characterSize / 2, width - characterSize / 2); characterY = constrain(characterY, characterSize / 2, height - characterSize / 2); if (score >= 10) { if (endTime == 0) { endTime = millis() + 2000; // Set the end time 2 seconds (2000 milliseconds) from now } else if (millis() >= endTime) { endGame(); // Call the endGame() function when the specified time has elapsed } } } }
Categories
INTERACTON LAB

Arduino code + circuit

byte ledPin = 13; byte switchPin = 3; void setup() {  pinMode(ledPin, OUTPUT);  pinMode(switchPin, INPUT_PULLUP);  Serial.begin(9600); // Initialize serial communication } void loop() {  if (digitalRead(switchPin) == LOW) {    digitalWrite(ledPin, HIGH);    Serial.println("1"); // Send "1" to indicate button pressed  } else {    digitalWrite(ledPin, LOW);    Serial.println("0"); // Send "0" to indicate button not pressed  }  delay(100); // Add a small delay to avoid rapid serial communication }

Categories
INTERACTON LAB

Final Project: Life Craft 2024

“Life Craft 2024”

Ninj Tumurkhuyag

Partner: Audrey

Professor: Eric Parren

CONCEPT & DESIGN:

Our concept was to create an interactive game inspired by New Year’s resolutions, where players could collect words of affirmation for the upcoming year. Our preparatory research and essay led us to explore the concept of affirmations and the importance of setting positive intentions for personal growth. We wanted to create a playful and engaging experience that would encourage users to reflect on their goals and aspirations for the new year. In terms of user interaction, we initially decided to attach a tilt sensor to a controller board, allowing users to turn left and right to catch words of affirmation. However, during the User Testing Session, our professor Eric provided valuable feedback suggesting attaching the sensor to the head so we decided to create a hat and attach the tilt sensor to it. Users would then tilt their heads left and right to catch the words, creating a “thinking” action that added an extra layer of engagement to the game. To match the theme of New Year, we chose fabrics such as green silk for the hat and used green yarn to hide the wires attached to it. Additionally, based on feedback received during the User Testing Session, we decided to incorporate sound into the game and added background music and sound effects to make the gameplay more enjoyable. We also decided to set the background image as a galaxy, evoking a sense of shooting stars and wishes.

FABIRCATION & PRODUCTION: 

During our production process, we encountered both failures and successes that shaped our final project. One of the significant steps was the decision to create multiple keychains for users to take home for more memorable and provide users with an evident reminder of their affirmations. However, we faced challenges with the code that was supposed to make the square contain the texts inside the stars. Then we changed it to display the collected affirmations at the end of the game instead. In terms of the sensors and actuators used in our project, we selected a tilt sensor as the primary device. The tilt sensor allowed users to control the movement in the game by tilting their heads and we chose this because it provided a hands-free and intuitive interaction method. As for other options, one possibility we considered was adding another player to the game. However, we rejected this option because our project’s primary focus was on personal reflection. During the coding process, our main goal was to ensure that the tilt sensor accurately detected movement and allowed users to catch the words. Once we made this function, we gradually added additional features such as sound effects and background. In terms of visuals, we designed and created a hat, drawers, and keychains to add a physical element to the game. These elements were crafted to match the theme of New Year’s and to provide users with tangible tokens to take home. 

CONCLUSION:

The goals of our project were to create an interactive game inspired by New Year’s resolutions, encouraging people to reflect on their goals and aspirations for the upcoming year. We aimed to create a playful and engaging experience that would promote positive intentions and personal growth. During the IMA show, we saw that our audience interacted with the project, especially the kids, who enjoyed the physical and interactivity of the gameplay. Users actively tilted their heads to catch the words of affirmation, and the incorporation of sound effects and visuals enhanced their engagement. I think the results of our project align well with our definition of interaction, as users physically interacted with the tilt sensor. However, if we had more time, we would’ve liked to further refine the code that would make the square contain the texts inside the stars. Additionally, we could’ve added more varied affirmations to provide users with a wider range of positive messages. Through setbacks and failures encountered during the production process, we learned the importance of thorough testing and iterating on our design. In conclusion, our project successfully achieved its goal of creating an interactive game that encourages reflection and personal growth. We took valuable lessons from this course, and the way people played and enjoyed our game made us proud of the outcome of our project. Lastly, I’m very thankful for everyone, including our professors (from all sections), my dear partner Audrey, fellows, learning assistants, and other fellow students who helped and gave us good recommendations and feedback. 

DISASSEMBLY: 

We took this back to our dorms and cleaned the studio after every working session.

APPENDIX : 

Arduino code + circuit             Processing code

Sources:

tinkercad.com

background music

sound effect

background galaxy image

cuttle.xyz