Nick and Paulin: Iron Man Shooting Game Full Documentation

So here it is. The end of our project. I honestly do not know where to begin. I guess it started as just a small idea Paulin had, and after discussing it with me our excited minds started to race towards building the game.

When we started planning the blueprint of our game, we knew that our common goal was to make the game as authentic as possible. We really desired the user to have an experience with their body as if they were Iron Man, which is why we had the kinetic camera idea along with the Iron Man glove. Moreover, we also needed the game to be like a “video game”. Not so simple, and not so easy. With that in mind, here is what we have accomplished.

Like most video games, we had a main menu and features inside it.

The menu would have buttons so that each would serve its function: play game, take a look at scoreboard, read the instructions, quit. In case you are wondering about the black screen in the middle, we decided that it would be better to have a demo before first-timers started playing the game. So we implemented a visualization of the camera so that the target could see themselves or specifically their kinetic movements to know that their aiming was supposed to be colored red, and if they pushed their arm forward (color changed to dark red) they knew they were shooting.

Inside the game, there are mainly three features. On the upper left hand side, you can see that the timer is ticking down. We set this to 2 minutes so that everyone during the showcase could have a fair chance and amount of time to play the game. On the upper right hand side, you could see a counter which measured the score. This counted the targets we killed and stored them into the array, then displaying the size of that array. Since the draw() function was looping, this was updating the whole time. On the bottom right hand side, we again had the visualization of the kinetic camera to show how the user was moving in relation to the camera’s view.

We then added targets. These would appear randomly and move in random animations as long as they were inside the screen. When the user aimed and the shooting motion was detected (the shoot was defined as object closest to kinetic camera, which was arm pushed forward) the targets would be hit and disappear. We had a cursor as well to update where the user was moving . The animations at some point were moving very smoothly, but when we tried to add another png image (Thanos) as another target to shoot, things had a bad turn and the whole game slowed down quite intensively. We managed to make it faster by cutting parts that we didn’t need, save as much CPU and memory as possible, but I believe that after a while Paulin’s Macbook Air could not handle an intensive game like this very well. That was certainly one aspect that felt really sore, but in the end it was all the effort worth it to be able to make this sort of game.

After the game, the user would enter their name and their score would appear (from the size of the score array mentioned earlier). Then both the key and value would go into the hash map, the value (score) would be sorted through another array list, and looping through the hash map we would find that score and print out the top five winners. We had to use an array list since hash map did not allow sorting, and hash map was the one of the few data structures that allowed a key:value system that would link two identities of variables together. Either way, numerous people were excited to see their scores being put up in the scoreboard after playing the game.

One of our good friends, Harper, filmed a short clip of our other good friend, Ramon, playing the game.

An earlier version of the game is hard to find since we have been building upon the same file and overwriting the progress as we went. However I do have some earlier code for my scoreboard and my overall menu that I would like to share.

PImage menupic;
PImage bpic;
PImage spic;
PImage ipic;
import controlP5.*;
import java.util.Map;
import java.util.Collections;
int state = 0;
ControlP5 a;
ControlP5 c;
ControlP5 d;
String output;
PFont b;
PFont yo; //for Scoreboard text input
final int menu = 0;
final int game = 1;
final int scoreboard = 2;
final int options = 3;
final int quit = 4;
float score = 10;
int iu = 0;
HashMap<String,Float> hm = new HashMap<String,Float>();
ArrayList<Float> al = new ArrayList<Float>();
int tracker = 0;
int counter = 0;



void setup(){
  menupic = loadImage("menu.jpg"); //menu picture
  bpic = loadImage("background.jpg"); //background picture
  spic = loadImage("scoreboard.jpg"); //scoreboard picture
  ipic = loadImage("instructions.png");
  size(1920,1030);
  
  
  
  
  
  
  //MENU INTERACTIONS
  a = new ControlP5(this); //a is for menu
  b = createFont("Verdana",30); //font for menu
  yo = createFont("Verdana",15); //font for scoreboard form
  a.addButton("Play") //name
    .setPosition(100,150) //position
    .setSize(250,200) //size
    .setFont(b) //font
    ;
  a.addButton("Scoreboard")
    .setPosition(1500,150)
    .setSize(250,200)
    .setFont(b)
    ;
  a.addButton("Instructions")
    .setPosition(100,750)
    .setSize(250,200)
    .setFont(b)
    ;
  a.addButton("Quit")
    .setPosition(1500,750)
    .setSize(250,200)
    .setFont(b)
    ;
    //C = Back Button
  c= new ControlP5(this); //c is for back button
  c.addButton("Back")
    .setPosition(1500,750)
    .setSize(250,200)
    .setFont(b)
    ;
    //D = Scoreboard
  d= new ControlP5(this); //d is for scoreboard screen
  
  d.addTextfield("Insert Name Here").setPosition(200,800).setSize(200,50).setAutoClear(false).setFont(yo);
  d.addBang("Submit").setPosition(400,800).setSize(200,50).setFont(yo);
  
    
}

void draw(){
  image(menupic,0,0);
  if(state == 0){ //Menu
    textSize(40);
    text("MENU",50,100);
    c.hide();
    a.show();
    d.hide();
  }
  else if(state == 1){ //Game
    runGame();
    score = random(50);
    
    a.hide();
    //c.hide();
    c.hide();
    d.hide();
  }
  else if(state == 2){ //Scoreboard
    image(spic,0,0);
    
    c.show();
    a.hide();
    d.show();
    
    updateBoard();
    
  }
  else if(state ==3){ //Instructions
    background(0);
    image(ipic,850,20);
    textSize(40);
    text("1. Click \"Play Game\"",300,400);
    text("2. Stand on the designated platform",300,500);
    text("3. Use your hand to aim, push your hand towards the kinect camera to shoot",300,600);
    text("4. After the game write your name, submit, and see how well you did!",300,700);
    c.show();
    a.hide();
    d.hide();
  }
  else if(state ==4){ //Quit
    exit(); 
  }
}

void runGame(){
  image(bpic,0,0);
}

void Play(){
  state = 1;
}
void Scoreboard(){
  state = 2;
}
void Back(){
  state = 0;
}
void Instructions(){
  state = 3;
}

void Quit(){
  state = 4;
}

void Submit(){ //Submit form for text input in Scoreboard
  output = d.get(Textfield.class,"Insert Name Here").getText();
  
  hm.put(output,score);
  hm.put("hey",10.0);
  al.add(10.0);
  hm.put("hi",7.5);
  al.add(7.5);
  if(score != 0){
    al.add(score);
  }
  
  //println(output);
}

void updateBoard(){
  textSize(60);
  text("SCOREBOARD",750,90);
  
  
  java.util.Collections.sort(al,Collections.reverseOrder());
   
  
    for(int i = 0; i < al.size(); i++){
     //println((float)al.get(i));
     if((float)al.get(i) != 0 && i<5){
         println((float)al.get(i));
        text((float)al.get(i),800, 300+i*60);
        
      }
    }
    


      
    for (Map.Entry me : hm.entrySet()) {
      
      Object test = me.getKey();
      
      if(test != null){
        if(al.contains(me.getValue())){
          if(tracker<5){
             text((String)me.getKey(),400,300+iu*60);
             
             iu+= 1;
             tracker+=1;
          }
        }
        else{
          continue;
        }
      }
    }
    iu = 0;
    tracker = 0;
}

 

Overall, this was very stressful at times but in the end one of the most fun projects I have worked on in my life. Building towards something that I knew other people would marvel at (did you get the pun) and enjoy playing was the true motivation Paulin and I had when we started creating this project. Although the game was lagging a bit during the game, we are still happy that people at the showcase were able to have a fun experience playing our shooting game. I hope you enjoyed reading this as well, and below is the code (main function) of our project. Farewell!

// ======== Final Interactive Media Project Spring 2019 ========= //


//----------Libraries------------------//
import processing.video.*;
import processing.sound.*;
import org.openkinect.freenect.*;
import org.openkinect.freenect2.*;
import org.openkinect.processing.*;
import org.openkinect.tests.*;
import controlP5.*;
import java.util.Map;
import java.util.Collections;

//-------- GLobal Variables----------//

PImage menupic;
PImage bpic;
PImage spic;
PImage ipic;
int state = 0;
ControlP5 a;
ControlP5 c;
ControlP5 d;
String output;
PFont b;
PFont yo; //for Scoreboard text input
final int menu = 0;
final int game = 1;
final int scoreboard = 2;
final int options = 3;
final int quit = 4;
//float score;
int iu = 0;
HashMap<String, Float> hm = new HashMap<String, Float>();
ArrayList<Float> al = new ArrayList<Float>();
int tracker = 0;
int counter = 0;


//Paulin Global Variables
//kinect
PImage img, dImg;
float angle;
Kinect kinect;
boolean shoot;
float minShoot;
float minThresh;
float maxThresh;
//Targets
ArrayList<Targets> targets;
Targets target;
//cursor
Aiming_Box aiming_Circle;
float rx, ry, scale, _rx, _ry;
float _x = 0;
float _y = 0;
//timer
int m, sec;
//score
ArrayList<Integer> score;
//Animations and sound
SoundFile blasterSound;
SoundFile avengers;
Boom boom;
Blaster blaster;
//Movie Intro;
//diframes
ArrayList<Integer> dists;
int numfc;
int threshold;
int randint, pattern;
//Timer
int begin, duration, time;
float prevWidth, prevHeight;
int shootthreshold;
Timer clock;
PImage Imheart;


//-------------------------------------------//
//-------------------------------------------//
//-------------------------------------------//
void setup() {
  //size(640, 480);
  fullScreen();
  menupic = loadImage("menu.jpg"); //menu picture
  bpic = loadImage("background.jpg"); //background picture
  spic = loadImage("scoreboard.jpg"); //scoreboard picture
  ipic = loadImage("instructions.png");

  //score = random(50);


  //Paulin's SetUP
  prevWidth = 1920;
  prevHeight = 1030;
  //Kinect
  kinect = new Kinect(this);
  kinect. initDepth();
  kinect.initVideo();
  img = createImage(kinect.width, kinect.height, RGB); 
  angle = kinect.getTilt();
  shoot = false;
  minShoot = 650;
  minThresh = 700;
  maxThresh = 780;
  //Objects
  targets = new ArrayList<Targets>();
  aiming_Circle = new Aiming_Box(); 
  //Score
  score = new ArrayList<Integer>();
  //Animation
  blasterSound = new SoundFile(this, "shortblast.wav");
  avengers = new SoundFile(this, "IMbgmus.wav");
  avengers.play();
  avengers.loop();
  boom = new Boom();
  // Intro = new Movie(this,"IMintro.mov");
  blaster = new Blaster();
  //DiffFrame
  numfc=10;
  dists = new ArrayList<Integer>(numfc);
  threshold = 40;
  scale = .1;
  //timer
  begin = millis();
  duration = 120;
  time = 180;
  _rx =_ry = 0;
  shootthreshold = 3840;
  clock = new Timer();
  //Imheart = loadImage("ironmanheart.png");

  //------------------------------------//
  //

  //MENU INTERACTIONS
  a = new ControlP5(this); //a is for menu
  b = createFont("Verdana", height*(25/prevHeight)); //font for menu
  yo = createFont("Verdana", height*(15/prevHeight)); //font for scoreboard form
  a.addButton("Play") //name
    .setPosition(width*(100/prevWidth), height*(150/prevHeight)) //position
    .setSize(int(width*(250/prevWidth)), int(height*(200/prevHeight))) //size
    .setFont(b) //font
    ;
  a.addButton("Scoreboard")
    .setPosition(width*(1500/prevWidth), height*(150/prevHeight))
    .setSize(int(width*(250/prevWidth)), int(height*(200/prevHeight)))
    .setFont(b)
    ;
  a.addButton("Instructions")
    .setPosition(width*(100/prevWidth), height*(750/prevHeight))
    .setSize(int(width*(250/prevWidth)), int(height*(200/prevHeight)))
    .setFont(b)
    ;
  a.addButton("Quit")
    .setPosition(width*(1500/prevWidth), height*(750/prevHeight))
    .setSize(int(width*(250/prevWidth)), int(height*(200/prevHeight)))
    .setFont(b)
    ;
  //C = Back Button
  c= new ControlP5(this); //c is for back button
  c.addButton("Back")
    .setPosition(width*(1500/prevWidth), height*(750/prevHeight))
    .setSize(int(width*(250/prevWidth)), int(height*(200/prevHeight)))
    .setFont(b)
    ;
  //D = Scoreboard
  d= new ControlP5(this); //d is for scoreboard screen

  d.addTextfield("Insert Name Here").setPosition(200, 800).setSize(200, 50).setAutoClear(false).setFont(yo);
  d.addBang("Submit").setPosition(400, 800).setSize(200, 50).setFont(yo);
}

void draw() {
  image(menupic, 0, 0);
  if (state == 0) { //Menu
    textSize(30);
    text("MENU", width*(150/prevWidth), height*(150/prevHeight));
    c.hide();
    a.show();
    d.hide();
    img.loadPixels(); 
   SetThresholdsandRecords();// This function goes pixel by pixel looking for the shortest distance to the sensor and will provide the values of rx and ry which will be send to the aiming box
   
   img.updatePixels(); 
   image(img,width/2-width/8 ,height/2-height/8, width/4,height/4);
    time = duration;
    begin = millis();
    for(int i=0; i<score.size();i++){
      score.remove(i);
    }
  } else if (state == 1) { //Game
    runGame();
    a.hide();
    //c.hide();
    c.hide();
    d.hide();
  } else if (state == 2) { //Scoreboard
    image(spic, 0, 0);

    c.show();
    a.hide();
    d.show();

    updateBoard();
  } else if (state ==3) { //Instructions
    background(0);
    image(ipic, 850, 20);
    textSize(40);
    text("1. Click \"Play Game\"", width*(300/prevWidth), height*(400/prevHeight));
    text("2. Stand on the designated platform", width*(300/prevWidth), height*(500/prevHeight));
    text("3. Use your hand to aim, push your hand towards the kinect camera to shoot", width*(300/prevWidth), height*(600/prevHeight));
    text("4. After the game write your name, submit, and see how well you did!", width*(300/prevHeight), height*(700/prevHeight));
    c.show();
    a.hide();
    d.hide();
  } else if (state ==4) { //Quit
    exit();
  }
}


//---------------------------Functions---------------------------------//
void runGame() {
  image(bpic, 0, 0,width,height);
  //image(Intro,0,0,width,height);
  img.loadPixels(); 
  //kinect
  SetThresholdsandRecords();// This function goes pixel by pixel looking for the shortest distance to the sensor and will provide the values of rx and ry which will be send to the aiming box
  img.updatePixels(); 
  image(img,width-width/8 - width/80,height-height/8- height/80, width/8,height/8);
  if (shoot==true) {
    pushStyle();
    fill(255, 0, 0);
    popStyle();
  }
  //Targets
  add_target();
  target_functions(); 
  //Aiming_box
  aiming_Circle.update(rx, ry, shoot);
  color TempColor = color_Aiming_Box();
  aiming_Circle.display(TempColor, shoot, blasterSound, blaster);
  //timer & Score
  timer();
  printScore();
}



void Play() {
  state = 1;
}
void Scoreboard() {
  state = 2;
}
void Back() {
  state = 0;
}
void Instructions() {
  state = 3;
}

void Quit() {
  state = 4;
}

void Submit() { //Submit form for text input in Scoreboard
  output = d.get(Textfield.class, "Insert Name Here").getText();
  //println(output);
  
    if((float)score.size() != 0.0){
      hm.put(output, (float)score.size());
      al.add((float)score.size());
    }
    
  
}

void updateBoard() {
  textSize(60);
  text("SCOREBOARD", 750, 90);


  java.util.Collections.sort(al, Collections.reverseOrder());


  for (int i = 0; i < al.size(); i++) {
    //println((float)al.get(i));
    if ((float)al.get(i) != 0 && i<5) {

      text((float)al.get(i), 1000, 300+i*60);
      println(al.get(i));
    }
  }




  for (Map.Entry me : hm.entrySet()) {

    Object test = me.getKey();

    if (test != null) {
      if (al.contains(me.getValue())) {
        //if (tracker<5) {
          text((String)test, 700, 300+iu*60);
          //println(me.getValue());
          iu+= 1;
          tracker+=1;
        //}
      } else {
        continue;
      }
    }
  }
  iu = 0;
  tracker = 0;
}

/*
      if(al.contains(me.getValue())){
 println(me.getValue());
 if(hm.containsKey(me.getKey())){
 if(me.getValue() != null){
 text((String)me.getKey(),700,500-iu*100);
 text((float)me.getValue(),1000, 500-iu*100);
 iu+= 1;
 }
 
 }
 }
 }
 iu = 0;
 */

//----Paulin's Function----// 
void SetThresholdsandRecords() {
  PImage dImg = kinect.getDepthImage(); //To get the default kinect image to find manually the thresholds
  //image(dImg,0,0); 
  shoot = false;
  int record = 4500;
  _x=_y=0;
  int totdis;
  float total =0;
  int[] depth = kinect.getRawDepth();
  for (int x = 0; x<kinect.width; x++) {
    for (int y =0; y< kinect.height; y++) {
      int offset = x + y*kinect.width;
      int d = depth[offset];
      if (d>=minThresh && d<maxThresh) {
        img.pixels[offset] = color(245,72,72);
        //if (d<record) {
          //record = d;
         _x+=x;
         _y+=y;
        //}
        //_x+=x;
        //_y+=y;
        total++;
      } else  if (d>=minShoot && d<=minThresh){
        img.pixels[offset] = color(255,0,0) ;
        shoot=true;
        _x+=x;
        _y+=y;
        total++;
      }
      else{
       img.pixels[offset] = color(0,0,0) ; 
      }
    }
  }

  if (total>0) {
    _x= _x/total;
    _y= _y/total;
  }
 

  _rx += ((640-_x)-_rx)*scale;
  rx = map(_rx, 150, 640-150, 0, width);
  _ry += (_y-_ry)*scale;
  ry = map(_ry, 110, 480-110, 0, height);
  //ellipse(rx,ry,30,30);
  //dists.add(record);
  //if (dists.size()==numfc)
  //  dists.remove(0);
  //totdis = dists.get(0) - dists.get(dists.size()-1);
  ////println("totdis -> ",totdis);
  //println(totdis);
  //if (totdis>shootthreshold) {
  //  shoot =true;
  //}
  //println("shoot ->", shoot);
}

//To provide a different color to the aiming box if it is shooting
color color_Aiming_Box() {
  color Color;
  Color = color(255, 255, 255);
  for (int i = 0; i<targets.size(); i++) {
    if (aiming_Circle.rx>targets.get(i).x
      &&aiming_Circle.rx<(targets.get(i).x+targets.get(i).w)
      &&aiming_Circle.ry>targets.get(i).y
      &&aiming_Circle.ry<(targets.get(i).y+targets.get(i).h)) {
      Color = color(255, 0, 0);
      break;
    }
  }
  return(Color);
}

//To move the angle of the kinect
void keyPressed() {
  if (key == CODED) {
    if (keyCode == UP) {
      angle++;
    } else if (keyCode == DOWN) {
      angle--;
    }
    angle = constrain(angle, 0, 30);
    kinect.setTilt(angle);
  }
}    

//Set up timer in the right corner
void timer() {
  float lettersize = height*.054;
  float timerposition = width*.04125;
  float Yposition = height*.08125;
  float position = timerposition + (width*.125);
  //float secondposition = position + (width*.022);
  if (time > 0) {  
    time = duration - (millis() - begin)/1000;
    pushStyle(); 
    stroke(188, 23, 23);
    strokeWeight(width*.003);
    fill(188, 166, 23, 100);
    ellipse(timerposition+width*.01, Yposition-lettersize/3.1+height*.01, height*.128, height*.128);
    fill(255);
    textSize(lettersize);
    text(time, timerposition-width*.02, Yposition+height*.01);
    popStyle();
  }
  if (time ==0) {
    state = 2;
    textSize(40);
    text("GAME OVER!: ", 600, 90);
  }
} 

// add a target  every 120 frames
void add_target() { 
  randint = int(random(3));
  pattern = int(random(45));
  if(frameCount%10==0){
    targets.add(new Targets(shoot, randint, pattern));
  }
  //if(time<60 && time>30){
  //if (frameCount%80==0) {
  //  targets.add(new Targets(shoot, randint, pattern));
  //}
  //}
  //else if (time>60 && time<90){
  //   if (frameCount%100==0) {
  //  targets.add(new Targets(shoot, randint, pattern));
  //}
  //}
  //else if(time>90){
  //      if (frameCount%100==0) {
  //  targets.add(new Targets(shoot, randint, pattern));
  //}
  //}
  //else if(time<30){
  //          if (frameCount%120==0) {
  //  targets.add(new Targets(shoot, randint, pattern));
  //          } 
  //}
}

//All the targets functions
void target_functions() {
  for (int i = 0; i<targets.size(); i++) {
    targets.get(i).display();
    targets.get(i).destroy(shoot, aiming_Circle);
    targets.get(i).update();
    if (targets.get(i).destroyed == true) {
      //println("Object being destroyed -> target size -> ",targets.size());
      //blasterSound.play();
      boom.display(targets.get(i).x, targets.get(i).y);
      targets.remove(i);
      score.add(i);
      //println(" destroyed -> target size -> ",targets.size());
    }
  }
}

void printScore() {
  float lettersize = height*.054;
  float Yposition = height*.08125;
  float ScorePos = width*.75;
  float PointPos = ScorePos + height*.15;
  float numPos = PointPos + height*.03;
  pushStyle();
  stroke(188, 23, 23);
  strokeWeight(width*.003);
  fill(188, 166, 23, 100);
  ellipse(numPos+width*.09, Yposition-lettersize/3.1+height*.01, height*.128, height*.128);
  fill(255);
  textSize(lettersize);
  //text("Score", ScorePos, Yposition);
  //text(":", PointPos, Yposition);
  text(score.size(), PointPos+width*.095, Yposition+height*.01);
  popStyle();
}

void intro() {
}

 

Computer Vision for Artists and Designers: Pedagogic Tools and Techniques for Novice Programmers (Response)

I definitely enjoyed this week’s reading since it brought up numerous critical points and inspiring thoughts from me.

To begin with, I was inspired by the fact that computer vision has detached from an esoteric, high-privileged scheme into something that everyday artists and users can utilize to add to their performances. For instance, I was amazed by “Cheese”, the installation by Christian Moller because it has a very intriguing objective and the process of using computer vision to achieve that is interesting as well. Basically, from what I understood, there is a level-meter that is able to detect the actress’s smile and analyze how happy she seems. Unfortunately, I wish there was a more technical explanation for that since I was very curious on how it exactly worked rather than just what it was.

Other than that, I admired the way that the author attempted to introduce the mechanisms for how each installation worked, along with the fundamentals of computer vision techniques and algorithms at the latter part of the article. Since Paulin and I are also using computer vision in our final project, this article has been so helpful in the sense of what to use, when to use, and how to use. Now that I’ve read the article, maybe we can switch up for our project and even try out Infrared Illumination in a dark panel for our Iron Man glove. It is definitely an option, and we will have to discuss more to find the optimal solution.

In Class Exercise

For the in-class exercise, I decided to build up upon what we did during class with the pixels and played around with some of the variables. I had my own image from Thanos and first changed the ellipses to rectangles. Then, in the “pix” variable, I wanted to add a random integer from 0 to 99 to add to the color of pix in order to have a “bling” effect where the image would constantly sparkle like it is a GIF. I knew this was possible since the draw function acts like a loop, and the random values will constantly add differently every time the loop goes on.

I also played around with the constrain of increment, but one question I had in mind was “how to reverse the constrain?”, as in how do I make it so that the image zooms in the more I go left rather than right, the more I go up rather than down, etc. Because when I just reversed the values in the constrain function (1,990) to (990,1), the image would not zoom out. So maybe if I search online a bit more I will understand why this is happening.

Here is how the whole thing works, and before that is the code. Note that the main function is provided by Prof. Aaron Sherwood.

PImage a;
int x =0;
int y= 0;
int increment = 10;
void setup(){
  
  background(255);
  size(990,600);
  a=loadImage("jeff2.jpg");
  
  
}

void draw(){
  
  
  background(0);
  
  a.loadPixels();
  for (int y=0; y<height; y+=increment) {
    for (int x=0; x<width; x+=increment) {
      int loc = x+(y*width);
      color pix=a.pixels[loc]+int(random(100));
      fill(pix);
      rect(x,y,increment,increment);
    }
  }
  a.updatePixels();
  increment=constrain(mouseY,1,600);
  
  
  
  
  
  
}

Ironman Project: Update 5/1/19

Concept of the Project:
After the feedback received in class, the concept of the remains the same. We will make a 3D video game that simulates that the user is using the iron man glove to shoot at objects.

Materials Needed:
– Infrared WebCam
– Infrared Light
– IronMan Cable
– A bluetooth arduino that send instructions to the infrared light(if it exist)
– If the above material does not exist, then batteries and a small plastic box that allow us to put the arduino in the glove without causing any accident.
– T.V or projector to screen the video game

Building the project:
The building process will be divided in two main parts: Physical Computing and creating the video game environment. The physical computing consists of building a remodeling of an iron man sensor with an infrared light that allows an infrared webcam detect the location of the glove. The glove will need to be as similar as possible as the iron man glove to create a better experiences with the user. The user in the other hand will have a button that allows them to shoot wherever they are aiming with the glove.

Creating the video game environment consists of using processing to create video game interaction. Our Processing program will receive the location of the glove and will map it to an aiming box that will show up in the screen and will move according to the glove movement. The background will recreate an iconic landscape from one of the Iron Man or Avengers movies in order to immerse the user into the story. Iconic Iron Man enemies will show up for a few seconds and these will be the targets that the user must destroy to earn points. Also, to bring more activeness to the user in the video game, AC/DC and Iron Man music will be played while the user is playing the game.

Biggest Challenges:
– Many Marvel fans have always wanted to know how does it feel to be iron man, and we hope that the interactivity of this game would have enough quality to cause that sensation.
– One of the biggest challenges will be to build a glove that gives the sensation to the user that is an actual iron man glove. That would be a key to achieve the interactivity that we want
– Another challenge is to create a video game environment that causes the user to feel that he or she is part of the Iron Man Universe. We do not only want the user to feel that they are inside of the iron man suit but also that they traveled to the MCU universe

Lessons from Computing

As a CS major, I have been “computing” for a long time, so in that field the new experiences I had were mostly learning more about Arduino and Processing. But in other senses, computing this semester has helped me in other ways. Some days, when projects are due, I would pull an all-nighter to work things out and get tasks done, and for my midterm project that was the similar case. Actually, for Intro to IM in general, I used the computer for prolonged periods of time since most of the work done was on Arduino or Processing. This experience of using the computer for IM and multiple other classes simultaneously for a long time taught me a valuable lesson.

That lesson is to take a break. It might sound simple, but there are a lot of instances I see where people are frustrated with coding and their minds are filled with stressed. I feel that way too sometimes. But this semester especially, when I felt that I could not work after a few hours, I would take nature walks and small breaks where I would eat some snacks and talk to other people. This really aided in re-organizing my thoughts and when I came back I would perform better and sometimes realize that it was only a small mistake I made that was preventing my work from functioning properly. Now that I practice this method from time to time, I believe it has and will help me numerous times in throughout my lifetime.

LED CONTROLLER

For this week’s project, I had the choice of making a physical input or output, given that I just needed to use the serial monitor to connect between Arduino and Processing. So I decided to make an LED controller that would switch on if you press the button for each one, and would turn off if you pressed an “off” button.

Overall it was not bad, but I had a few mistakes especially since I was using a new library and I had to get used to the syntax. Also, when I created the functions for each of the buttons, I didn’t know the names had to match but that was silly of me, since the functions wouldn’t work obviously if the names didn’t match. Finally, it was interesting to see that when Processing uses the “COM4” port that my Arduino is linked to, I cannot open the Serial Monitor in Arduino since it says that my Serial Port is busy (probably used in Processing).

The program is simple: it uses characters transferred within the Serial Monitor to communicate between the hardware and the software. The functions in Processing write on the port the characters that match with the buttons, then the Arduino reads those characters and if they match with each LED color (code in Arduino) the corresponding lights will turn on.

Below is the code, the pictures, and a video of me testing it out!

Arduino:

void setup(){
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);

  Serial.begin(9600);
}

void loop(){
    
   if(Serial.available()){
    char val = Serial.read();

    if(val == 'r'){
      digitalWrite(8,HIGH);
    }
    if(val == 'b'){
      digitalWrite(9,HIGH);
    }
    if(val == 'g'){
      digitalWrite(10,HIGH);
    }
    if(val == 'f'){
      digitalWrite(8,LOW);
      digitalWrite(9,LOW);
      digitalWrite(10,LOW);
    }
    }
   }

Processing:

import controlP5.*;
import processing.serial.*;

Serial port;
ControlP5 a;
PFont b;
void setup(){
  size(400,600);
  
  printArray(Serial.list()); //print available ports
  port = new Serial(this,"COM4",9600); //connection time!  
  a = new ControlP5(this);
  b = createFont("Verdana",30);//bigger font to put for the buttons 
  
  
  //buttons:
  a.addButton("red") //name
    .setPosition(30,150) //position
    .setSize(150,100) //size
    .setFont(b) //font
    ;
  a.addButton("blue")
    .setPosition(220,150)
    .setSize(150,100)
    .setFont(b)
    ;
  a.addButton("green")
    .setPosition(30,350)
    .setSize(150,100)
    .setFont(b)
    ;
  a.addButton("off")
    .setPosition(220,350)
    .setSize(150,100)
    .setFont(b)
    ;
}

void draw(){
  background(227,154,118);
  textSize(15);
  text("INSTRUCTIONS: PRESS A BUTTON AND FIGURE OUT!",15,50);
  
  
}

void red(){
  port.write('r');
}
void blue(){
  port.write('b');
}
void green(){
  port.write('g');
}
void off(){
  port.write('f'); //press f in chat  
}

Images:

The Controller:The LEDs:

Video:

Generative Text

For this week’s project, I decided to base my work on a popular movie, an old one though: V for Vendetta. My work, which uses the manipulation of text, is divided into two parts.

The first part is a big V, but only if you look closely can you see the detail. In a nested for loop, I made the V so that every line would have three “v”s, with each character being less transparent than the one before. This, however, doesn’t show much since the characters are two close together but if you look closely you might spot a slight color difference.

For the next part, I made a simple rotation scheme where I would have it so that the big V would stay there but the characters around it would orbit in a circle so that it would altogether spell out “Vendetta”.

PFont myFont;
char v = 'v';
int z = 15;
int x = 100;
int y = 100;
float a = 400;
float b = 500;
float r = 30;
String s = "ENDETTA";
void setup(){
  size(750,750);
  background(200,0,0);
  myFont = createFont("Helvetica",40);
  textFont(myFont,40);
  textAlign(CENTER);
}

void draw(){
  
  int x = 170;
  int y = 100;
  for(int i=0;i<20;i++){
    
    for(int j=0;j<3;j++){
      //println(z);
      color a = color(19,24,98,z);
      fill(a);
      text(v,x,y);
      x += 3;
      z -= 5;
      
      
    }
    z = 15;
    
    y += 20;
    
  }
  for(int i=0;i<21;i++){
    
    for(int j=0;j<3;j++){
      //println(z);
      color a = color(19,24,98,z);
      fill(a);
      text(v,x,y);
      x += 3;
      z -= 5;
      
      
    }
    z = 15;
    
    y -= 20;
    
  }
  
  text("IS FOR",375,550);
  a = 400;
  b = 500;
  float mb = 0;
  //pushMatrix();
  //translate(400,500);
  translate(350,500);
  for(int i=0;i<s.length();i++){
    char d = s.charAt(i);
    float h = textWidth(d);
    
    mb += h/2;
    float theta = PI + mb/r;
    
    pushMatrix();
    translate(r*cos(theta),r*sin(theta));
    rotate(theta+PI/2);
    text(d,170,170);
    popMatrix();
    mb += h/2;
    
  }
  //popMatrix();
  
  
}

 

Paintings speak better than words. Here is my final creation:

Response: The Digitization of Just About Everything

So this week’s reading was very interesting in the sense that I was able to relate the content and examples of the article with lessons from another class. In “Cyberwarfare”, the other class I am taking, we have discussed how users are unexpectedly always providing data to businesses such as Facebook or Netflix when we are using their products. I feel like the same is happening with Waze. In order to have a better experience, as it says in the article, more people have to use it, since the app has to record date and time and therefore can reuse the log once another person makes the same trip. I know this data gathering from people is for a positive use as shown in the Waze example, but I would be careful since privacy invasion is also a significant matter these days and giving your information to navigator apps like Waze also could expose yourself to anyone who wants to track you down.

In the second part, to see digitization in an economic perspective, I get the author’s point, and it is certainly true that digitization has made our lives much more convenient in numerous methods. However, I do think that the author is too positive about this change, and I have a few reasons on why I politely disagree with this notion.

To begin with, digitization also means that any sort of data can be pirated. This is extremely harmful in the cases of starting musicians or artists who want to make cash by selling their work online. It is cool if I share my pdf book file to Hank, but to do that for free? If I pay and he doesn’t, but I still share it to him because he is my friend, the author gets half the price of the book in the real world. Currently, torrenting has become a huge problem in our modern society, especially in terms of copyright claims and what not. I think, in that sense, there are still perks as to why keeping some objects in the physical world might be more safe.

Similarly, data breaches are also very dangerous. This ties to the first argument, but I want to talk more about subjects such as finance or personal information. Let’s look at finance, for example. If I have my money in a bank or a safe, it will be arduous for a robber to steal my money. Even if they do, chances are I will use CCTV cameras or fingerprint scanning, even collecting hair in the suspected areas to go on to find who the suspect is. However, cyber-security is not as developed yet, and in the cyber world it is way harder for police to digitally track down someone. This of course, leads to individuals getting away and even sometimes groups of people working for nations, as we have seen in the Russian hacking of elections a few years ago.

Overall, I like the concept of the article and it has taught me new things that I previously did not know, but I wish the author put in the opposite perspective’s views, especially in terms of how digitization can be disruptive and negative so that we should always be cautious but it can still be beneficial if used correctly. Unfortunately, there does not seem to be too much negative connotation that can provide alert and warning to the readers, which I personally believe is very significant.

Memory Card Game

For this project, I decided to make a memory card game where the user would be given a set of cards and would have to match two cards in order to get rid of them, until the game ends of course.

I originally got this idea from Meri Engel, so I will leave a link to her youtube channel below.

https://www.youtube.com/channel/UCjBGQA6hPD3SY4G5feqMDFw

So, now on to the procedure.

To do this I first created a class called Cards that would have values of its x-coords, y- coords, FaceValue, etc. Moreover with the certain attributes, the class would also have functions such as faceDown() or displayFront() which would flip the card back and forth.

In the main part of my code, interactions with the cards began. I would have an array that would store two flipped cards, and then check if they were the same. Before that, I had a shuffle function that would randomly shuffle the cards in different order, since without shuffling they would be placed in same order every time. Finally, the mouseClicked() function would serve as where I would click in terms of coordinates and if so what would happen, which of course would be to flip the cards. But even here, I didn’t want to flip more than two cards so I have a switch that flips back the cards.

Below is my code, and below that is the youtube video of me explaining how it works.

Cards[] myCard = new Cards[6];
int[] x = new int[6]; //x coordinate array
int[] y = new int[6]; //y coordinate array
int[] fv = new int[6]; //facevalue array
int[] checkFv = new int[2]; //check face value
int[] cardUp = new int[2]; //check card up
boolean[] clicked = new boolean[8];
PImage flip;
PFont  myFont;
int flipped = 0;
int win = 0;

void setup(){
  int myX = 15; // x coord
  int myY = 15; // y coord
  int myFv = 0;
  int count = 1;
  size(1000,1000);
  myFont =createFont("Verdana",40,true);
  flip = loadImage("flip.png"); // flip button
  
  
  for(int i =0; i<6;i++){   //spacing out the cards
    clicked[i] = false; //can't click card again  
    y[i] = myY;
    x[i] = myX;
    fv[i] = count;
    count += 1;
    if(count == 4){ // number of replicates
      count = 1;
    }
    if(myX <345){
      myX += 250;
    } else if (myX >345){
      myX = 15;
      myY += 400;
      
    }
  }
  
  shuffle();
  for(int i=0;i<6;i++){
    myCard[i] = new Cards(x[i],y[i],fv[i]); //each card is assigned coordinate value
  }
}

void draw(){
  
  textFont(myFont);
  fill(0);
  background(255);
  
  for(int i=0;i<6;i++){
    myCard[i].display();
  }
  
  image(flip,500,750);
  
  if(mousePressed){
    if(mouseX>500 && mouseX<600 && mouseY > 770 && mouseY<880){
      for(int i = 0; i<6;i++){
        myCard[i].faceDown();
        clicked[i]=false;
        flipped=0;
      }
    }
  }
  if(win == 3){
    text("You Win!",500,500);
  }
}
/*
void flipme(){//flipperino
  for(int i=0;i<6;i++){
    if(mouseX>x[i] && mouseX<(x[i]+305) && mouseY > y[i] && mouseY<(y[i]+350)){
      myCard[i].displayFront();
    }
  }
 
}
*/
void mouseClicked(){
  for(int i=0;i<6;i++){
    if(mouseX>x[i] && mouseX<(x[i]+250) && mouseY > y[i] && mouseY<(y[i]+300) && (clicked[i]==false)  ){
      myCard[i].displayFront();
      clicked[i] =true;
      cardUp[flipped] = i;
      
      flipped++;
      println(flipped);
      if(flipped == 2){
        flipped = 0;
        
        if(fv[cardUp[0]] == fv[cardUp[1]]){
          myCard[cardUp[0]].matched();
          myCard[cardUp[1]].matched();
          win += 1;
        }
        /*else if(fv[cardUp[0]] != fv[cardUp[1]]){
          myCard[cardUp[0]].display();
          myCard[cardUp[1]].display();
          myCard[cardUp[0]].faceDown();
          myCard[cardUp[1]].faceDown();
          clicked[i] = false;
          clicked[i+1] = false;
          
        }
        */
        
      }
    }
  }
  }
  
void shuffle(){//shufflerino
  int temp = 0;
  int rand = 0;
  for(int i=0; i<6;i++){
    rand = int(random(0,6));
    temp = fv[i];
    fv[i] = fv[rand];
    fv[rand] = temp;
  }

}
class Cards{

  PImage cardImage;
  int show = 0;
  //int cWidth = 105;
  //int cHeight = 130;
  int cX = 0;
  int cY = 0;
  int faceValue = 0;
  String[] cardName ={"0.png","creep.png","isabelle.png","kk.png","psycho.png","digby.png","tomnook.png"};
  
  Cards(int x, int y, int fv){
    cX = x;
    cY = y;
    faceValue = fv;
  }
  
  void display(){
    cardImage = loadImage(cardName[show]);
    image(cardImage,cX,cY);
  }
  
  void displayFront(){
    show = faceValue;
  }
  
  void faceDown(){
    show = 0;
  }
  void matched(){
    cX = -300;
  }
  
  
}

Design Meets Disability: Comment

Disability is surely not a new concept that I have encountered. In fact, the course that I take right before my Intro to IM class is called “Dis/abilities in Musical Context”. However, this approach was something I had not met before: how design is crucial to suit people with needs.

Before reading this article, when debating upon the creation of devices for disabled people, I assumed that technicality would be above all else. For instance, if the hearing aid is not loud enough, it is basically useless to someone. Or if colorblind glasses do not work properly, that too would be a reason for colorblind people to neglect that product. However, by thinking this way, I diminished the importance of ‘design’.

One valuable lesson I learned is that design matters as much as technicality. If a product works, but is not fit for the person’s body, what much use is there to it? That was one question I failed to acknowledge before. And especially for disabled people, because their degrees of disability may vary (which may lead to different body shapes and sizes) it is also arduous to come up with one single design that can fit every disabled person.

I have learned, ultimately, that not only is design significant for certain aids, but it is definitely a hard task to complete as numerous obstacles are in the way.