Ticha-Bots and Bitrain

Sketch:

initial sketch

Result:

 

Coding this was awkward. I never imagined that drawing without a stylus and mouse would be so tedious and time-consuming. Thankfully, I was able to make most of the measurements + find the pixel locations using my Photoshop file and the surprisingly handy Ruler Tool. As far as the animation goes, in general I am more satisfied with the final composition than the initial draft. The use of binary bits instead of conventional rain makes for a more interesting composition, and the ‘bit splashes’ in the foreground are a nice touch. Additionally, the too-small umbrella gives the animation a more comical feel. The gif itself is actually a little slower than the real one; I tried removing some frames manually but decided not to mess with it too much to avoid losing the flow of the animation (Here’s what it’s supposed to look like). I think I somewhat succeeded in giving the animation some dimensionality despite how I was limited to working with more simple tools, as opposed to working with different special effects that are available in typical animation programs. I attempted to make the robot look round by adding some simple shading and tried to give depth to the bitrain by making its color range from medium gray to white.

Still, I wish that *more* animation could be involved and that the piece could be more compositionally interesting. I added a ‘lightning’ feature briefly but decided to remove it when I felt like I was ready to have a seizure. Perhaps what it needs the most is a more interesting environment, as gray is not very exciting to look at. However, I would also have to learn how to strike a balance between minimalism and detail – as the best animations / works of art are able to use both to strengthen the overall piece.

Here is the code which is probably longer than it should be (I have no idea why WordPress add more lines at the bottom):

/* Thanks Golan for the reference code! 
 Credit to LearningProcessing for oscillation reference.
 
 */

int     nFramesInLoop = 160;
int     nElapsedFrames;
boolean bRecording; 
float theta = 0; 
float theta2 = 0;
float x;


//===================================================
void setup() {
  size(500, 500);

  bRecording = false;
  nElapsedFrames = 0;

  x = width/2-100;
}
//===================================================
void keyPressed() {
  bRecording = true;
  nElapsedFrames = 0;
}

//===================================================
void draw() {

  // Compute a percentage (0...1) representing where we are in the loop.
  float percentCompleteFraction = 0; 
  if (bRecording) {
    percentCompleteFraction = (float) nElapsedFrames / (float)nFramesInLoop;
  } 
  else {
    percentCompleteFraction = (float) (frameCount % nFramesInLoop) / (float)nFramesInLoop;
  }

  // Render the design, based on that percentage. 
  renderMyDesign (percentCompleteFraction);

  // If we're recording the output, save the frame to a file. 
  if (bRecording) {
    saveFrame("output/myname-loop-" + nf(nElapsedFrames, 4) + ".png");
    nElapsedFrames++; 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
} 

void renderMyDesign(float percent) {
  background(#464646);
  smooth();
  noStroke(); 
  strokeWeight(2);
  //----------------------
  // Here, I assign some handy variables. 
  float cx = 100;
  float cy = 100;

  robotLegs();
  robotBody();
  robotHead();
  robotArms(); 

  textSize(40);
  fill(255);
  text("Error 404;;", x, 100);

  textSize((int)random(10, 22));
  pushMatrix();
  translate(-75, 30);
  rotate(radians(-8));

  //rain effect
  for (int i = 0; i < 80; i++) {
    int w = int(random(width+40));
    int h = int(random(height+40));
    fill(random(70, 255));

    int rand = (int)random(2);
    String bit = (rand == 0)? "0" : "1";

    text(bit, w, h);
  }

  popMatrix();

  pushMatrix();
  translate(-60, 480); 

  textSize(18);
  //rain effect
  for (int i = 0; i < 100; i++) {
    int w = int(random(width+40));
    int h = int(random(height/8));
    fill(random(70, 255));

    int rand = (int)random(2);
    String bit = (rand == 0)? "0" : "1";

    text(bit, w, h);
  }
  popMatrix();
  /*
  // If we're recording, I include some visual feedback. 
   if (bRecording) {
   fill (255, 0, 0);
   textAlign (CENTER); 
   String percentDisplayString = nf(percent, 1, 3);
   text (percentDisplayString, cx, cy-15);
   }*/
} 

void robotHead() {
  float a = map(sin(theta2), -1, 1, -5, 5); //shaking
  theta2 += 0.6; //lower values slow down the movement

  //head 
  fill(#e24b00);
  ellipse(257 + a, 250, 124, 84);
  fill(#f25d13);
  ellipse(257 + a, 243, 115, 70);
  fill(#f67535);
  ellipse(257 + a, 235, 110, 50);
  //shiny
  pushMatrix();
  translate(270 + a, 220);
  rotate(radians(8));
  fill(#ffb793);
  ellipse(0, 0, 30, 10);
  popMatrix();

  //left eyebrow
  stroke(#1c1c1c); 
  strokeWeight(2.6);
  line(223 + a, 245, 223, 238);
  noStroke();
  fill(#1c1c1c);
  pushMatrix();
  translate(213 + a, 236);
  rotate(radians(-10));
  rect(0, 0, 20, 6);
  popMatrix();

  //left eye
  fill(#1c1c1c);
  ellipse(224 + a, 255, 20, 20);
  fill(#ebcb88);
  stroke(50); 
  strokeWeight(2);
  ellipse(224 + a, 255, 13, 13);
  noStroke();

  //right eyebrow
  stroke(#1c1c1c); 
  strokeWeight(2.6);
  line(283 + a, 235, 283, 248);
  noStroke();
  fill(#1c1c1c);
  pushMatrix();
  translate(273 + a, 230);
  rotate(radians(10));
  rect(0, 0, 25, 6);
  popMatrix();

  //right eye
  fill(#1c1c1c);
  ellipse(284 + a, 255, 25, 25);
  fill(#ebcb88);
  stroke(50); 
  strokeWeight(2.6);
  ellipse(284 + a, 255, 16, 16);
  noStroke();

  //left ear
  fill(#1c1c1c);
  rect(186 + a, 230, 15, 44, 7);
  ellipse(185 + a, 252, 10, 30);
  stroke(#1c1c1c); 
  strokeWeight(3);
  line(181 + a, 253, 165 + a, 253);
  line(165 + a, 253, 160 + a, 247);
  line(160 + a, 247, 155 + a, 253);
  line(155 + a, 253, 152 + a, 253);

  //right ear
  rect(310 + a, 230, 15, 44, 7);
  ellipse(326 + a, 252, 10, 30);
  stroke(#1c1c1c); 
  strokeWeight(3);
  line(323 + a, 253, 343 + a, 253);
  line(343 + a, 253, 348 + a, 247);
  line(348 + a, 247, 353 + a, 253);
  line(353 + a, 253, 360 + a, 247);

  //line across middle
  noFill();
  stroke(#9e3b0a); 
  strokeWeight(1.5);
  line(257 + a, 209, 257 + a, 291);

  //bolts
  int b=0;
  for (int i = 1; i <= 5; i++) {
    ellipse(250 + a, 218+b, 4, 4);
    b+=12;
  }
  noStroke();
}

void robotBody() {
  //body
  fill(#f25d13);
  arc(241, 347, 130, 159, radians(-32), radians(213), OPEN);
  fill(#fa6a22);
  arc(241, 330, 125, 100, radians(-32), radians(213), OPEN);
  fill(#e24b00);
  ellipse(241, 308, 114, 26);

  //neck
  fill(#1c1c1c);
  rect(230, 275, 26, 37, 10);
}

void robotLegs() {
  //left leg
  fill(#1c1c1c);
  pushMatrix();
  translate(212, 420);
  rotate(radians(22));
  ellipse(0, 0, 35, 20);
  popMatrix();

  rect(205, 418, 15, 90);

  //left foot
  arc(230, 500, 40, 20, radians(-180), radians(0), OPEN);

  //right leg
  pushMatrix();
  translate(280, 410);
  rotate(radians(-22));
  ellipse(0, 0, 35, 20);
  popMatrix();

  rect(273, 418, 15, 90);

  //right foot
  arc(300, 500, 40, 20, radians(-180), radians(0), OPEN);
}

void robotArms() {
  float a = map(sin(theta), -1, 1, 230, 240);
  float b = map(sin(theta), -1, 1, 220, 230);
  float c = map(sin(theta), -1, 1, 225, 235);
  float d = map(sin(theta), -1, 1, 230, 240);
  theta += 0.03; //lower values slow down the movement

  //umbrella
  fill(#0076b3);
  rect(c, 160, 8, 200, 3);
  arc(c, 165, 160, 80, radians(-180), radians(0), OPEN);

  //left arm
  fill(#1c1c1c);
  ellipse(200, 333, 18, 23);

  fill(#1c1c1c);
  rect(195, 333, 10, 60, 5);

  stroke(0); 
  strokeWeight(10);
  line(200, 390, a, 330);
  noStroke(); 

  //left hand
  fill(0);
  rect(b, 320, 20, 25, 3);
}

Comments are closed.