1 of 42

Chapter 7 - Motion

Supanit Angsirikul

2 of 42

Velocity Simulation

  • distance = velocity * time

3 of 42

Velocity Simulation

float d = 0.0; // Distance

float v = 0.5; // Velocity

float t = 0.0; // Time

void setup() {

size(1000, 100);

}

void draw() {

d = v * t;

t += 0.5;

background(0);

text("v = " + v, 10, 20);

ellipse(d, height/2, 30, 30);

if (d > width)

noLoop();

}

// Increase and decrease velocity and reset time

void keyPressed() {

if (key == 'a')

v += 0.5;

else if (key == 'z')

v -= 0.5;

t = 0;

}

4 of 42

Step

  • For a fixed frame rate drawing, the speed is depended on the step which is the displacement of objects between frame.
  • For drawing with a fixed frame rate, the speed depends on the movement of the object between frames.
  • We can increase speed by increasing step.

5 of 42

Step

float d = 0.0;

float step = 0.5;

void setup() {

size(1000, 100);

}

void draw() {

d += step;

background(0);

text("step = " + step, 10, 20);

ellipse(d, height/2, 30, 30);

if (d > width)

noLoop(); // d=0;

}

// Increase and decrease step and reset distance

void keyPressed() {

if (key == 'a')

step += 0.5;

else if (key == 'z')

step -= 0.5;

d = 0;

}

6 of 42

Direction

  • We can keep track of the moving direction of an object by keeping the values of dirX and dirY for directions in x and y axis.

  • The dirX and dirY variables may be integer with only values 1 and -1 only.

  • We can reverse the direction values by multiply with -1.

7 of 42

Direction

float x, y;

float stepX = 1.2, stepY = 1.5;

int dirX = 1, dirY = 1;

void setup() {

size(500, 300);

x = 0; y = height/2;

}

void draw() {

x += (stepX * dirX);

y += (stepY * dirY);

background(0);

text("stepX = " + stepX + ", stepY = " + stepY, 10, 20);

ellipse(x, y, 30, 30);

if (x < 0 || x > width)

dirX = -dirX;

if (y < 0 || y > height)

dirY = -dirY;

}

void keyPressed() {

if (key == 'a')

stepX += 0.3;

else if (key == 'z')

stepX -= 0.2;

else if (key == 's')

stepY += 0.3;

else if (key == 'x')

stepY -= 0.2;

}

8 of 42

Acceleration

  • Force = Mass x Acceleration
  • Acceleration = Force / Mass

Note : The motion of an object is caused by applied force.

9 of 42

Acceleration

float f = 0.15; // Force

float m = 5.0; // Mass

float a = 0.0; // Acceleration

float v = 0.0; // x-velocity

float d = 0; // distance

void setup() {

size(1000, 100);

}

void draw() {

a = f / m;

v += a; // New velocity = Original velocity + Acceleration d += v; // New position = Previous position + Velocity

background(0);

text("f = " + f + ", a = " + a + ", v = " + v, 10, 20);

ellipse(d, height/2, 30, 30);

if (d > width )

noLoop();

}

// Increase and decrease force and reset distance and velocity

void keyPressed() {

if (key == 'a')

f += 0.1;

else if (key == 'z’)

f -= 0.1;

d = 0;

v = 0;

}

10 of 42

Travel Speed

  • As an object takes off it must gradually accelerate its speed until reaching a travel speed then moves along with that speed.

  • When an object starts moving, it must gradually accelerate until it reaches its desired speed, then continue moving at that speed.

11 of 42

Travel Speed

float f = 0.15; // Force

float m = 5.0; // Mass

float a = 0.0; // Acceleration

float v = 0.0; // x-velocity

float d = 0; // distance

void setup() {

size(1000, 100);

}

void draw() {

a = f / m;

v += a;

d += v;

background(0);

text("a = " + a + ", v = " + v, 10, 20);

ellipse(d, height/2, 30, 30);

// start reduce force when move pass width/3

if (f > 0 && d > width/3 && a > 0.001)

f -= 0.01;

if (d > width ) {

// reset

a = 0; v = 0; d = 0; f = 0.15;

}

}

12 of 42

Acceleration without Force

float d = 0;

float stepX = 0.0;

float a = 0.05; // acceleration

void setup() {

size(1000, 100);

}

void draw() {

stepX += a;

d += stepX;

background(0);

text( "a = " + a + ", stepX = " + stepX, 10, 20);

ellipse(d, height/2, 30, 30);

// start reduce acceleration when move pass width/3

if (a > 0.001 && d > width/3)

a -= 0.001;

if (d > width ) {

// reset

a = 0.05; d = 0; stepX = 0.0;

}

}

13 of 42

Friction

  • Friction is the force against moving.
  • We define friction as a constant to reduce acceleration.

14 of 42

Friction

float x = 0.0;

float stepX = 1.3;

float a = 0.05; // acceleration

float fr = 0.02; // friction

void setup() {

size(1000, 100);

smooth();

}

void draw() {

stepX += (a - fr);

x += stepX;

background(0);

text("a = " + a + " fr = " + fr, 10, 20);

ellipse(x, 70, 40, 40);

// start reduce acceleration when move pass width/3

if (a > 0.001 && x > width/3)

a -= 0.001;

if (x > width) {

// reset

a = 0.05; x = 0; stepX = 0.0; fr = 0.02;

}

}

// Increase and decrease friction

void keyPressed() {

if (key == 'a')

fr += 0.001;

else if (key == 'z')

fr -= 0.001;

a = 0.05; x = 0; stepX = 0.0;

}

15 of 42

Easing (Reduce Movement)

  • As the object approaches the target, its speed should be slowed down to stop.
  • We define an easing as a factor to multiply the range between the current position and target to get the displacement step.
  • As the object approaches the target, the displacement step reduces to zero.

16 of 42

Easing (Reduce Movement)

float x = 0.0;

float easing = 0.05; // 0.0 -> 1.0

void setup() {

size(1000, 200);

smooth();

}

void draw() {

float target = mouseX;

x += (target - x) * easing; // มาจาก step = (target – x) * easing , แล้วจึงให้ x += step

background(0);

rect(mouseX-20, height-40, 40, 40);

ellipse(x, 70, 40, 40);

}

17 of 42

Easing

float x = 0.0;

float y = 0.0;

float easing = 0.05; // 0.0 -> 1.0

void setup() {

size(1000, 800);

smooth();

}

void draw() {

float targetX = mouseX;

x += (targetX - x) * easing; // มาจาก step = (target – x) * easing , แล้วจึงให้ x += step

float targetY = mouseY;

y += (targetY - y) * easing;

background(0);

rect(mouseX-20, mouseY, 40, 40);

ellipse(x, y, 40, 40);

}

18 of 42

no tail

void setup() {

size(1000, 100);

noStroke();

}

float x = 0.0;

void draw() {

fill(255);

background(0);

ellipse(x, 50, 50, 50);

if (++x > width)

noLoop();

}

19 of 42

Tailing

  • Drawing objects with moving tail, intensify the feeling of moving speed.

20 of 42

Tailing

void setup() {

size(1000, 100);

noStroke();

}

float x = 0.0;

void draw() {

// tails

fill(0, 12); // try varying the alpha value

rect(0, 0, width, height);

// circle

fill(255);

// fill(0, 255, 0); // try varying color

ellipse(x, 50, 50, 50);

if (++x > width)

noLoop();

}

21 of 42

Rotating Square with Tails

float w = 100;

float angle = 0.0;

void setup() {

size(600, 600);

noStroke();

}

void draw() {

fill(0, 12);

rect(0, 0, width, height);

fill(255, 0, 0);

// fill(random(255), 0, 0);

// fill(random(255), random(255), random(255));

translate(width/2, height/2);

rotate(angle);

// w += random(-5, 5);

rect(-width/3, -height/3, w, w);

angle += 0.02;

}

22 of 42

Dancing Comets

float speed = 0.015;

float radius;

float angle = 0;

float sx = 1.0;

float sy = 0.5;

void setup() {

size(800, 600);

noStroke();

radius = width/3;

textSize(15);

}

void draw() {

fill(0, 4);

rect(0, 0, width, height);

angle += speed;

float x = width/2 + (cos(angle * sy) * radius);

float y = height/2 + (sin(angle * sx) * radius);

fill(x, y, 255, x);

ellipse(x, y, 3, 3); // smaller circle

x = x + cos(angle * sx) * radius/2;

y = y + sin(angle * sy) * radius/2;

fill(y, 255, x, y);

ellipse(x, y, 11, 11); // larger circle

}

void keyPressed() {

if (key == 'a')

speed += 0.01;

else if (key == 'z')

speed -= 0.01;

else if (key == 's')

radius += 3;

else if (key == 'x')

radius -= 3;

text("speed = " + speed, 20, 30);

text("radius = " + radius, 20, 50);

}

23 of 42

Growing

float r = 20.0; // size

float step = 1.0;

int d = 1; // direction

void setup() {

size(200, 200);

noStroke();

frameRate(50);

fill(255, 0, 0);

}

void draw() {

r += step * d;

background(255);

ellipse(width/2, height/2, r, r);

if ((r > width) || (r < height/10))

d = -d;

}

24 of 42

Brownian Motion

  • Named in honor of the botanist Robert Brown, is jittery, stochastic motion that was originally ascribed to the movements of minute particles within fluids or the air; it appears entirely random. This motion can be simulated in software by setting a new position for a particle each frame, without preference as to the direction of motion. Leaving a trail of the previous positions of an element is a good technique for tracing its path through space.

25 of 42

Brownian Motion

void setup() {

size(200, 200);

background(0);

stroke(255);

}

float x = width/2;

float y = height/2;

void draw() {

x += random(-2, 2);

y += random(-2, 2);

point(x, y);

if (x < 0 || x > width || y < 0 || y > height) {

x = width/2;

y = height/2;

background(0);

}

}

26 of 42

Periodic Motion

float angle = 0.0; // Current angle

float speed = 0.1; // Speed of motion

float radius = 40.0; // Range of motion

float x = 0.0;

void setup() {

size(500, 100);

smooth();

noStroke();

}

void draw() {

angle += speed;

float y = sin(angle) * radius;

// no tail

fill(255);

background(0);

/* // tail

fill(0, 12);

rect(0, 0, width, height);

fill(255);

*/

ellipse((++x % width), height/2 + y, 20, 20);

// Vertical Periodic

// ellipse(width/2, height/2 + y, 20, 20);

}

27 of 42

Vibration with Amplitude

float speed = 0.1;

float angle = 0.0;

float amp1 = 15;

float amp2 = 3;

float amp3 = 5;

void setup() {

size(100, 100);

noStroke();

}

void draw() {

angle += speed;

background(0);

ellipse(25, 50+(sin(angle + PI)*amp1), 30, 30);

ellipse(55, 50+(sin(angle + HALF_PI)*amp2), 30, 30);

ellipse(85, 50+(sin(angle + TWO_PI)*amp3), 30, 30);

}

28 of 42

Swaying

void setup() {

size(200, 100);

stroke(255);

smooth();

}

float inc = 0.0;

void draw() {

inc += 0.01;

float angle = sin(inc)/10.0 + sin(inc*1.2)/20.0;

background(0);

tail(35, 9, angle/1.4);

tail(50, 8, angle/0.7);

tail(70, 12, angle);

tail(95, 10, angle/1.2);

tail(120, 5, angle*1.3);

tail(155, 7, angle*2);

}

void tail(int x, int units, float angle) {

pushMatrix();

translate(x, 100);

for (int i = units; i > 0; i--) {

strokeWeight(i);

line(0, 0, 0, -8);

translate(0, -8);

rotate(angle);

}

popMatrix();

}

29 of 42

shaking

float y;

float n = 0.0; // noise

float v = 0.4; // vary

float a = 25.0; // amplitude

void setup() {

size(300, 200);

stroke(255);

strokeWeight(20);

}

void draw() {

y = (noise(n) - 0.5) * a;

n += v;

background(0);

text("v = " + v + ", a = " + a, 10, 20);

line(0, height/2, width/2 - 10, height/2 + y);

}

void keyPressed() {

if (key == 'a')

v += 0.01;

else if (key == 'z')

v -= 0.01;

else if (key == 's')

a += 3;

else if (key == 'x')

a -= 3;

}

30 of 42

Elastic Motion 1

class Spring {

float M = 0.8; // Mass

float K = 0.2; // Spring constant

float D = 0.92; // Damping

float Rx = 100; // Rest position

float Ry = 100; // Rest position

float xpos; // Position x

float ypos; // Position y

float vx = 0.0; // Velocity x

float vy = 0.0; // Velocity y

float a = 0; // Acceleration

float f = 0; // Force

boolean released = false;

void move() {

f = -K * (xpos - Rx); // f=-Kx

a = f / M; // Set the acceleration, f=ma == a=f/m

vx = D * (vx + a); // Set the velocity in X axis

xpos += vx; // Updated x position

f = -K * (ypos - Ry); // f=-Ky

a = f / M; // Set the acceleration, f=ma == a=f/m

vy = D * (vy + a); // Set the velocity in Y axis

ypos += vy; // Updated y position

if (abs(vx) < 0.01 && abs(vy) < 0.01) {

vx = 0.0;

vy = 0.0;

released = false;

}

}

}

Damping is the gradual reduction of amplitude.

31 of 42

Elastic Motion 1 (cont.)

Spring s = new Spring();

void setup() {

size(300, 300);

fill(0);

s.Rx = s.xpos = width/2;

s.Ry = s.ypos = height/2;

}

void draw() {

background(200, 10);

if (s.released)

s.move();

ellipse(s.xpos, s.ypos, 30, 30);

}

void mousePressed() {

if (dist(mouseX, mouseY, s.xpos, s.ypos) < 10 && s.released == false) {

s.xpos = random(width);

s.ypos = random(height);

}

}

void mouseReleased() {

s.released = true;

}

32 of 42

Elastic Motion 2

class Spring {

float M = 0.8; // Mass

float K = 0.2; // Spring constant

float D = 0.92; // Damping

float Rx = 100; // Rest position

float Ry = 100; // Rest position

float xpos; // Position x

float ypos; // Position y

float vx = 0.0; // Velocity x

float vy = 0.0; // Velocity y

float a = 0; // Acceleration

float f = 0; // Force

boolean released = false;

void move() {

f = -K * (xpos - Rx); // f=-kx

a = f / M; // Set the acceleration, f=ma == a=f/m

vx = D * (vx + a); // Set the velocity

xpos += vx; // Updated x position

f = -K * (ypos - Ry); // f=-ky

a = f / M; // Set the acceleration, f=ma == a=f/m

vy = D * (vy + a); // Set the velocity

ypos += vy; // Updated y position

if (abs(vx)<0.01 && abs(vy) < 0.01) {

vx = 0.0;

vy = 0.0;

released = false;

}

}

}

33 of 42

Elastic Motion 2

int n = 9;

Spring [] s = new Spring[n];

void setup() {

size(300, 300);

for (int i = 0; i < n; i++) {

s[i] = new Spring();

s[i].xpos = random(width);

s[i].ypos = random(height);

s[i].Rx = s[i].xpos;

s[i].Ry = s[i].ypos;

}

}

void draw() {

background(200, 10);

for (int i=0; i< n; i++) {

if (s[i].released)

s[i].move();

ellipse(s[i].xpos, s[i].ypos, 10, 10);

}

for (int i = 0; i < n-1; i++)

line(s[i].xpos, s[i].ypos, s[i+1].xpos, s[i+1].ypos);

}

void mousePressed() {

for (int i = 0; i < n; i++)

if (dist(mouseX, mouseY, s[i].xpos, s[i].ypos) < 10 &&

s[i].released == false) {

s[i].xpos = random(width);

s[i].ypos = random(height);

}

}

void mouseReleased() {

for (int i = 0; i < n; i++)

s[i].released = true;

}

34 of 42

Elastic Motion 3

class Spring {

float M = 0.8; // Mass

float K = 0.2; // Spring constant

float D = 0.92; // Damping

float Rx = 100; // Rest position

float Ry = 100; // Rest position

float xpos; // Position x

float ypos; // Position y

float vx = 0.0; // Velocity x

float vy = 0.0; // Velocity y

float a = 0; // Acceleration

float f = 0; // Force

boolean released = false;

void move() {

f = -K * (ypos - Ry); // f=-ky

a = f / M; // Set the acceleration, f=ma == a=f/m

vy = D * (vy + a); // Set the velocity

ypos += vy; // Updated y position

if (abs(vx)<0.01 && abs(vy) < 0.01) {

vx = 0.0;

vy = 0.0;

released = false;

}

}

}

35 of 42

Elastic Motion 3

int n = 7;

int selected;

Spring [] s = new Spring[n];

void setup() {

size(300, 300);

for (int i = 0; i < n; i++) {

s[i] = new Spring();

s[i].xpos += 30*(i+1);

s[i].ypos = 50;

}

}

void draw() {

background(200, 10);

for (int i=0; i< n; i++) {

if (s[i].released)

s[i].move();

ellipse(s[i].xpos, s[i].ypos, 10, 10);

}

for (int i = 0; i < n; i++)

line(s[i].xpos, s[i].ypos, s[i].xpos, height-50);

}

void mouseMoved() {

for (int i = 0; i < n; i++)

if (dist(mouseX, mouseY, s[i].xpos, s[i].ypos) < 10 && s[i].released == false) {

//s[i].xpos = random(width);

s[i].ypos = random(height);

println("i = " + i);

selected = i;

s[selected].released = true;

}

}

36 of 42

2D Moving with Friction

class Circle {

int d ;

float x, y, sx, sy, f = 0.5;

Circle(int d) {

this.d = d;

x = random(width);

y = random(height);

sx = random(1);

sy = random(1);

}

void move() {

x += sx/f;

y += sy/f;

if (x < 0 || x > width) sx *= -1;

if (y < 0 || y > height) sy *= -1;

x = constrain(x, 0, width);

y = constrain(y, 0, height);

ellipse(int(x), int(y), d, d);

f += 0.01;

}

}

Circle c;

void setup() {

size(600, 400);

fill(0);

c = new Circle(30);

}

void draw() {

background(255);

c.move();

}

void mouseDragged() {

if (dist(mouseX, mouseY, c.x, c.y) < 20) {

c.f = 0.5;

c.sx = mouseX - pmouseX;

c.sy = mouseY - pmouseY;

}

}

37 of 42

Circle Array

// using the previous Circle class

int n = 10;

Circle c[] = new Circle[n];

void setup() {

size(600, 400);

noStroke();

fill(0) ;

for (int i = 0; i < n; i++)

c[i] = new Circle(5*(i+1));

}

void draw() {

background(255);

for (int i = 0; i < n; i++)

c[i].move();

}

void mouseDragged() {

for (int i = 0; i < n; i++)

if (dist(mouseX, mouseY, c[i].x, c[i].y) < 20) {

c[i].f = 0.5;

c[i].sx = mouseX - pmouseX;

c[i].sy = mouseY - pmouseY;

}

}

38 of 42

atan2(y , x)

  • Calculates the angle (in radians) from a specified point to the coordinate origin as measured from the positive x-axis. Values are returned as a float in the range from PI to -PI. The atan2() function is most often used for orienting geometry to the position of the cursor. Note: The y-coordinate of the point is the first parameter and the x-coordinate is the second due the structure of calculating the tangent.

39 of 42

Rotate rectangle

void draw() {

background(204);

translate(width/2, height/2);

float a = atan2(mouseY-height/2, mouseX-width/2);

rotate(a);

rect(-30, -5, 60, 10);

}

40 of 42

Collision

class Circle {

int id, d = 30;

float x, y, sx, sy, f = 0.5;

Circle ca[];

Circle(int id, Circle ca[]) {

this.id = id;

x = random(width);

y = random(height);

sx = random(1);

sy = random(1);

this.ca = ca;

}

void move() {

x += sx/f;

y += sy/f;

if (x < 0 || x > width) sx *= -1;

if (y < 0 || y > height) sy *= -1;

x = constrain(x, 0, width);

y = constrain(y, 0, height);

ellipse(int(x), int(y), d, d);

f += 0.01;

}

}

41 of 42

Collision (cont.)

void collide() {

for(int i = 0; i < ca.length; i++) {

if (i != id && dist(x, y, ca[i].x, ca[i].y) < d) {

float a = atan2(ca[i].y - y, ca[i].x - x);

float ax = x + cos(a)*d - ca[i].x;

float ay = y + sin(a)*d - ca[i].y;

sx -= ax;

sy -= ay;

ca[i].sx += ax;

ca[i].sy += ay;

}

}

}

}

int n = 10;

Circle c[] = new Circle[n];

void setup() {

size(600, 400);

fill(0);

for (int i = 0; i < n; i++)

c[i] = new Circle(i, c);

}

void draw() {

background(255);

for (int i = 0; i < n; i++) {

c[i].collide();

c[i].move();

}

}

void mouseDragged() {

for (int i = 0; i < n; i++)

if (dist(mouseX, mouseY, c[i].x, c[i].y) < 20) {

c[i].f = 0.5;

c[i].sx = mouseX - pmouseX;

c[i].sy = mouseY - pmouseY;

}

}

42 of 42