Ticha-Bots and Bitrain
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);
}