Forlola started as a napkin sketch. I prototyped the code for the physics using Processing before beginning the final development in Xcode.
float gravity = 6.0;
int numsprings = 4;
ArrayList springs;
Spring2D feet, body, head, eye;
void setup()
{
size(640, 960);
smooth();
fill(0);
noStroke();
springs = new ArrayList();
feet = new Spring2D(width/2, 20, 2, gravity, 40, 0.2);
body = new Spring2D(width/2, 300, 10, gravity, 100, 0.8);
head = new Spring2D(width/2, 500, 6, gravity, 60, 0.5);
eye = new Spring2D(width/2, 600, 2, gravity, 20, 0.2);
springs.add(feet);
springs.add(body);
springs.add(head);
springs.add(eye);
}
void draw()
{
background(204);
Spring2D firstspring = (Spring2D) springs.get(0);
firstspring.update(width/2, 50, 50);
firstspring.display();
for (int i=1; i<springs.size(); i++) {
Spring2D spring = (Spring2D) springs.get(i);
Spring2D backspring = (Spring2D) springs.get(i-1);
spring.update(backspring.x, backspring.y, backspring.ty);
spring.display();
}
}
void mousePressed() {
for(int i=1; i<springs.size(); i++) {
Spring2D spring = (Spring2D) springs.get(i);
if(abs(spring.x-mouseX) < spring.radius && abs(spring.y-mouseY) < spring.radius) {
spring.drag = true;
} else {
spring.drag = false;
}
}
}
void mouseReleased() {
for(int i=1; i<springs.size(); i++) {
Spring2D spring = (Spring2D) springs.get(i);
spring.drag = false;
}
}
class Spring2D {
float vx, vy; // The x- and y-axis velocities
float x, y; // The x- and y-coordinates
float gravity;
float mass;
float radius;
float stiffness;
float damping = 0.9;
boolean drag = false;
float tx, ty;
Spring2D(float xpos, float ypos, float m, float g, float r, float k) {
tx = xpos;
ty = ypos;
x = xpos;
y = ypos;
mass = m;
gravity = g;
radius = r;
stiffness = k;
}
void update(float targetX, float targetY, float ty0) {
if(drag) {
x = mouseX;
y = mouseY;
return;
}
float forceX = (targetX - x) * stiffness;
float ax = forceX / mass;
vx = damping * (vx + ax);
x += vx;
float forceY = ((targetY - y)-(ty0 - ty)) * stiffness;
forceY += gravity;
float ay = forceY / mass;
vy = damping * (vy + ay);
y += vy;
}
void display() {
ellipse(x, y, radius*2, radius*2);
}
}
I scanned construction paper to give the final app a tactile appearance.