Final Project: Intro to IM Show (Adham & Neyva)

So, here goes a shot at the description for Adham and I’s last project!

Firstly, the project did end up looking like the original idea. There was a controller which activated physical things on a board to move, which in turn caused the main character to move. The visuals even turned out cooler than I thought, as originally I wanted to paint the board, but Adham thought that projection mapping objects onto the wooden pieces on the board would look cooler. Which it did.

The project consisted of a 46in x 36in wooden board with 2 stepper motors, one servo, and 2 dc motors mounted onto it. Along with various wooden platforms for the character to walk on. In addition to this, there was a physical controller with 5 buttons which controlled each of these motors, and activated the animations for the board. The end goal is to get from the starting point, to the door in the bottom left-hand screen, and this is only possible if the user presses the buttons in the right sequence. Pressing the buttons will always cause the physical component on the board to move, but it only triggers the animation when they are pressed with correlation to where the heroine is on the board.

Here are some videos of people using our project:

I am quite proud of the code, as the animation took around 450 lines to write, making it the most code I have ever written for a project. Here is the code:

//compatible with madmapper
import codeanticode.syphon.*; 
import processing.serial.*;
Serial port;
SyphonServer server;


//right walk images
PImage[] walkRight = new PImage[10];
PImage img0;
PImage img1;
PImage img2;
PImage img3;
PImage img4;
PImage img5;
PImage img6;
PImage img7;
PImage img8;
PImage img9;

//left walk images
PImage[] walkLeft = new PImage[10];
PImage img_0;
PImage img_1;
PImage img_2;
PImage img_3;
PImage img_4;
PImage img_5;
PImage img_6;
PImage img_7;
PImage img_8;
PImage img_9;

//fire animation
PImage[] fireAni = new PImage[32];
PImage f0;
PImage f1;
PImage f2;
PImage f3;
PImage f4;
PImage f5;
PImage f6;
PImage f7;
PImage f8;
PImage f9;
PImage f10;
PImage f11;
PImage f12;
PImage f13;
PImage f14;
PImage f15;
PImage f16;
PImage f17;
PImage f18;
PImage f19;
PImage f20;
PImage f21;
PImage f22;
PImage f23;
PImage f24;
PImage f25;
PImage f26;
PImage f27;
PImage f28;
PImage f29;
PImage f30;
PImage f31;

//background designs
PImage plat;
PImage wall;
PImage ground;
PImage door;
PImage win;

//triggers
boolean standing = true;
boolean triggerWaterMill = false;
boolean triggerTrapDoor = false;
boolean triggerLift = false;
boolean triggerSpike1 = false;
boolean triggerSpike2 = false;

//count numbers
int animIndex = 0;
int animIndexFire = 0;
int animIndexFire0 = 0;

//coordinates of figure
int locX=80;
int locY=60;


int[] permissions = {0, 0, 0, 0, 0};
int timer = 120;

void setup() {
  size (920, 720, P3D);
  frameRate(10);

  server = new SyphonServer(this, "Processing Syphon");
  printArray(Serial.list());
  String portName = Serial.list()[5];
  port = new Serial(this, portName, 9600);




  //load right walk images
  walkRight[0] = loadImage("figure0.png");
  walkRight[1] = loadImage("figure1.png");
  walkRight[2] = loadImage("figure2.png");
  walkRight[3] = loadImage("figure3.png");
  walkRight[4] = loadImage("figure4.png");
  walkRight[5] = loadImage("figure5.png");
  walkRight[6] = loadImage("figure6.png");
  walkRight[7] = loadImage("figure7.png");
  walkRight[8] = loadImage("figure8.png");
  walkRight[9] = loadImage("figure9.png");


  //load left walk images
  walkLeft[0] = loadImage("figure_0.png");
  walkLeft[1] = loadImage("figure_1.png");
  walkLeft[2] = loadImage("figure_2.png");
  walkLeft[3] = loadImage("figure_3.png");
  walkLeft[4] = loadImage("figure_4.png");
  walkLeft[5] = loadImage("figure_5.png");
  walkLeft[6] = loadImage("figure_6.png");
  walkLeft[7] = loadImage("figure_7.png");
  walkLeft[8] = loadImage("figure_8.png");
  walkLeft[9] = loadImage("figure_9.png");

  //load fire images
  fireAni[0] = loadImage("fire0.png");
  fireAni[1] = loadImage("fire1.png");
  fireAni[2] = loadImage("fire2.png");
  fireAni[3] = loadImage("fire3.png");
  fireAni[4] = loadImage("fire4.png");
  fireAni[5] = loadImage("fire5.png");
  fireAni[6] = loadImage("fire6.png");
  fireAni[7] = loadImage("fire7.png");
  fireAni[8] = loadImage("fire8.png");
  fireAni[9] = loadImage("fire9.png");
  fireAni[10] = loadImage("fire10.png");
  fireAni[11] = loadImage("fire11.png");
  fireAni[12] = loadImage("fire12.png");
  fireAni[13] = loadImage("fire13.png");
  fireAni[14] = loadImage("fire14.png");
  fireAni[15] = loadImage("fire15.png");
  fireAni[16] = loadImage("fire16.png");
  fireAni[17] = loadImage("fire17.png");
  fireAni[18] = loadImage("fire18.png");
  fireAni[19] = loadImage("fire19.png");
  fireAni[20] = loadImage("fire20.png");
  fireAni[21] = loadImage("fire21.png");
  fireAni[22] = loadImage("fire22.png");
  fireAni[23] = loadImage("fire23.png");
  fireAni[24] = loadImage("fire24.png");
  fireAni[25] = loadImage("fire25.png");
  fireAni[26] = loadImage("fire26.png");
  fireAni[27] = loadImage("fire27.png");
  fireAni[28] = loadImage("fire28.png");
  fireAni[29] = loadImage("fire29.png");
  fireAni[30] = loadImage("fire30.png");
  fireAni[31] = loadImage("fire31.png");

  //load background stuff
  plat = loadImage("platform.png");
  wall = loadImage("block.jpg");
  ground = loadImage("wall2.jpg");
  door =loadImage("door.png");
  win =loadImage("win.png");
}

void draw() {
  //resets the background to white each frame


  background(255);
  if (millis()%1000 == 0){
    timer--;
  }
  text(str(timer),10,10);
  
  if (standing && !triggerWaterMill) {
    //loads the new image from the array
    PImage frameStand = walkRight[0];
    //draws this new image from the center at coordinate x,y
    imageMode(CENTER);
    image(frameStand, 80, 60, 40, 80);
  }

  //platform 1
  imageMode(CENTER);
  image(plat, 78, 115, 61, 28);
  //platform 2
  image(plat, 345, 175, 70, 28);
  //platform 3
  image(plat, 500, 209, 190, 28);
  //wall 1
  image(wall, 647, 112, 11, 182);
  //platform 4
  image(plat, 608, 414, 212, 28);
  //platform5
  image(plat, 763, 317, 70, 28);
  //platform6
  image(plat, 763, 510, 70, 28);
  //platform7
  image(plat, 551, 551, 63, 28);
  //platform 8
  image(plat, 438, 414, 178, 28);
  // //platform9
  image(plat, 79, 608, 157, 28);

  //door
  image(door, 71, 540, 90, 110);

  pushMatrix();
  translate(282, 575);
  //rotate(cos(angle))
  rotate(-PI/14);
  image(plat, 0, 0, 216, 30);
  popMatrix();

  //loads the new image from the array drawing FIRE AAYYYYY
  PImage frame0 = fireAni[animIndexFire];
  PImage frame1 = fireAni[animIndexFire0];
  //draws this new image from the center at coordinate x,y FIRE!!!!
  imageMode(CENTER);
  //ground 1
  image(ground, 75, 675, 146, 90);
  //fire 1
  image(frame1, 174, 655, 98, 200);
  //ground 2
  image(ground, 287, 675, 166, 140);
  //fire 2
  image(frame0, 394, 655, 100, 200);
  //fire 3
  image(frame1, 447, 655, 100, 200);
  //fire4
  image(frame0, 495, 655, 100, 200);
  //fire5
  image(frame1, 610, 655, 100, 200);
  //fire 6
  image(frame0, 660, 655, 100, 200);
  //fire 7
  image(frame1, 714, 655, 100, 200);
  //fire 8
  image(frame0, 820, 655, 100, 200);
  //fire 9
  image(frame1, 868, 655, 100, 200);
  //ground 3
  image(ground, 555, 675, 60, 200);
  //ground 4
  image(ground, 765, 705, 60, 200);
  image(ground, 765, 630, 60, 200);
  //ground 5
  image(ground, 900, 705, 60, 200);
  image(ground, 900, 650, 60, 200);




  //loops the animation 
  animIndexFire = (animIndexFire + 1) % fireAni.length;
  animIndexFire0 = (animIndexFire0 + 2) % fireAni.length;


  noFill();
  //draw the ladder
  strokeWeight(6);
  line(730, 100, 792, 100);
  line(730, 130, 792, 130);
  line(730, 160, 792, 160);
  line(730, 190, 792, 190);
  line(730, 220, 792, 220);

  //trampoline
  fill(255, 0, 0);
  strokeWeight(3);
  ellipse(605, 350, 50, 20);
  line(600, 360, 625, 370);
  line(625, 370, 590, 375);
  line(590, 375, 620, 385);
  strokeWeight(6);
  line(580, 385, 635, 385);



  if (permissions[0]>0 && !triggerWaterMill) {
    triggerWaterMill = true;
    standing = false;
  }
  if (permissions[1]>0) {
    if (triggerWaterMill&&!triggerTrapDoor) {
      triggerTrapDoor = true;
      standing = false;
    }
  }
  if (permissions[4]>0) {
    if (triggerTrapDoor&&!triggerLift) {
      triggerLift = true;
      standing = false;
    }
  }
  if (permissions[3]>0){
    if (triggerLift&&!triggerSpike1 ) {
        triggerSpike1 = true;
        standing = false;
      }
  }
  if (permissions[2]>0){
    if (triggerSpike1&&!triggerSpike2) {
        triggerSpike2 = true;
        standing = false;
      }
  }

  //if watermill
  //----------------------------FIRSTTRIGGER_WATERMILL---------------------------------
  if (triggerWaterMill&&!triggerTrapDoor) {
    if (locX <= 118 && locY== 60) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
    } else if (locX <= 135) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY -=3;
    } else if (locX <= 170) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY +=5;
    } else if (locX <= 260) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY ++;
    } else if (locX <= 280) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=2;
      locY +=5;
    } else if (locX <= 320) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY -=3;
    } else if (locX < 342) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
    } else {
      standing = true;
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      fuck = 1;
      //animIndex = (animIndex % (walkRight.length-1))+1;
    }
  }
  //if trapdoor
  //----------------------------SECONDTRIGGER_TRAPDOOR---------------------------------
  if (triggerTrapDoor&&!triggerLift) {
    if (locX <= 360) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
    } else if (locX <= 385) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY -=3;
    } else if (locX <= 414) {
      //PImage frame = walkRight[animIndex];
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=3;
      locY +=5;
    } 
    //double image for some reason
    else if (locX <= 605 && locY==152) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
    } else if (locY < 300 && locX<=620) {
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locY +=5;
    } else if (locY <= 315 && locX<=690) {
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY -=5;
    } else if (locY < 320 && locX<=725) {
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
      locY +=5;
    } else if (locX<=760 && locY<317) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=2;
    } else if (locX<=780 && locY>60) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locY -=5;
    } else {
      standing =true;
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      fuck = 2;

      //animIndex = (animIndex % (walkRight.length-1))+1;
    }
  }

  //if lift
  //----------------------------THIRDTRIGGER_LIFT---------------------------------
  if (triggerLift&&!triggerSpike1) {
    if (locX <= 860 && locY <=57) {
      PImage frame = walkRight[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX +=5;
    } else if (locX<=900 && locY<=416) {
      PImage frame = walkRight[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      locY +=10;
    } else if (locY>=416 && locX>=843) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX -=5;
      println(locX);
      println(locY);
    } else if (locY>=417 && locX>=802) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=4;
      locY+=4;
    } else if (locY>=461 && locX>=754) {
      PImage frame = walkLeft[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=4;
    } else {
      standing =true;
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
    }
  }
  //___________________________fourth Trigger_________________
  if (triggerSpike1 && !triggerSpike2) {
    if (locY>=386 && locX>=720) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=4;
      locY +=4;
    } else if (locY>=471 && locX>=582) {
      PImage frame = walkLeft[animIndex];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=4;
      locY -=4;
    } else if (locY>=457 && locX>=630) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=4;
      //println("here0");
      //println(locX);
      //println(locY);
    } else if (locY>=450 && locX>=610 ) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=4;
      locY+=2;
      //println("now0");
      //println(locX);
      //println(locY);
    } else if (locY<=490 && locX>=540) {
      PImage frame = walkLeft[0];
      image(frame, locX, locY, 40, 80);
      println("blah");
      println(locX);
      println(locY);
      locX-=4;
      locY+=2;
    } else {
      standing =true;
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //println("bl");
      //println(locX);
      //println(locY);
    }
  }

  //___________________________fourth Trigger_________________
  if (triggerSpike2 && triggerSpike1) {
    if (locY>=430 && locX>=480) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=5;
      locY -=5;
      //println("here1");
      //println(locX);
      //println(locY);
    }
    if (locY>=420 && locX>=475) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locY -=2;
      locX --;
      //println("here2");
      //println(locX);
      //println(locY);
    } else if (locY>=390 && locX>=378) {
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      //animIndex = (animIndex % (walkRight.length-1))+1;
      locX-=5;
      locY +=5;
      //println("b");
      //println(locX);
      //println(locY);
    } else if (locY>=390 && locX>=290)
    {
      standing =true;
      PImage frame = walkLeft[animIndex];
      imageMode(CENTER);
      animIndex = (animIndex % (walkRight.length-1))+1;
      image(frame, locX, locY, 40, 80);
      locX-=5;
      locY--;
      //println(locX);
      //println(locY);
    } else if (locY>=400 && locX>=220)
    {
      standing =true;
      PImage frame = walkLeft[animIndex];
      animIndex = (animIndex % (walkRight.length-1))+1;
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      locX-=5;
      locY+=2;
      println("now");
      println(locX);
      println(locY);
    } else if (locY>=400 && locX>=100)
    {
      standing =true;
      PImage frame = walkLeft[animIndex];
      animIndex = (animIndex % (walkRight.length-1))+1;
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      locX-=5;
      println("here");
      println(locX);
      println(locY);
    } else
    {
      standing =true;
      PImage frame = walkLeft[0];
      imageMode(CENTER);
      image(frame, locX, locY, 40, 80);
      image(win, 250, 410, 300, 300);
    }
  }
  server.sendScreen();
}

void keyPressed() {
  //watermill
  if (standing) {
    if (key == 'w' || key == 'W') {
      if (!triggerWaterMill) {
        triggerWaterMill = true;
        standing = false;
      }
    }
    //trapdoor
    if (key == 't' || key == 'T') {
      if (triggerWaterMill&&!triggerTrapDoor) {
        triggerTrapDoor = true;
        standing = false;
      }
    }
    //lift
    if (key == 'l' || key == 'L') {
      if (triggerTrapDoor&&!triggerLift) {
        triggerLift = true;
        standing = false;
      }
    }
    //spike1
    if (key == 's' || key == 'S') {
      if (triggerLift&&!triggerSpike1 ) {
        triggerSpike1 = true;
        standing = false;
      }
    }
    //spike2
    if (key == 'z' || key == 'Z') {
      if (triggerSpike1&&!triggerSpike2) {
        triggerSpike2 = true;
        standing = false;
      }
    }
  }
}

void serialEvent(Serial port) {
  String incoming = port.readStringUntil('\n');
  if (incoming!=null) {
    incoming = trim(incoming);
    if (incoming.length()>1) {
      String[] lis = split(incoming, ',');
      permissions[0] = int(lis[0]);
      permissions[1] = int(lis[1]);
      permissions[2] = int(lis[2]);
      permissions[3] = int(lis[3]);
      permissions[4] = int(lis[4]);
      println(permissions);
    }
    port.write('0');
  }
}

 

Now for a description of some of our difficulties on this proj, as there were some complications.

  1. Adham originally planned trying to make our controller wirelessly work with the board instead of using long wires. This was very time consuming, and in the end the idea was scrapped because the wireless communication was simply not working the best.
  2. This was the first time I did this type of animation on processing. Most times, I simply use photoshop for animations by making gifs, but it turns out that processing and gifs do not play nicely. Therefore, it was time to use processing for the animation.
  3. There were a TON of random bugs. Adham had trouble causing certain motors to move on the board, even after we attached wires to the proj. (In the end, one of the stepper motors just would not move.) And our first stepper motor would move, but super slowly (Not to mention that our laser cut wheel for it would occasionally fly of when the stepper spun…oops.)  Then there was also the fact that the slide potentiometer that was originally in the controller was on a logarithmic scale, making it hard to map. Another issue was the way I coded the animation, sometimes my character would slightly glitch as coordinate commands would partially overlap.  And although there were more, I can’t remember them all.
  4. After lots of help and patience from Aaron, I was able to projection map the animation onto the board. This was actually easier after I found and used the image of the girl above, instead of a stick figure drawn in processing which was originally used for testing. This was due to the fact that the image was simply drawn from the CENTER coordinate from it, while the stick figure needed to move various lines in relation to each other. In the end though, I have a better idea of how to projection map with madmapper, and I look forward to working with it more in the future.

Overall, I would say the project was a success. Although I do think we should have toned down the project a bit, I am happy with the results.

Response to Computer Vision for Artists and Designers

Before this article, I was not sure exactly what computer vision was. It was a term I had vaguely heard on occasion, but had never had described in detail.

I really liked Rafael Lozano-Hemmer’s installation Standards and Double Standards (2004) , as I think the idea of an exhibit having constant moving pieces that indicate where a viewer is standing in real time is a nice touch. I have seen something similar to this in a museum in my town, the Perot museum. It is an interactive science and history museum, and when you enter, there are a bunch of water molecules suspended on the ceiling at a certain level. When you walk under them, they “fall” or move down a couple of feet toward your position. In that way, it’s like rain that only moves when you stand under one of the molecules.

Computing and Me: My story in Poem form

Computing and Me:

Let me tell you a bit about this,

so that you can see,

what it is that computing means to me.

My first look into computing came when I saw coding.

I enjoyed it since then, let me tell you so you see,

coding to me became an expression to be free.

It became another medium for me to explore art,

to use colors I’d never held in my hand,

to explore design, my choices, and if need be lay barren my heart for the world to see.

This passion was unplanned,

and I simply hoped I could withstand  so I could understand,

how this would be a part of my future.

It is important to note that I did struggle to stay afloat,

but I realized that came from the type of coding I did.

With the visuals and graphics I felt I could gloat

but the math and logic were harder for me to grasp.

But this was only the first part of my computing view,

as next came the physical, you know, part two.

Working with sensors, motors and my Arduino

I was able to create a physical version of my art.

Another part to my art which served to jumpstart

yet another passion to use to express myself.

Don’t get me wrong,

I realize I have a long way to go,

but computing means to me the things I want to be,

because I want to show one day I can be a pro,

and use it not only for expression

but to maybe leave an impression and work in succession

to design something beautiful.

Controller Project: RGB Game

In the world of graphic design . . .

Designers have to constantly work with color values. While it is easy to simply google the R,G,B value of a color, it is a nice skill to recognize what values will output what colors.  I thought this would be a fun concept to explore visually, and so the RGB GAME controller emerged.

For this project, there is an input of 3 numbers, ranging from 0 – 255 as the Red, Green and Blue values. (Meaning 0,0,0 will be black and 255,255,255 will be white.)  I thought it would be a fun way for people to practice visually looking at colors and relating them to a numerical value (such as that used in coding.)

From there, the numbers are inputed through 3 knobs on the box/controller shown below.

(The knobs correspond to the color they edit. )
Inside look at the box as it was being wired and built.

When the game actually begins, the player must turn the knobs in order to try their best to match the color of a randomly drawn rectangle on the screen.  The values of the r,g,b values the user is altering are shown on the screen, along with a timer that counts down from 25 seconds.

Originally, I wanted the randomized rectangle that was shown on the screen to disappear after 5 seconds, and the user still had to match the new rectangle from memory. This feature was discarded after some user testing that determined this would make the game a bit too difficult.

Here is a final product video.

How the code works:

There is a range of numbers ( + or – 25) in which the code is checking to see if the random rectangle matches. There is also the timer which will display a loss if the colors are not matched after 25 seconds; a win will be shown immediately.

Here is the code:

import processing.serial.*;
PFont font; 
Serial myPort;
String[] messages;
int r;
int g;
int b;
boolean complete = false;
int begin; 
int duration = 25;
int time = 25;

int baseRectR = floor(random(0, 255));
int baseRectG = floor(random(0, 255));
int baseRectB = floor(random(0, 255));

void setup () {
  //println(Serial.list());
  font = createFont("Arial", 40); 
  textFont(font);

  begin = millis(); 
  printArray(Serial.list());
  String portname=Serial.list()[3];
  println(portname);
  myPort = new Serial(this, portname, 9600);
  fullScreen();
}
void draw() {
  background(255);
  noStroke();
  String vals =r + "  " + g + "  " + b; 
  String valsSet = "This rect was: " + baseRectR + "  " + baseRectG + "  " + baseRectB; 
  String valYours = "Your rect was: " + r + "  " + g + "  " + b; 
//checks if the colors match within a range of 25
  if ( (r-baseRectR <= 25) && (r-baseRectR >= -25) && (g-baseRectG <= 25) && (g-baseRectG >= -25) && (b-baseRectB <= 25) && (b-baseRectB >= -25))
  {
    complete = true;
    font = createFont("Arial", 75); 
    textFont(font);
    fill(0);
    text("YOU HAVE WON :)", 400, height/2);
    font = createFont("Arial", 40); 
    textFont(font);
    text(valsSet, 800, 800);
    text(valYours, 250, 800);
    noLoop();
  }
// if colors do not match after the timer is up == lose
  if (time <=0 && complete == false)
  {
    vals = null;
    fill(0);
    text("SORRY HOMIE, BETTER LUCK NEXT TIME :(", 250, height/2);
    font = createFont("Arial", 40); 
    textFont(font);
    complete = true;
    text(valsSet, 800, 800);
    text(valYours, 250, 800);
    noLoop();
  }

//displays end message
  fill(0);
  if (complete==false) {
    text(vals, 250, 800);
  }

  if (complete == false) {
    fill(baseRectR, baseRectG, baseRectB);
    rect((1.8*width)/3, height/3, 400, 400);
  }
  fill(r, g, b);
// sets timer
  if ((time > 0) && complete == false) { 
    rect(width/9, height/3, 400, 400);
    fill(0);
    time = duration - (millis() - begin)/1000;
    text(time, width/2.07, height/2);
  }
}
//reads the input
void serialEvent(Serial porty)
{
  String message = porty.readStringUntil('\n');
  if (message != null) {
    message = trim(message);
    messages = message.split(",");
    //println(message);
    r = int(messages[0]);
    g = int(messages[1]);
    b = int(messages[2]);
    //println(messages[0], messages[1], messages[2]);
  }
}

Overall, I’m super happy with how this turned out! Even the box for the controller ended up looking really cool.

Lev Manovich Response

Cinema Section:

The first thing I noticed when reading this was the author is tying together a bit too many metaphors/similes and so it makes it a bit confusing. In one page he likens books to films; movies to computer culture; the mobile camera being essential to computer culture and the “3D-ness it brings” along with a whole other plethora of comparisons and expressions. And this was all just on the first page.

He then goes on to talk about various objects such as VR, (computer) games, more on 3D space and models, and perspective. I can see his intention in this, but the jargon made it difficult to process.

HCI: Representation versus Control Section:

He then talks about remediating. I particularly liked how he brought up the example of Xerox making basic standards of interfaces, and how these were repurposed. He then talks more about these interfaces, and how they differ from books… for some reason…

Overall, some aspects he mentioned that I want to keep in mind are how culture affects design. (Such as with computer icons)

Casey Reas on Eyeo2012

When looking at the art work displayed in the presentation, I was conflicted on whether or not I liked it. I genuinely enjoyed the idea of how he made the artworks, as I am interested in generated, repeated patterns, but I didn’t actually love the end results too much. To quote Kristopher in class, some of the pieces did look a little too “crowded” or “busy”.

I enjoyed how there is a balance of semi-abstraction vs. complete abstraction, as in the pieces (including some of the other artists he talks about such as mondrian who did the colorful squares we all have seen at least once [mondrian works] )

Overall, I agree with my peers that the video tended to be a bit on the monotonous side, but overall, some interesting concepts of chaos and abstraction were explored.

Art Piece(Edited; Read New Version After Asterisk)

When I started this assignment, I knew I really wanted to make an interactive art piece for a website I am making for another class.(CommLab)

Examples of these can be found on Pierre or Aaron’s websites:

Aaron’s: http://aaron-sherwood.com/

Pierre’s: https://pierredepaz.net/

 

This led me to bite off waay more than I could chew.

I was inspired by this image:

I wanted to make something like this that would happen when a mouse rolled/hovered over certain points. I also wanted to make it in a rectangular shape similar to the one found on Pierre’s website, as it would work as a header for my site.

Boy did I pick the wrong thing.

Let me tell you what was so hard about this:

1) I had trouble randomizing dots that would appear in a circular form as in the gif above. I could get them to appear at random, but not contained in a certain area.

2) It was actually pretty hard just to get the dots to be visible actually, so I ended up making the points into crosses.

3)I couldn’t get the image to change when the mouse hovers over certain points in the code, only a general area around and above the image.

4) I couldn’t get multiple random line segments at points, only a 1:1 ratio.

5) I also didn’t know how to show the movement of the line, rather than to just have it drawn and connected to the points.(ie, show it actually moving and connecting to the other point.)

And so, here is the finished (sad) product:

DotRect rect1;

void setup (){
  fullScreen();
  //size(640, 480);
  int rectX = 450;
  int rectY= 600;
  int amount = 50;
  rect1 = new DotRect(width/25 +rectX,height-rectY, amount);
 
}
void draw (){
  background(#35465c);
  rect1.draw();
}

void mouseMoved(){
  rect1.check(mouseX,mouseY);
}
class DotRect {
  int locX, locY, amount, seed;
  //consructor
  DotRect(int x, int y, int a) {

    locX = x; 
    locY = y;
    amount = a;
    seed=0;
  }
  void draw() {
    pushMatrix();
    translate(locX, locY);
    for (int i=0; i<50; i++)
    {


      stroke(255);
      float x = random(locX);
      float y = random(locY);
      float x2 = random(locX);
      float y2 = random(locY);
      for(int m =0; m<4; m++)
      {
      point(x+m, y);
      point(x2+m, y2);
      }
      for(int m =0; m<4; m++)
      {
      point(x, y+m);
      point(x2, y2+m);
      }
      for(int m =0; m<4; m++)
      {
      point(x-m, y);
      point(x2-m, y2);
      }
      for(int m =0; m<4; m++)
      {
      point(x, y-m);
      point(x2, y2-m);
      }
      line(x,y, x2, y2);
    
    }
    delay(100);
    popMatrix();
  }
  void check(int x, int y) {
    if ((dist(x, y, locX, locY) < x) && (dist(x, y, locX, locY)<y) )
    {
      seed = millis();
    }

}

}

So what did I learn?

This was not as easy as I believed it to be, and I am sorely disappointed with my outcome.

 

**********************************************************

PLEASE READ: EDITED

So I went back and fixed my code. (After a lot of time and help from Mateo; credit to him where it is due.)

ArrayList<Dot> dots;

void setup() {
  size(1200, 200); //screen size

  dots = new ArrayList<Dot>();
  for (int i = 0; i < 50; ++i) {
    dots.add(new Dot(random(width), random(height), 5));//adds and instantiates new Dot object into the array list
  }
}

void draw() {
  background(0);
  stroke(255);
  connect();
  for (int i = 0; i < dots.size(); ++i) {
    dots.get(i).move();//makes the Dots move
    dots.get(i).render();//draws the  the Dots
  }
}

void connect() {
  int count =0; //used to limit the connecting lines between Dots
  for (int i = 0; i < dots.size(); ++i) {
    for (int j = 0; j < dots.size(); ++j) {
      if (count<=5) // limits the lines
      {
        if (dist(dots.get(i).x, dots.get(i).y, dots.get(j).x, dots.get(j).y) < 100
          && dist(dots.get(i).x, dots.get(i).y, mouseX, mouseY) < 40) {
          line(dots.get(i).x, dots.get(i).y, dots.get(j).x, dots.get(j).y);
          count ++;
//the ifs work to check if the mouse is above the area around the dots and then draws the line
        }
      }
    }
  }
}



class Dot {
  float x, y, r;
  float seedX, seedY; //needed to vary frameCount

  Dot(float _x, float _y, float _r) {
    x = _x;
    y = _y;
    r = _r;
//takes the x,y,and r values from the main program and brings them into this obj

    seedX = random(10);
    seedY = random(10);
  }

  void render() { 
    fill(255);
    ellipse(x, y, r, r);
  }

  void move() {
    x += map(noise(seedX + frameCount*0.029), 0, 1, -1, 1); //changes the x
    y += map(noise(seedY + frameCount*0.012), 0, 1, -1, 1); //changes the y such that they will move in a nice, random pattern
    //the ifs below allow for the dots to loop around if they exit the screen
    if (x < 0) {
      x = width;
    } else if (x > width) {
      x = 0;
    }
    
    if (y < 0) {
      y = height;
    } else if (y > height) {
      y = 0;
    }
  }
}

And finally, the working product!

The next step is to turn it into javascript for my commlab website!

 

Recreating a Graphic Design (Processing)

I knew starting this assignment that I wanted to work with squares, because I like the type of grid pattern they can create.

I considered doing Random Squares William Kolomyjec, as shown below:

but instead I did this piece that has been done by various people. Here is the link: http://recodeproject.com/artwork/v1n4untitled-1

Untitled 1 Various

Here is my version:

I think it would have looked better if I had kept my screen smaller, as in the example piece, but I wanted mine to be full screen while still keeping the same number of rows and columns.

Here is my code:

static final int cols = 11; // as the image showed 11 columns
static final int rows = 10; // as the image showed 10 rows

void setup() {
fullScreen();
noLoop();
}

void draw() {

rectMode(CENTER); // draws from the center to make it easier. Thank goodness for this.
strokeWeight(2);
fill(255);

int squareSize= 140;
int sizeDiff = 20;
float offsetX;
float offsetY;

for (int r = 0; r<rows; r++) // runs 10 times for 10 rows
{
for (int c = 0; c<cols; c++) // runs 11 times for 11 columns
{
offsetX = random(-5, 5);// will get a new random x each time
offsetY = random(-5, 5);// will get a new random y each time
rect(c*squareSize, r*squareSize, squareSize, squareSize); //draws the outermost squares, all the same size just in different positions
for (int n=1; n<6; n++) // runs 5 times as each square has 5 squares inside
{
rect((c*squareSize)+(n*offsetX), // takes the column/x value of my square and offsets it
(r*squareSize)+(n*offsetY), // takes the row/y value of my square and offsets it
squareSize – (n*sizeDiff), //makes the square smaller and smaller
squareSize – (n*sizeDiff));
}
}
}
}

Self Portrait

For my selfportrait, I wanted to go a bit more abstract in my design. It is truly, Picasso inspired.

This was a lot of fun to make, as I went really colorful and used a lot of abstract shapes.

Here is a photo that inspired me.

 

And so, my picture looks like this:

Here is my code:

void setup(){
fullScreen();
}
void draw(){

//peach color of skin with full opacity
//fill(240,220,200,255);
//yellow color face
fill(255, 204, 0, 20);

//draw the face outline
ellipse(660,425, 560, 620);

//forhead color
fill(255, 92, 51, 20);
//draw forehead
rect(397, 110, 528, 200);

//get rid of the color
noFill();

//top outline eye
bezier(488, 348, 518, 318, 548, 298, 600, 373);
//bottom outline eye
bezier(490, 352, 522, 387, 552, 377, 602, 377);

//get rid of the lines
//——————————–EVERYTHING PAST THIS WILL HAVE NO OUTLINE——————————————————
noStroke();

//idk what color this is
// fill(0,220,200,20);

//white color for eyes with full opacity
fill(255,255,255,255);

//inner eyeball that is now white; top part
bezier(490, 350, 520, 320, 550, 300, 600, 375);
//inner eyeball that is now white; bottom part
bezier(490, 350, 520, 385, 550, 375, 600, 375);

//color for the iris as dark purple
fill(102,0,102,220);

//draw the iris
ellipse(543, 350, 52, 48);

//(for the eyeball/pupil) black with full transparency
fill(0,0,0,255);

//draw the pupil
ellipse(543, 348, 20, 20);

//——————————–OUTLINE——————————————————
//sets the stroke to black /line for the iris details and iris outline
stroke(0);
noFill();

//outline for the iris
ellipse(543, 350, 53.5, 48);

noStroke();
//——————————–EVERYTHING PAST THIS WILL HAVE NO OUTLINE——————————————————

//sets the color to white for glare
fill(255,255,255,255);

//draw glare
ellipse(551, 342, 14, 11);

//sets color for eyebrows
fill(77, 25, 51);

//draws the left eyebrow
bezier(445,290, 490, 275, 570, 265, 625, 310);

//sets the red ellipse shadow for eye under brow
fill(204, 0 ,0, 50);

//draws the ellipse under the eye
ellipse(518, 352, 245, 150);

//sets the color for the nose
fill(255, 102, 102, 255);

//draws the triangle for the nose
//rect(635, 395, 55, 80, 3, 6, 12, 18);
triangle(600, 500, 720, 500, 665, 340);

//nose tip color
fill(255, 179, 128, 200);

//draw the nose tip
ellipse(663,485, 60,60);

//left nostril color
fill(230, 92, 0, 50);

//draw left nostril
ellipse(630, 500, 60,60);

//draw right nostril
ellipse(690, 500, 60, 60);

//nose hole
fill(0,0,0, 100);

//draw the holes
ellipse(630, 502, 20,18);
ellipse(690, 502, 20,18);

//lip color
fill(153, 0, 153, 100);

//draw the top lip
bezier(662, 570, 700, 545, 710, 545, 740, 570);
bezier(585, 570, 615, 545, 625, 545, 662, 570);

//draw the bottom of the lip
bezier(585, 570, 640, 630, 690,630, 740, 570);

//——————————–OUTLINE——————————————————
stroke(0);

//part of the mouth
line(585, 570, 740, 570);

noFill();

noStroke();
//——————————–EVERYTHING PAST THIS WILL HAVE NO OUTLINE——————————————————

//color for the hair
fill(102, 0, 41, 120);

//begin the hair
bezier(670, 150, 740, 250, 950, 380, 810, 470);

bezier(770, 150, 840, 250, 1050, 380, 910, 470);

//contrast color hair
fill(204, 0, 204, 90);

//hair multistrand1
bezier(670, 150, 700, 350, 1050, 380, 910, 470);

//hair multistrand2
bezier(700, 150, 770, 250, 980, 380, 840, 470);

//color for the hair (again)
fill(102, 0, 41, 120);

bezier(720, 150, 790, 250, 1000, 380, 860, 470);

//contrast color hair
fill(204, 0, 204, 90);

bezier(740, 150, 910, 350, 1000, 380, 860, 470);

//color for the hair
fill(102, 0, 41, 120);

//begin the hair
bezier(420, 250, 500, 80, 800, 70, 900, 250);

//contrast color hair
fill(204, 0, 204, 90);
bezier(440, 250, 500, 100, 800, 120, 900, 250);

//color for the hair
fill(102, 0, 41, 120);

//hair multistrand3
bezier(700, 150, 780, 350, 800, 380, 910, 470);

ellipse(880, 270, 50,50);
ellipse(880, 270, 50,50);

//background fill
fill(255, 255, 204, 5);
ellipse(1,1,500,500);
rect(100, 100, 500,500);
ellipse(900,900, 700, 400);
rect(40, 550, 400,300);

fill(255, 153, 255, 5);
ellipse(800,800,700,500);
rect(900, 100, 500,500);
rect(5, 550, 800,800);

fill(153, 153, 255,5);
ellipse(660,20, 700, 600);
rect(300,50, 100, 300);
rect(3, 300, 200, 400);
ellipse(1250, 450, 600, 700);

fill(153, 255, 204, 5);
rect(1000,3,700, 300);
ellipse(120, 80, 400, 600);
ellipse(1300, 800, 500, 500);

fill(204, 255, 153, 5);
rect(50, 1000, 500, 500);
}

Human Motion Project

For this project, I wanted to make something funny that related to human motion. I was heavily inspired by Ivory’s Stupid Pet Trick in which she had various human expressions made on a potted plant.

Originally, I wanted to make 2 eyeballs pop out of a face but I sadly could not get that circuit to work properly.

Instead, I went for a kissy, smoochy face. The idea is that it is blowing kisses at the viewer. It was made using a large solenoid.

The code simply used the “Blink” profile that is given in the RedBoard.