Categories
Interaction Lab

Final Project Individual Reflection

Project Title: Food except 🐑

Creator: Ran Xu (Charlotte)

Instructor Name: Prof. Marcela Godoy

CONCEPTION AND DESIGN

This project is based on the current situation in Shanghai and aims at people who are locked down in Shanghai and worried about their food supply. People are anxious about whether they can get enough food and things that are normally within reach now become luxuries, for example, fast food and bubble tea. We would like to make a game world where people can fetch the food they want, such as cakes and bubble tea, and through an unrealistic way like “天上掉馅饼”( a saying in China that means getting something without hard work. It can be translated directly as ” pies falling down from the sky without effort”)

We want users to release their stress while playing the game. So we use the microphone to control the beginning of the game. We also use the pressure sensor to control the hunter and hang it on the wall. In that case, users can make some exercise at the same time.

During the user test, we found the difficulty of the game is too high and people fail the game easily since the sheep always fall down with the food and it is hard to avoid. I thought it is not helpful for stressed people during the lockdown time, so we reduce the speed of the sheep. I think this change is effective since the user experience becomes better after changing.

In addition, we change the caught sound of different food. When people catch basic food such as vegetables and meat, the sound is like “duu–“. And when people catch snacks such as cakes and ice creams, the sound is relatively high. When people catch sheep which means positive, the sound is relatively low.

We also add a score detail display to the game. The detail of the score will show in the right-down corner when the hunter catches the food.

 

FABRICATION AND PRODUCTION

Younian and I cooperate to complete this project. Since we don’t live together, we each finished the physical part.

In the coding process, I complete the original version of this game. I control the hunter with the variable resistors at first.I draw the image of the hunter with Processing and let food fall from the top of the screen at different times. But later Younian found that we only need to let the hunter move right and left. Saving it as an image will be better. So we use the image of the hunter rather than the code.Younian helps me to make the falling code more graceful since in the original one every food has a long code.

In addition, she solved the problem of interaction between the hunter and the food and complete the control of the beginning and the end of the game. Then I complete the timer of the game and she finfish the scoring record part. After we talk about the ending, I add a video to the winning part. At last, we talk about the storyline of the video and shoot the video separately. And I edit the video.

I think the most successful part is the coding part. We have never made such a big code and we still have a lot to learn. During this part, we searched for relative information and tutoring videos online and ask professor Marcela for help. We also cooperate to solve each other’s problems and improve the design of this game. Younian has the original idea of this game and at first, this game tends to show the pressure during lockdown time. But after we talked together and think about the aim audience, we found that maybe a light-hearted game is more suitable for people locked down at home. So we change the code accordingly.

From my perspective, the failure of this game is the sensor. Since each of us only has one vibration sensor. We need to give up the original idea of controlling the hunter by punching pillows. But we still want to relieve people’s stress so we use the pressure sensor. But we found it is hard for us to decorate it since it is not very sensitive. I try to stick a rubber decompression toy on it and control the hunter by pressing the toy, but it doesn’t work. So at last we stick the image of sheep on it and people can play the game by pressing the sheep.

CONCLUSION

The goal of our project is to let people who are locked down in Shanghai release their stress while playing the game. The users interact with the project by shouting and pressing the pressure sensor. This is an input process. And the computer takes charge of ” thinking” and gives feedback ( begin the game and move the hunter) This shows the definition of interaction. If we have more time, I will improve the catch sound effect of the game. I would like to design a special effect for different food. And I also want to improve the code to let the score detail appear near the caught food. These elements can let the users understand the mechanics of this game. 

During the process of this project, I learn the importance of user testing. Sometimes it is hard for the designer to find the problem and details that can be improved. We need suggestions to make our project better. 

What’s more, I learned the importance of cooperation. It did can lead to the effect of  1+1 > 2.  In this surreal semester, everyone suffers more pressure. Understanding and communication become more important during this special period and help this project works better. Younian and I divided the work equally and helped each other. That kind of cooperation makes the final weeks not so stressful. 

At last, thanks for Younian making this project with me. I really enjoy cooperation with you 💗💗💗  Thanks for Marcela helping us to complete this project and teaching us this semester.

Hope we can meet in the fall!

TECHNICAL DOCUMENTATION

Arduino

void setup()
{
  Serial.begin(9600);
}

void loop() 
{
  // to send values to Processing assign the values you want to send
  //this is an example
  int sensor1 = analogRead(A0);
  int sensor2 = analogRead(A1);


  // send the values keeping this format
  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(sensor2);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

Processing 

import processing.serial.*;
import processing.sound.*;
import processing.video.*;
int NUM_OF_VALUES_FROM_ARDUINO = 2;
int sensorValues[];
String myString = null;
Serial myPort;
AudioIn microphone;
Amplitude analysis;
Movie myMovie;

//added this to have a feedback when you catch something
//you can replace the sound
SinOsc sine;
Env env;
float attackTime = 0.001;
float sustainTime = 0.004;
float sustainLevel = 0.5;
float releaseTime = 0.4;

Catcher c;
Dropfruit[] dropf;
Droprefresh[] dropr;
Dropsheep[] drops;
//Apple[] apples;

Timer dropTimer;

int numDrops;
int dropInterval;
int activeDrops;

String gameState;
int score;

Timer countDownTimer;
int timeLeft;
int maxTime;

PImage catcherImage;
int x;
int r =150;




void setup() {
  size(800, 800);
  background(237, 222, 139);
  microphone = new AudioIn(this, 0);
  microphone.start();
  analysis = new Amplitude(this);
  analysis.input(microphone);

  
  sine = new SinOsc(this);
  env  = new Env(this);

 countDownTimer = new Timer(1000);
 maxTime = 140;
 timeLeft = maxTime;
 
  PFont myFont;
  myFont = createFont("Phosphate-Inline", 50);
  textFont(myFont);

  gameState = "TITLE";
  score = 0;

  myMovie = new Movie(this, "Never.mp4");
  
  

  c= new Catcher();
  numDrops = 20;//need to adjust, now the orange will run out after we catch them
  dropf = new Dropfruit[numDrops];
  dropr = new Droprefresh[numDrops];
  drops = new Dropsheep[numDrops];
  //apples = new Apple[numDrops];
  for ( int i =0; i < numDrops; i++) {
    dropf[i] = new Dropfruit();
    dropr[i] = new Droprefresh();
    drops[i] = new Dropsheep();
  }
  activeDrops = 0;
  dropInterval = 1000;
  dropTimer = new Timer(dropInterval);
  dropTimer.start();

  setupSerial();
  x = width/2;
  catcherImage = loadImage("hunter.png");
  catcherImage.resize(r, r);
  //d = new Drop();
}

void draw() {
  background(237, 222, 139);
  //println(analysis.analyze());
  getSerialData();
  //printArray(sensorValues);
  
   
 
  if (gameState =="TITLE") {
    title();
  } else if (gameState == "GAME") {
    //noCursor();
    game();
  } else if (gameState == "WIN") {
    cursor();
    win();
  } else if (gameState == "LOSE") {
    cursor();
    lose();
  } else {
    println("something went wrong with gameState");
  }
}


//h.update();
//h.display();
boolean intersect (Catcher c, Dropfruit d) {
  float distance = dist(c.forkX, c.forkY, d.x, d.y);
  if (distance < 50) {
    return true;
  } else {
    return false;
  }
}
boolean intersect (Catcher c, Droprefresh r) {
  float distance = dist(c.forkX, c.forkY, r.x, r.y);
  if (distance < 50) {
    return true;
  } else {
    return false;
  }
}
boolean intersect (Catcher c, Dropsheep s) {
  float distance = dist(c.forkX, c.forkY, s.x, s.y);
  if (distance < 50) {
    return true;
  } else {
    return false;
  }
}

void game() {
  noStroke();
  background(237, 222, 139);
  c.update();
  c.display();

  //time management
  if ( dropTimer. complete() == true) {
    if (activeDrops < numDrops) {
      activeDrops++;
    }
    dropTimer. start();
  }

  for (int i =0; i<activeDrops; i++) {
    dropf[i].update();
    dropf[i].display();
    dropr[i].update();
    dropr[i].display();
    drops[i].update();
    drops[i].display();
    if (intersect (c, dropf[i])==true) {
      dropf[i].caught();
      score++;
      println("score= "+score);
      fill(1,77,103);
      textSize(36);
      String a = "basics +1";
      text(a, 650, 700);
      sine.play();
      sine.freq(500);
      env.play(sine, attackTime, sustainTime, sustainLevel, releaseTime);
    }
    if (intersect (c, dropr[i])==true) {
      dropr[i].caught();
      score=score+2;
      println("score= "+score);
      fill(1,77,103);
      textSize(36);
      String m ="snack +2";
      text(m, 650, 700);
      sine.play();
      sine.freq(1000);
      env.play(sine, attackTime, sustainTime, sustainLevel, releaseTime);
    }
    if (intersect (c, drops[i])==true) {
      drops[i].caught();
      score=score-10;
      println("score= "+score);
      fill(1,77,103);
      textSize(36);
      String u = "sheep -10";
      text(u, 650, 700);
      sine.play();
      sine.freq(200);
      env.play(sine, attackTime, sustainTime, sustainLevel, releaseTime);
    }
  }
  if (score >=10) {  //need to adjust
    gameState = "WIN";
  }
  if (score < 0) {  //need to adjust
    gameState = "LOSE";
  }
   
  fill(1,77,103);
   textSize(36);
  String p = "LIFE:" + score;
  text(p, 90, 90); 
  
  if (countDownTimer. complete() == true){
    if (timeLeft >1){
      timeLeft--;
      countDownTimer.start();
    }else{
      gameState = "LOSE";   
    }
  }
  String s = "Time Left:" + timeLeft;
  textAlign(LEFT);
  textSize(36);
  fill(1,77,103);
  text(s,50,50);
}//end game


void clearBackground() {
  fill (237, 222, 139);
  rect(0, 0, width, height);
}


void resetGame() {
  for (int i = 0; i< numDrops; i++) {
    dropf[i].reset();
    dropr[i].reset();
    drops[i].reset();
  }
  activeDrops=0;
  score = 0;
  gameState = "GAME";
  
  timeLeft = maxTime;
  countDownTimer.start();
  
  
  
}


void title() {
  background(237, 222, 139);
  fill(1,77,103);
  textSize(36);
  textAlign(CENTER);
  String s = "Shout out FOOD to Play";
  text(s, 400, 200);
  //Sound code
  float volume = analysis.analyze();
  float diameter = map(volume, 0, 1, 0, 1000);
  if (diameter > 20) {
    //startTime = millis();
    gameState = "GAME";
    countDownTimer.start();
  } 
}

void win() {
  background(237, 222, 139);
  fill(1,77,103);
  textSize(36);
  textAlign(CENTER);
  String s = "You win!\n Dancing is better than hunting ";
  text(s, 400, 50);
  float volume = analysis.analyze();
  float diameter = map(volume, 0, 1, 0, 1000);
  if (diameter > 0.1) {
if (myMovie.available()) {
    myMovie.read();
  }
  play();
}
}

void play(){
  myMovie.play();
  image(myMovie, 25, 130);
  
}



void lose() {
  background(237, 222, 139);
  fill(1,77,103);
  textSize(36);
  textAlign(CENTER);
  String s = "You will starve to death\nSHOUT to Play Again";
  text(s, 400, 200);
  float volume = analysis.analyze();
  float diameter = map(volume, 0, 1, 0, 1000);
  if (diameter > 20) {
    resetGame();
  }
  
}

void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 3 ], 9600);
  myPort.clear();
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;

  sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

Catcher

class Catcher {
  //properties
  float x, y, w, h, forkX, forkY;

  //constructor
  Catcher() {
    x= width/2;
    y = height-r;
  }

  //methods
  void update() {
    if (sensorValues[0]>600) {
      x=x+20;
    }
    if (sensorValues[1]>600) {
      x=x-20;
    }
    //x = mouseX;
    image(catcherImage, x, y);
    w = catcherImage.width;
    h = catcherImage.height;
    forkX = x+w-30;
    forkY = y+30;

    if (x>width-r) {
      x=width-r;
    }
    if (x<0) {
      x=0;
    }
  }
  void display() {
    image(catcherImage, x, y);
    //you can delete this part, it is just to figure out where the fork is
    fill(0, 0, 0, 0 );
    rectMode(CENTER);
    rect(forkX, forkY, 60, 10);
  }
}

Drop_fruit

PImage cucmber;
PImage greens;
PImage onion;
PImage orange;
PImage steak;
PImage fruit;
class Dropfruit {
  float x, y, w, h;
  float speedY;
  String pix;
  Dropfruit() {
    x = random(width);
    y = -10;
    h = 16;
    w = 16;
    speedY = random(5, 10);
    float r = int(random(1,8));
    if (r <= 2) {
      pix = "cucumber.png";
    } else if (r == 3) {
      pix = "greens.png";
    } else if (r == 4) {
      pix = "onion.png";
    } else if  (r == 5) {
      pix = "orange.png";
    } else if  (r >= 6) {
      pix = "steak.png";
    } 
  }
  void update() {
    y+= speedY;
    if (y > height +h/2) {
      y = -h/2;
    }
  }
  void display() {
    fruit = loadImage(pix);
    fruit.resize(60, 50);
    image(fruit, x, y);
    //orange = loadImage("orange.png");
    //apple = loadImage("apple.png");
    //apple.resize(60, 50);
    //image(apple,x+100, y+60);
  }
  void caught() {
    speedY =0;
    y = 0;
  }
  void reset() {
    y=0;
    speedY = random(5, 10);
  }
}

Drop_refresh

PImage cake;
PImage hamburger;
PImage ice;
PImage refresh;

class Droprefresh {
  float x, y, w, h;
  float speedY;
  String pix;
  Droprefresh() {
    x = random(width);
    y = -10;
    h = 16;
    w = 16;
    speedY = random(5, 10);
    float r = int(random(8,13));
    if (r <= 9) {
      pix = "cake.png";
    } else if (r == 10) {
      pix = "hamburger.png";
    } else if (r >= 11) {
      pix = "ice.png";
    } 
  }
  void update() {
    y+= speedY;
    if (y > height +h/2) {
      y = -h/2;
    }
  }
  void display() {
    refresh = loadImage(pix);
    refresh.resize(60, 50);
    image(refresh, x, y);
  }
  void caught() {
    speedY =0;
    y = 0;
  }
  void reset() {
    y=0;
    speedY = random(5, 10);
  }
}

Drop_sheep

PImage sheep;

class Dropsheep {
  float x, y, w, h;
  float speedY;
  //String pix;
  Dropsheep() {
    x = random(width);
    y = -10;
    h = 16;
    w = 16;
    speedY = random(3, 7);
    //float r = int(random(15,18));
    //if (r == 15||r == 16) {
    //  pix = "sheep.png";
    //}
  }
  void update() {
    y+= speedY;
    if (y > height +h/2) {
      y = -h/2;
    }
  }
  void display() {
    sheep = loadImage("sheep.png");
    sheep.resize(60, 50);
    image(sheep, x, y);
  }
  void caught() {
    speedY =0;
    y = 0;
    
  }
  void reset() {
    y=0;
    speedY = random(5, 10);
  }
}

Timer

 

class Timer {
  int startTime;
  int interval;
  Timer (int timeInterval) {
    interval = timeInterval;
  }
  void start() {
    startTime = millis();
  }
  boolean complete() {
    int elapsedTime = millis()- startTime;
    if (elapsedTime > interval) {
      return true;
    } else {
      return false;
    }
  }
}

Images in the game

 

 

Circuit

Video

The video is too big to upload to this blog. Here is the link to the YouTube video. 

Categories
Interaction Lab

Recitation 10 :Image & Video

 Part 1: Media controller

I decided to make the image of a hunter for our final project and control it with the variable resistors. So I made the code of the hunter. 

void drawMan(float u, float v, float s, color c){
   fill(255);
  noStroke();
  circle(u-450,v-450,s-20);
  
  ellipse(u-450,v-415,s+5,s);
  ellipse(u-433,v-390,s-30,s-40);
  ellipse(u-465,v-390,s-30,s-40);
  
  ellipse(u-475, v-410, s-40, s-20);
  ellipse(u-425, v-425, s-20, s-40); 
  
  
  fill(0);
  noStroke();
  stroke(0);
  line(u-455,v-450,u-445,v-450);
  circle(u-455,v-450,s-45);
  circle(u-445,v-450,s-45);
 
  
  fill(0);
  noStroke();
  rect(u-413,v-450,s-45,s+10);
  rect(u-420,v-450,s-30,s-40);
  rect(u-420,v-470,s-45,s-20);
  rect(u-413,v-470,s-45,s-20);
  rect(u-405,v-470,s-45,s-20);
  
}

I forgot that I need to use an image at that time and change the numbers into variables. And then I realized this problem and save it as a picture.

 

Here is the code.

Arduino

void setup()
{
  Serial.begin(9600);
}

void loop() 
{
  // to send values to Processing assign the values you want to send
  //this is an example
  int sensor1 = analogRead(A0);
  int sensor2 = analogRead(A1);


  // send the values keeping this format
  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(sensor2);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

Processing

PImage hunter; 
import processing.serial.*;
int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[];      /** this array stores values from Arduino **/

String myString = null;
Serial myPort;
void setup(){
  size(600,600);
  background(237,222,139);
  setupSerial(); 
  imageMode(CENTER);
}
void draw(){
  background(237,222,139);
   getSerialData();
  printArray(sensorValues);
 float val1 = sensorValues[0];
 float val2 = sensorValues[1];
 hunter = loadImage("hunter.png");
 hunter.resize(90,90);
 
 image(hunter,val1,val2);

}

void setupSerial() {
  //printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 3 ], 9600);

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
  
    sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

 

Part 2: Musical Instrument

At first, I didn’t understand the requirement of the exercise so I asked LA for help. I knew that the functions of envelope and difference are necessary but I don’t know how to use them. I spent a long time solving this problem. 

Code

import processing.video.*; 
import processing.sound.*;
TriOsc triOsc;
Env env;
String[] cameras = Capture.list();
Capture cam;
float attackTime = 0.006;
float sustainTime = 0.002;
float sustainLevel = 0.3;
float releaseTime = 0.4;
int size = 20;
float r, prer;
void setup() {
  size(640, 480);
  cam = new Capture(this, cameras[0]);
  cam.start();
  triOsc = new TriOsc(this); 
  env  = new Env(this);  
}
void draw() {
  if (cam.available()) {
   cam.read(); 
  } 
 
  for (int x=0; x<cam.width; x=x+size) {
     for (int y=0; y<cam.height; y=y+size) {
       color c=cam.get(x,y);
       fill(c);
       noStroke();
       rect(x,y,size,size);
     }
}
  color c = cam.get(width/2, height/2); 
  r = red(c);
  float difference = abs(r-prer);
  if (difference>10) {
    triOsc.play();
    triOsc.freq(map(r, 0, 255, 100, 600));
    env.play(triOsc, attackTime, sustainTime, sustainLevel, releaseTime);
}
prer = r;
}

 

 

 

Categories
Interaction Lab

Recitation 9: Sound in Processing

Exercise One

I tried to use the play(); function to play the music at first. But I found it doesn’t work. The music isn’t played when I pressed the keyboard. In addition, when I change the code, I can’t let it stop.  Then I asked the learning assistant for help and I changed it to “playSound1=!playSound1” In that case, it can stop when I press the button twice. 

 

Code

import processing.sound.*;
Boolean playSound1 = true;
Boolean playSound2 = true;
SoundFile sound1;
SoundFile sound2;

void setup() {
  size(640, 480);
  background(0);
  sound1 = new SoundFile(this, "plunkysynthloop.wav");
  sound2 = new SoundFile(this, "monsterwobbleloop.wav");
}

void draw() {
}

void keyPressed() {
  if (key == 'd') {
    playSound1=!playSound1;
  }
  if (playSound1==false) {
    sound1.loop();
    noStroke();
    fill(255,222,0);
    circle(200,250,100);
  } else {
    sound1.stop();
    noStroke();
    fill(150);
    circle(200, 250, 100);
  }
  if (key == 'j') {
    playSound2=!playSound2;
  }
  if (playSound2==false) {
    sound2.loop();
    fill(147,224,255);
    circle(400, 250, 100);
  } else {
    sound2.stop();
    fill(150);
    circle(400, 250, 100);
  }
}

Exercise Two

I can feel the vibration motor working when I put my hands on it but I can’t show it is jumping with the music even I put a light string on it. But it works. 

import processing.serial.*;
import processing.sound.*;
SoundFile sound;

int NUM_OF_VALUES_FROM_PROCESSING = 3;  /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
float processing_values[] = new float[NUM_OF_VALUES_FROM_PROCESSING]; /** this array stores values you might want to send to Arduino **/

Serial myPort;
String myString;

Amplitude analysis;

void setup() {
  size(500, 500);
  background(0);
  setupSerial();
  sound = new SoundFile(this, "Lost On The Freeway.mp3");
  sound.play();
  analysis = new Amplitude(this);
  analysis.input(sound);
}

void draw() {
  
 println(analysis.analyze());
  background(0);
  
  // analyze the audio for its volume level
  float volume = analysis.analyze();
  // map the volume value to a useful scale
  float diameter = map(volume, 0, 1, 0, width);
  // draw a circle based on the microphone amplitude (volume)
  circle(width/2, height/2,diameter ); 


  sendSerialData();

}

void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[2], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;

}

void sendSerialData() {
  String data = "";
  for (int i=0; i<processing_values.length; i++) {
    data += processing_values[i];
    //if i is less than the index number of the last element in the values array
    if (i < processing_values.length-1) {
      data += ","; // add splitter character "," between each values element
    } 
    //if it is the last element in the values array
    else {
      data += "\n"; // add the end of data character linefeed "\n"
    }
    
  }
  //write to Arduino
  myPort.write(data);
  print(data); // this prints to the console the values going to arduino 
  
}

Homework

There are little faces changing with the music. The size of their faces changes with the volume of the music.

 

Code

import processing.sound.*;
AudioIn microphone;
Amplitude analysis;

void setup(){
    size(500, 480);
  // create the AudioIn object and select the mic as the input stream
  microphone = new AudioIn(this, 0);
  // start the mic input without routing it to the speakers
  microphone.start();
  // create the Amplitude analysis object
  analysis = new Amplitude(this);
  // use the microphone as the input for the analysis
  analysis.input(microphone);
}   

void draw(){
background(0);
  println(analysis.analyze());
 
  float volume = analysis.analyze();
 
  float diameter = map(volume, 0, 1, 0, width);
  // draw a circle based on the microphone amplitude (volume)


   fill(255,113,113,90);
  circle(320,240,diameter);
  fill(255);
  circle(310,240,10);
  circle(330,240,10);
  
  stroke(255);
  line(310,240,330,240);
  
  fill(147,224,255,90);
  circle(400,400,diameter);
  fill(255);
  circle(390,400,10);
  circle(410,400,10);
  
   stroke(255);
  line(390,400,410,400);
  
  fill(255,222,0,90);
  circle(200,200,diameter);
  fill(255);
  circle(190,200,10);
  circle(210,200,10);
   stroke(255);
  line(190,200,210,200);
  
  fill(131,175,155,90);
  circle(100,300,diameter);
  fill(255);
  circle(90,300,10);
  circle(110,300,10);
   stroke(255);
  line(90,300,110,300);
  
  fill(227,160,93,90);
  circle(80,50,diameter);
  fill(255);
  circle(70,50,10);
  circle(90,50,10);
  stroke(255);
  line(70,50,90,50);
  
  fill(255,238,210,90);
  circle(400,50,diameter);
  fill(255);
  circle(390,50,10);
  circle(410,50,10);
  stroke(255);
  line(390,50,410,50);

}

 

 

Categories
Interaction Lab

Final Project Essay

Food except 🐑

Younian and I decided to cooperate to finish the final project together. This project is based on current situation of Shanghai and aims at people who are locked down in Shanghai and worried about their food. We would like to make a game world that people can fetch the food they want, such as cakes and bubble tea and through an unrealistic way like “天上掉馅饼”( a saying in China that means getting something without hard work. It can be translated directly as ” pies falling down from the sky”)

This project will let players use fork to hunt food that falling from the sky.  People have 20 points that represents LIFE at the beginning of the game and the game has a  time limit of 140 seconds for one round.  LIFE increases when people get food and decreases when the fork touches sheep.( Since sheep is “羊yáng” in Chinese and its pronunciation is the same as 阳, which means positive)  We decided to let the microphone input the beginning of the game. The player shout out “FOOD” to let the food start falling. And then the player can use soft rubber toys to control the character to move left and right. These two toys are connected with pressure sensors so that people can release pressure by squeezing the toys. We decided to finish the first draft of code before May 1 and revise it before May 7. During the week of May 2, we will finish the physical part of the project.

This proposal contains variability that I have argued in the research part. People don’t know where and how fast the food is falling and they need to move the character to get food. The interaction is uncertain. In addition, people can easily step in to the role and try to explore the points of each food and the speed of them. This process is immersive just like the project Connected Worlds I have researched. People can have a interaction with the project without instructions from the designers or experts. 

 

 

Categories
Interaction Lab

Recitation 8: Serial Communication

Exercise 1: Make a Processing Etch-A-Sketch

code:

Arduino

// IMA NYU Shanghai
// Interaction Lab
// For sending multiple values from Arduino to Processing


void setup() {
  Serial.begin(9600);
}

void loop() {
  // to send values to Processing assign the values you want to send
  //this is an example
  int sensor1 = analogRead(A0);
  int sensor2 = analogRead(A1);
//  int sensor3 = analogRead(A2);

  // send the values keeping this format
  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(sensor2);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

Processing

// IMA NYU Shanghai
// Interaction Lab
// For receiving multiple values from Arduino to Processing

/*
 * Based on the readStringUntil() example by Tom Igoe
 * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
 */

import processing.serial.*;


int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[];      /** this array stores values from Arduino **/

String myString = null;
Serial myPort;

void setup() {
  size(500, 500);
  setupSerial();
}

void draw() {
  background(229,187,129);
  getSerialData();
  printArray(sensorValues);
  noStroke();
  fill(161,23,21);

 float val1 = sensorValues[0];
 float val2 = sensorValues[1];
 circle(val1, val2, 100);
}

void setupSerial() {
  //printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 1 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
  
    sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

I didn’t get into trouble when I let the ball move. But when I change it into a line, the problem of background happened again. I didn’t find this problem and tried to modify other elements. Finally, I found that I need to delete the background() in the void draw to let the line appear on the screen.

code

Processing

// IMA NYU Shanghai
// Interaction Lab
// For receiving multiple values from Arduino to Processing

/*
 * Based on the readStringUntil() example by Tom Igoe
 * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
 */

import processing.serial.*;


int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[]; /** this array stores values from Arduino **/
String myString = null;
Serial myPort;
float x = random (width);
float y = random (height);

void setup() {
  size(500, 500);
  setupSerial();
   background(229,187,129);
}

void draw() {
 
  getSerialData();
  printArray(sensorValues);
  
 float lx = map ( sensorValues[0],0,1023,0,500);
 float ly = map ( sensorValues[1],0,1023,0,500);
 stroke(161,23,21);
 strokeWeight(3);
 line (lx,ly, x, y);
 
 x = lx;
 y = ly;
 
 
}

void setupSerial() {
  //printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 1 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
  
    sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

Exercise 2

 

Code

Arduino

#include <Servo.h>
#define NUM_OF_VALUES_FROM_PROCESSING 3    /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/

Servo myservo; 

/** DO NOT REMOVE THESE **/
int tempValue = 0;
int valueIndex = 0;

/* This is the array of values storing the data from Processing. */
int processing_values[NUM_OF_VALUES_FROM_PROCESSING];


void setup() {
  Serial.begin(9600);

  myservo.attach(9);
}

void loop() {
  getSerialData();
  
     if (processing_values[0] == 1){
      myservo.write(180);
      delay(100);
     }else{
      myservo.write(0);
    }
}

//receive serial data from Processing
void getSerialData() {
  while (Serial.available()) {
    char c = Serial.read();
    //switch - case checks the value of the variable in the switch function
    //in this case, the char c, then runs one of the cases that fit the value of the variable
    //for more information, visit the reference page: https://www.arduino.cc/en/Reference/SwitchCase
    switch (c) {
      //if the char c from Processing is a number between 0 and 9
      case '0'...'9':
        //save the value of char c to tempValue
        //but simultaneously rearrange the existing values saved in tempValue
        //for the digits received through char c to remain coherent
        //if this does not make sense and would like to know more, send an email to me!
        tempValue = tempValue * 10 + c - '0';
        break;
      //if the char c from Processing is a comma
      //indicating that the following values of char c is for the next element in the values array
      case ',':
        processing_values[valueIndex] = tempValue;
        //reset tempValue value
        tempValue = 0;
        //increment valuesIndex by 1
        valueIndex++;
        break;
      //if the char c from Processing is character 'n'
      //which signals that it is the end of data
      case '\n':
        //save the tempValue
        //this will b the last element in the values array
        processing_values[valueIndex] = tempValue;
        //reset tempValue and valueIndex values
        //to clear out the values array for the next round of readings from Processing
        tempValue = 0;
        valueIndex = 0;
        break;
    }
  }
}

Processing

import processing.serial.*;
int NUM_OF_VALUES_FROM_PROCESSING = 1;  
int processing_values[] = new int[NUM_OF_VALUES_FROM_PROCESSING]; 
Serial myPort;
String myString;

float x;
float speedX;
float s;

void setup() {
  fullScreen();


  background(0);
  speedX = 5 ;
  
  setupSerial();
}
void draw() {
  background(147,224,255);
  noStroke();
  fill(255,66,93);
  circle (x, 350, 100);
  x= x+speedX;
  if (x > width || x < 0) {
    speedX = -speedX;
  }
   if (x > width) {// hit the left wall
    processing_values[0] = 1;
  } else  {
    processing_values[0] = 0;
}
  sendSerialData();
}
void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.clear();
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
}
void sendSerialData() {
  String data = "";
  for (int i=0; i<processing_values.length; i++) {
    data += processing_values[i];
   
    if (i < processing_values.length-1) {
      data += ","; // add splitter character "," between each values element
    }
    else {
      data += "\n"; // add the end of data character linefeed "\n"
    }
  }
  myPort.write(data);
  print(data); // this prints to the console the values going to arduin0
}

When I made the Processing code, I found my motor didn’t move and only the bouncing ball worked. In addition, the number in the console of Processing is always 0. I asked Professor Godoy for help and she solved the coding problem by changing the “if (x > width-s/2)” into “if (x > width)” so that it represents 1 when the ball touches the side of the screen. And we also found I connect the circuit in the wrong way and it stopped the motor. (The right order is brown is ground, red is 5V and orange is special pin)

Homework

Code 

Arduino

// IMA NYU Shanghai
// Interaction Lab
// For sending multiple values from Arduino to Processing
int button1 = 4;
int button2 = 8;

int count1;
int count2;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(button1) == HIGH){
    count1 = count1 +1;
  }
    if (digitalRead(button2) == HIGH){
    count2 = count2 +1;
  }
  Serial.print(count1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(count2);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

Processing

// IMA NYU Shanghai
// Interaction Lab
// For receiving multiple values from Arduino to Processing

/*
 * Based on the readStringUntil() example by Tom Igoe
 * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
 */

import processing.serial.*;


int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[];      /** this array stores values from Arduino **/

String myString = null;
Serial myPort;

void setup() {
  size(600, 600);

  setupSerial();
  
}

void draw() {
    background(0);
  getSerialData();
  printArray(sensorValues);
 if (sensorValues[0] % 2 == 1) {
    pushMatrix();
    translate(width*0.3, height*0.3);
    rotate(frameCount / 200.0);
    star(0, 0, 30, 70, 5);
    popMatrix();
  }
  if (sensorValues[1] % 2 == 1) {
    pushMatrix();
    translate(width*0.7, height*0.7);
    rotate(frameCount / 200.0);
    star(0, 0, 80, 100, 40);
    popMatrix();
  }

}

void star(float x, float y, float radius1, float radius2, int npoints) {
  float angle = TWO_PI / npoints;
  float halfAngle = angle/2.0;
  beginShape();
  for (float a = 0; a < TWO_PI; a += angle) {
    float sx = x + cos(a) * radius2;
    float sy = y + sin(a) * radius2;
    vertex(sx, sy);
    sx = x + cos(a+halfAngle) * radius1;
    sy = y + sin(a+halfAngle) * radius1;
    vertex(sx, sy);
  }
  endShape(CLOSE);
}
void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[3], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;

  sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

At first, I write this Arduino code.

// Interaction Lab
// For sending multiple values from Arduino to Processing
int button1 = 4;
int button2 = 8;


void setup() {
  Serial.begin(9600);
}

void loop() {
  // to send values to Processing assign the values you want to send
  //this is an example
  int sensor1 = digitalRead(4);
  int sensor2 = digitalRead(8);
  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(sensor2);
//  Serial.print(",");  // put comma between sensor values
//  Serial.print(sensor3);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

 And I found only when I press the button, the star appears. The requirement is “when you press button 1 once, star 1 will appear on the canvas, and when you press button 1 once again, star 1 will disappear.”

So I decided to use count to solve this problem and when the number of pressing times is odd, the stars appear and the number is even, the stars disappear. 

I research that sound can work as input and generate creative outputs. Music can draw be shown on the screen and let it become more visible.

Here is the example I have found. https://processing.org/tutorials/sound/#example-5-6-audio-analysis

 

/**
 * Processing Sound Library, Example 5
 *
 * This sketch shows how to use the FFT class to analyze a stream
 * of sound. Change the number of bands to get more spectral bands
 * (at the expense of more coarse-grained time resolution of the spectrum).
 *
 * Load this example with included sound files from the Processing Editor:
 * Examples > Libraries > Sound > Analysis > FFTSpectrum
 */

import processing.sound.*;

// Declare the sound source and FFT analyzer variables
SoundFile sample;
FFT fft;

// Define how many FFT bands to use (this needs to be a power of two)
int bands = 128;

// Define a smoothing factor which determines how much the spectrums of consecutive
// points in time should be combined to create a smoother visualisation of the spectrum.
// A smoothing factor of 1.0 means no smoothing (only the data from the newest analysis
// is rendered), decrease the factor down towards 0.0 to have the visualisation update
// more slowly, which is easier on the eye.
float smoothingFactor = 0.2;

// Create a vector to store the smoothed spectrum data in
float[] sum = new float[bands];

// Variables for drawing the spectrum:
// Declare a scaling factor for adjusting the height of the rectangles
int scale = 5;
// Declare a drawing variable for calculating the width of the
float barWidth;

public void setup() {
  size(640, 360);
  background(255);

  // Calculate the width of the rects depending on how many bands we have
  barWidth = width/float(bands);

  // Load and play a soundfile and loop it.
  sample = new SoundFile(this, "beat.aiff");
  sample.loop();

  // Create the FFT analyzer and connect the playing soundfile to it.
  fft = new FFT(this, bands);
  fft.input(sample);
}

public void draw() {
  // Set background color, noStroke and fill color
  background(125, 255, 125);
  fill(255, 0, 150);
  noStroke();

  // Perform the analysis
  fft.analyze();

  for (int i = 0; i < bands; i++) {
    // Smooth the FFT spectrum data by smoothing factor
    sum[i] += (fft.spectrum[i] - sum[i]) * smoothingFactor;

    // Draw the rectangles, adjust their height using the scale factor
    rect(i*barWidth, height, barWidth, -sum[i]*height*scale);
  }
}

 

 

 

 

 

 

 

 

 

Categories
Interaction Lab

Final Projects: Three ideas

  1. Treasure Searching 

Players act as explorers and use a shovel to find buried treasure. In this project, I would use the Motion Detection functions to trace the movement of the shovel. There are several rounds in the game that require players to find both the treasure and the key. The shovel will be smaller and smaller and so is the treasure. This game can let people locked in their homes have more exercise and enjoy the fun of treasure hunting. 

2. Melody Matching 

In this game, participants need to first listen to the music from the player and use the stick to choose the correct button with the same melody and in the same order. (The music may consist of several pieces of melody) Motion Detection functions may be used or people can use two variable resistors to change the position of the stick. This game also will have several rounds and the music will be longer. It can practice players’ memorization.

3. Food Hunting

In this game, people will use two variable resistors to control the hunter. They need to go through a maze and keep away from the guards that move in a certain way to get the food. It represents the difficulty of buying food nowadays and I would like to show this phenomenon in a more interesting way. 

 

 

 

Categories
Interaction Lab

Final Project–Preparatory Research and Analysis

Interactive Projects Research

  1. An Auto-Multiscopic Projector Array for Interactive Digital Humans

      In this interactive project, the participant can interact with other people through interaction with equipment. Such interactions are both synchronous and asynchronous. The sense of transcending time and space adds fun to the equipment. In addition, people don’t need to wear external devices, which lowers the boundary of interaction and increases people’s sense of participation. It informs me that I need to think more about the interaction rather than feedback when I design my final project. And the interaction between users is also meaningful, maybe it is necessary to keep past users’ data. I also learned that keeping interaction requirements to a minimum to let more people get involved is also important.

2. Connected Worlds – Interactive ecosystem for NYSCI by Design I/O 

This interactive project uses bright colors and original designs of creatures to build interactive ecosystems. I was attracted by the setting of the hall and I also noticed that there is no instruction in the stadium. It gives the audience freedom of exploring the equipment by themselves and have their own experience. Moreover, exploring how to interact with the equipment is also a part of the interaction, which adds fun to the project. It informs me that I need to let my final project interact with the users rather than I told them how to interact with or use it. Maybe fewer instructions will be better.

What contributes to a successful interactive experience

Before I actually take this course, my definition of interaction was “a process of communication between two participators (both objects and people are all right) ” Moreover, it emphasizes the loop of effective listening, thinking, and feedback”. In other words, a successful interactive experience needs two or more participants and they need to have a complete conversation that includes the process of sending a message to receiving a response. 

Now based on the interactive projects I have made and found and the reading Art, Interaction and Engagement, I would like to explain more about the elements that contribute to a successful interactive experience. 

I think the first element is variability. When people get the same or similar feedback, they quickly get tired of interacting. Different kinds of feedback are necessary for people to continue interacting. In other words, a successful interactive experience is uncertain. Just as Edmonds has explained “It will depend on the history of interactions with the work. In this case, either the artist from time to time updates the specification of the art object or a software agent that is learning from the experiences of interaction automatically modifies the specification.” (3). Variability is the key to adding fun to the interactive equipment.

Another element is immersion. It implies the users need to have a conversation with the project by themselves. As the project Connected Worlds has shown, a successful interacting experience doesn’t need instructions from the designers or experts. Exploring during the process of interaction makes the experience even more impressive. 

   

 

Categories
Interaction Lab

Recitation 7: Functions and Arrays

Part 1: Grid Pattern

I wanted to create a more complex shape by combining different shapes. 

Here is the code:

void setup() { 
size(800, 800);
}
void draw() {  
noStroke();
background(132,192,194);
for (int i = -5; i < 70; i++){
  for (int j = -5; j < 70; j++){
  drawPicture (i*80,j*80,100,100);
    }
  }
}
void drawPicture (float u, float v, float s, float c){  
fill(132,192,194);
circle(u+60,v+60,s-20);

fill(252,222,180);
circle(u+60,v+60,s-60);

fill(132,192,194);
circle(u+60,v+60,s-70);

stroke(252,222,180);
strokeWeight(5);
line(u+88,v+88,u+32,v+32);
}

Part 2: moving shapes

Then I aimed to make these shapes move. I thought of the bubbles as the water boils and I decided to let these shapes move up and down.

Here is the code:

int n = 100;
float[] x = new float[n];
float[] y = new float[n];
float[] stepY = new float[n];
float speed = 2;
color[] c = new color[n];

void setup() { 
size(800, 800);
background(132,192,194);
for (int i=0; i< n; i++) {
    x[i] = random(width);
    y[i] = random(height);
    stepY[i] = random(-16, 16);
    c[i] = color(random(100,150), random(170,220), random(175,225));
}
}
void draw() {  
noStroke();
background(132,192,194);

   for (int i=0; i< n; i++) {
    drawPicture(x[i], y[i], 100, c[i]);
    y[i]= y[i]+stepY[i];
    if (y[i]<0 || y[i]>width) {
      stepY[i] = -stepY[i];
    }
  }
}
void drawPicture (float u, float v, float s, color c){  
fill(c);
circle(u+60,v+60,s-20);

fill(252,222,180);
circle(u+60,v+60,s-60);

fill(132,192,194);
circle(u+60,v+60,s-70);

stroke(252,222,180);
strokeWeight(5);
line(u+88,v+88,u+32,v+32);
}

Questions:

Q1: In the reading “Art, Interaction and Engagement” by Ernest Edmonds, he identifies four situations in an interactive artwork: ‘Static’, ‘Dynamic-Passive’, ‘Dynamic-Interactive’ and ‘Dynamic-Interactive(Varying)’. From the exercise you did today which situations you identify in every part you executed? Explain.

  In part one, the situation “static” happens since the shapes are still, and “There is no interaction between the two that can be observed by someone else, although the viewer may be experiencing personal psychological or emotional reactions.” (2) The computer will show the picture according to my code and I can’t change it without modifying the code just like people can’t touch the paintings in art galleries. So I think part one can be defined as “static”.

  In part two, the situation “Dynamic-Passive” happens since “The artist specifies the internal mechanism and any changes that take place are entirely predictable.” (3) The bubbles move up and down according to the code. In other words, it follows internal mechanisms.

Q2: What is the benefit of using arrays? How might you use arrays in a potential project? 

  Using arrays can make the code more simple and it is easier for people to modify the code since they only need to change one data and all relative things change. I think I will use arrays when there are a large number similar things or a lot of things follow the same order in the project. 

 

  

Categories
Interaction Lab

Recitation 6: Animating an Interactive Poster

I decided to use what I have learned in class to do this project and I got the idea of using red, yellow, and blue because of project B for Bauhaus Poster.  At first, I didn’t choose a light color background and I found it is a little bit insipid so I added different backgrounds for the letters and change the background to black. I found the trail of the bouncing balls left on the background and I solved this problem by changing the place of the background()   

 

Here is the code.

 

int x;
int y;
int p;
int q;
int a;
int b;


int speedX = 4;
int speedY = 4;
int speedP = 3;
int speedQ = 3;
int speedA = 5;
int speedB = 5;


PFont myFont;
void setup(){
  
  size(1024, 768);
  x = int (random (0, width));
  y = int (random (0, height));
  p = int (random (0, width));
  q = int (random (0, height));
  a = int (random (0, width));
  b = int (random (0, height));
  
  
  println(x);
  println(y);
  println(p);
  println(q);
  println(a);
  println(b);
 
 
  
}

void draw(){
  
 background(0,0,0);

 fill(255,0,0);
 rect(100,150, 200,100);
 
 fill(255,200,15);
 rect(50,350,630,60);
 
 fill(15,150,255);
 rect(90,450,170,60);
 
 fill(255,0,0);
 rect(130,550, 270,60);
 
 fill(255,200,15);
 rect(170,650,240,60);
  
  drawface();
  x = x+speedX;
  y = y+speedY;
  p = p+speedP;
  q = q+speedQ;
  a = a+speedA;
  b = b+speedB;
  
  if(x> width || x<0){
    speedX = - speedX;
  }
  if(y> height ||y<0){
    speedY = - speedY;
  }
  if(p> width || p<0){
    speedP = - speedP;
  }
  if(q> height ||q<0){
    speedQ = - speedQ;
  }
  if(a> width || a<0){
    speedA = - speedA;
  }
  if(b> height ||b<0){
    speedB = - speedB;
  }


  
}

void drawface() {
  
  
circle(x,y,200);
  fill(15,150,255);
  noStroke();
  strokeWeight(5);
  ellipse(x,y,200,200);
  
  
  fill(255, 255, 255);
  noStroke();
  circle(x-50, y, 10);
  circle(x+50, y, 10);
  circle(x, y, 20);
   
  
  circle(p,q,200);
  fill(255,0,0);
  noStroke();
  strokeWeight(5);
  ellipse(p,q,200,200);
  
  fill(255, 255, 255);
  noStroke();
  circle(p-50, q, 10);
  circle(p+50, q, 10);
  circle(p, q, 20);
  
  circle(a,b,200);
  fill(255,200,15);
  noStroke();
  strokeWeight(5);
  ellipse(a,b,200,200);
  
  fill(255,255,255);
  noStroke();
  circle(a-50, b, 10);
  circle(a+50, b, 10);
  circle(a, b, 20);
  myFont = createFont("Georgia",32);
  textFont(myFont);
  
  textSize(42);
  fill(255);
  text("Spring 22 End-Of-Semester Show",50,400);
  fill(255);
  text("8th floor",90,500);
  fill(255);
  text("Friday May 13",130,600);
  fill(255);
  text("6pm to 8pm",170,700);
  
  textSize(150);
  fill(255);
  text("IMA",100,200); 
   
}

Homework:  Make it Interactive

I want to make the project more interesting and I thought of scraping wax painting. I turned all the letters to black and let the mouse control three dots to move. At first, I remain the face of the previous project but I found it is too messy so I decided to delete it. 

(scraping wax painting)

Here is the code.

 

int x;
int y;
int p;
int q;
int a;
int b;

int r= 0;

int speedX = 4;
int speedY = 4;
int speedP = 3;
int speedQ = 3;
int speedA = 5;
int speedB = 5;


PFont myFont;
void setup(){
  background(0,0,0);
  size(1024, 768);
  x = int (random (0, width));
  y = int (random (0, height));
  p = int (random (0, width));
  q = int (random (0, height));
  a = int (random (0, width));
  b = int (random (0, height));
  
  
  println(x);
  println(y);
  println(p);
  println(q);
  println(a);
  println(b);
}

void draw(){
  drawface(mouseX,mouseY,1);
  drawface(mouseX,mouseY,1);
  drawface(mouseX,mouseY,1);
  if (keyPressed == true){
    r= r+1;
  }else{
    r=0;
  }
  
  x = x+speedX;
  y = y+speedY;
  p = p+speedP;
  q = q+speedQ;
  a = a+speedA;
  b = b+speedB;  
}

void drawface(float i, float j, float size) {
  fill(15,150,255);
  noStroke();
  strokeWeight(5);
  ellipse(i+28,j+28,30,30);
  fill(255,0,0);
  noStroke();
  strokeWeight(5);
  ellipse(i,j,30,30);
  fill(255,200,15);
  noStroke();
  strokeWeight(5);
  ellipse(i+28,j-28,30,30);
  

  myFont = createFont("Georgia",32);
  textFont(myFont);
  
  textSize(42);
  fill(0);
  text("Spring 22 End-Of-Semester Show",50,400);
  fill(0);
  text("8th floor",90,500);
  fill(0);
  text("Friday May 13",130,600);
  fill(0);
  text("6pm to 8pm",170,700);
  
  textSize(150);
  fill(0);
  text("IMA",100,200); 
   
}

 

 

Categories
Interaction Lab

Midterm Project Individual Reflection

Project Title: Career Express

Ran Xu (Charlotte) 

Instructor Name: Prof. Marcela Godoy

Context and Significance:

 The previous group project reminds me of using the material around and my ability to make full use of the material improved because of that. In addition, my understanding of the interaction: a process in which each participant in turn listens, thinks, and speaks can be shown in the process of the project. When a player wins, his sense of time is adjusted to the normal sense of time; in other words, it is an input and listening process. The player’s clock thinks about how to adjust accordingly after receiving the signal of winning or losing (winners tend to have the correct time, while losers have the same sense of time) is the thinking part. The corresponding adjustment of time sense given by the clock at the end (presented in the speed of pointer rotation) is the speaking part or the output part.  

We are inspired by a Bilibili short video (here is the link) and it is a short drama on a “career auction”. Near the ending of the video, a woman shout out “8000” but the host ignores her. So we intended to make a project to raise people’s awareness, especially men’s awareness of gender inequality in workplaces.

In order to make our project more scientific, we search for relative information from UNDP (here is the link) and use accurate data for our labels.

Conception and Design

  For the first part of the game, two players try their best to press the button as fast as they can and the serial monitor shows the times that they have pressed them. When one of the players first reaches 10 presses, the LED that represents him/ her lights up and the buzzer plays the melody. At first, we want to put this speed game on top of the equipment and use the cardboard as support. But we find that the competition is very fierce and the cardboard may break during the game. So we decided to put the breadboard aside. And we also want to change the design of the buttons and let them can be held in people’s hands. But we find the connection between wires and buttons is weak and we didn’t find appropriate material to make the connection stronger. In that case, we put the button on the breadboard.

For the second part of the game, the interaction part is people using the clip to stick the labels. Although it is manual, there is an interaction between the equipment and the player since he needs to use the clip manually and the label gives him relative feedback. (showing the content of notes) 

 

Fabrication and Production   

I think the most significant part of making the physical equipment.  Since at first, both Younian and I want to make combine the speed game and the UFO catcher together and put them in one piece of equipment. And in the original version, we have two players in the second round. I tried several ways to realize that target.

I forgot to take the picture of the finished first version. But I Cut two holes in the cardboard to hold the clips, then put the breadboard in the middle. But I found it’s not stable and the space for the clips are too small for players to control, so I just quit this idea.

(the original version design)

This is the second version of the equipment and at that time we supposed we can let the button be held in players’ hands. But after the user test, we found it is hard for us to realize that the second round only needs one player, so I also quit this idea. (We want to use the fruit button at first, but because of lockdown, we can’t buy apples immediately and the fruit we own is too juicy)

At last, I change the design and use a longer stick to make the clip hang on the hole. In addition, I move the light on the breadboard to the cardboard to make the result of the game clearer. Since the edge of my turntable is not connected with the equipment, poking down labels may break the turntable and the motor. So I try a different way from Younian’s and I use the clip to stick the label.

For the part of the concept, we also made changes. The original design of this project is to let women and men find their “true selves” and talks about gender labeling.  After talking with Professor Godoy, we realized that our target audience is too big and we need to focus on a specific topic. She also advised us to find some relative information such as data to make the design of labels more visual and scientific. So we changed the topic to “Career Express” and search for relative academic resources to support our project.

Younian and I find the relative code in the previous classes and recitations. Younian modify these codes to make them fit our project and I also made some modifications to the code such as the music. During this process, Professor Godoy helps us a lot with debugging. And after we made the physical equipment, we started to make the poster. We cooperate to write the content of the poster. Younian made the 3D model and I draw the 2D sketches. Then Younian combine everything together and made the amazing poster.  At last, we shoot the video and I did the editing part to make the final video.

Our Poster

Our Code 

int buzzerPin = 8;
int button1 = 10;
int button2 = 11;
int led1 = 3;
int led2 = 2;
int goal = 10;
int buttonState1 = LOW;
int previousState1 = LOW;
int buttonState2 = LOW;
int previousState2 = LOW;
int counter1 = 0;
int counter2 = 0;
boolean winner1 = false;
boolean winner2 = false;
long time = 0;
long debounce = 200;
boolean stage2 = false; // this is going to be a boolean variable that we will make true when we want to go to the second stage
void setup() {
  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  Serial.println("****ROUND 1: Once the monitor shows 【GO!!!!!!!!!!!!!!!!】, press the button as fast as you can. The one that first reaches 10 presses will win the game and can go into the 2nd round.");
  Serial.println("ROUND 2: Use the stick to poke down the label in the hole. And the game will end when you get the label with 【TRUE-SELF】 on it.****");
  delay(5000);
  Serial.println("READY");
   playBeep();
  delay(1000);
  Serial.println("SET");
 playBeep();
 playBeep();
  delay(1500);
    Serial.println("GO!!!!!!!!!!!!!!!!");
playBeep();
playBeep();
playBeep();
}
void playBeep() {
  playFreq(100, 200);
}
void playFreq(double freqHz, int durationMs) {
  //Calculate the period in microseconds
  int periodMicro = int((1 / freqHz) * 1000000);
  int halfPeriod = periodMicro / 2;
  //store start time
  long startTime = millis();
  //(millis() - startTime) is elapsed play time
  while ((millis() - startTime) < durationMs) {
    digitalWrite(buzzerPin, HIGH);
    delayMicroseconds(halfPeriod);
    digitalWrite(buzzerPin, LOW);
    delayMicroseconds(halfPeriod);
  }
} 
void loop() {
  buttonState1 = digitalRead(button1);
  buttonState2 = digitalRead(button2);
  if (counter1 < goal && winner2 == false) {
    if (buttonState1 != previousState1 && millis() - time > debounce) {
      if (buttonState1 == HIGH) {
        counter1++;
        Serial.print("player MALE: ");
        Serial.println(counter1);
        time = millis();
      }
    }
    previousState1 = buttonState1;
    if (counter1 == goal && winner2 == false) {
      winner1 = true;
      digitalWrite(led2, HIGH);
      Serial.println("PLAYER MALE WINS");
      playMelody();
    }
  }
  if (counter2 < goal && winner1 == false) {
    if (buttonState2 != previousState2 && millis() - time > debounce) {
      if (buttonState2 == HIGH) {
        counter2++;
        Serial.print("player FEMALE: ");
        Serial.println(counter2);
        time = millis();
      }
    }
    previousState2 = buttonState2;
    if (counter2 == goal && winner2 == false) {
      winner2 = true;
      digitalWrite(led2, HIGH);
      Serial.println("PLAYER MALE WINS");
      playMelody();
    }
  }
  //here we will check whether we start stage2
  if (stage2 == true) {
    moveMotor();
  }
}

void playMelody() {
  playFreq(100, 200);
  playFreq(100, 200);
  playFreq(500, 200);
  playFreq(500, 200);
  playFreq(600, 200);
  playFreq(600, 200);
  playFreq(500, 200);
  delay(100);
  playFreq(400, 200);
  playFreq(400, 200);
  playFreq(300, 200);
  playFreq(300, 200);
  playFreq(200, 200);
  playFreq(200, 200);
  playFreq(100, 200);
  delay(100);

  
  // you can find something or create your own melody for this
  //ad your melody here
  //after the melody stops we will go to stage 2
  //you can have a delay here before start moving
  delay(1000);
  stage2 = true;
}

void moveMotor() {
  float sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
  float MotorSpeed = map(sensorValue, 0, 1023, 0, 255);
  analogWrite(9, MotorSpeed);
  delay(1);        // delay in between reads for stability
}

Our video (Too big to upload. Younian uploaded this video to her Bilibili homepage and here is the link)

Conclusion

Our goal is to raise people’s awareness, especially men’s awareness of gender inequality in workplaces. We tried to express this theme by controlling some elements in the game and making it more story-telling. The result of the first-round game is fixed and only men have the opportunity to join the second round and see the labels with data on gender inequality in workplaces. In that case, men players can confront serious inequities they may not have noticed. In addition, since the first part of the game is competitive, it restores the competitive situation in the workplace to some extent to make the player more indulged. In that case, women players can also have a stronger feeling about the inequality.

Our project shows the understanding of interaction in two parts of the game and in both manual and electronic ways. If I have more time I would change the design of the button and have a better way to fix the motor. I learned that failure is normal during the process even if you know the methods. It is important to try again and make improvements to the project. In addition, communication and asking for help are important for the group project. Getting over the trouble together would make problems easier to solve.