Initial Commit

This commit is contained in:
plane000
2018-04-20 10:15:15 +01:00
parent 49150ccfe4
commit 62101e8e61
2870 changed files with 520122 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
/**
* Chain.
*
* One mass is attached to the mouse position and the other
* is attached the position of the other mass. The gravity
* in the environment pulls down on both.
*/
Spring2D s1, s2;
float gravity = 9.0;
float mass = 2.0;
void setup() {
size(640, 360);
fill(255, 126);
// Inputs: x, y, mass, gravity
s1 = new Spring2D(0.0, width/2, mass, gravity);
s2 = new Spring2D(0.0, width/2, mass, gravity);
}
void draw() {
background(0);
s1.update(mouseX, mouseY);
s1.display(mouseX, mouseY);
s2.update(s1.x, s1.y);
s2.display(s1.x, s1.y);
}
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 = 30;
float stiffness = 0.2;
float damping = 0.7;
Spring2D(float xpos, float ypos, float m, float g) {
x = xpos;
y = ypos;
mass = m;
gravity = g;
}
void update(float targetX, float targetY) {
float forceX = (targetX - x) * stiffness;
float ax = forceX / mass;
vx = damping * (vx + ax);
x += vx;
float forceY = (targetY - y) * stiffness;
forceY += gravity;
float ay = forceY / mass;
vy = damping * (vy + ay);
y += vy;
}
void display(float nx, float ny) {
noStroke();
ellipse(x, y, radius*2, radius*2);
stroke(255);
line(x, y, nx, ny);
}
}

View File

@@ -0,0 +1,202 @@
// The Boid class
class Boid {
PVector position;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
Boid(float x, float y) {
acceleration = new PVector(0, 0);
// This is a new PVector method not yet implemented in JS
// velocity = PVector.random2D();
// Leaving the code temporarily this way so that this example runs in JS
float angle = random(TWO_PI);
velocity = new PVector(cos(angle), sin(angle));
position = new PVector(x, y);
r = 2.0;
maxspeed = 2;
maxforce = 0.03;
}
void run(ArrayList<Boid> boids) {
flock(boids);
update();
borders();
render();
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// We accumulate a new acceleration each time based on three rules
void flock(ArrayList<Boid> boids) {
PVector sep = separate(boids); // Separation
PVector ali = align(boids); // Alignment
PVector coh = cohesion(boids); // Cohesion
// Arbitrarily weight these forces
sep.mult(1.5);
ali.mult(1.0);
coh.mult(1.0);
// Add the force vectors to acceleration
applyForce(sep);
applyForce(ali);
applyForce(coh);
}
// Method to update position
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
position.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
PVector seek(PVector target) {
PVector desired = PVector.sub(target, position); // A vector pointing from the position to the target
// Scale to maximum speed
desired.normalize();
desired.mult(maxspeed);
// Above two lines of code below could be condensed with new PVector setMag() method
// Not using this method until Processing.js catches up
// desired.setMag(maxspeed);
// Steering = Desired minus Velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce); // Limit to maximum steering force
return steer;
}
void render() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
// heading2D() above is now heading() but leaving old syntax until Processing.js catches up
fill(200, 100);
stroke(255);
pushMatrix();
translate(position.x, position.y);
rotate(theta);
beginShape(TRIANGLES);
vertex(0, -r*2);
vertex(-r, r*2);
vertex(r, r*2);
endShape();
popMatrix();
}
// Wraparound
void borders() {
if (position.x < -r) position.x = width+r;
if (position.y < -r) position.y = height+r;
if (position.x > width+r) position.x = -r;
if (position.y > height+r) position.y = -r;
}
// Separation
// Method checks for nearby boids and steers away
PVector separate (ArrayList<Boid> boids) {
float desiredseparation = 25.0f;
PVector steer = new PVector(0, 0, 0);
int count = 0;
// For every boid in the system, check if it's too close
for (Boid other : boids) {
float d = PVector.dist(position, other.position);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
PVector diff = PVector.sub(position, other.position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
steer.div((float)count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// First two lines of code below could be condensed with new PVector setMag() method
// Not using this method until Processing.js catches up
// steer.setMag(maxspeed);
// Implement Reynolds: Steering = Desired - Velocity
steer.normalize();
steer.mult(maxspeed);
steer.sub(velocity);
steer.limit(maxforce);
}
return steer;
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
PVector align (ArrayList<Boid> boids) {
float neighbordist = 50;
PVector sum = new PVector(0, 0);
int count = 0;
for (Boid other : boids) {
float d = PVector.dist(position, other.position);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.velocity);
count++;
}
}
if (count > 0) {
sum.div((float)count);
// First two lines of code below could be condensed with new PVector setMag() method
// Not using this method until Processing.js catches up
// sum.setMag(maxspeed);
// Implement Reynolds: Steering = Desired - Velocity
sum.normalize();
sum.mult(maxspeed);
PVector steer = PVector.sub(sum, velocity);
steer.limit(maxforce);
return steer;
}
else {
return new PVector(0, 0);
}
}
// Cohesion
// For the average position (i.e. center) of all nearby boids, calculate steering vector towards that position
PVector cohesion (ArrayList<Boid> boids) {
float neighbordist = 50;
PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all positions
int count = 0;
for (Boid other : boids) {
float d = PVector.dist(position, other.position);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.position); // Add position
count++;
}
}
if (count > 0) {
sum.div(count);
return seek(sum); // Steer towards the position
}
else {
return new PVector(0, 0);
}
}
}

View File

@@ -0,0 +1,21 @@
// The Flock (a list of Boid objects)
class Flock {
ArrayList<Boid> boids; // An ArrayList for all the boids
Flock() {
boids = new ArrayList<Boid>(); // Initialize the ArrayList
}
void run() {
for (Boid b : boids) {
b.run(boids); // Passing the entire list of boids to each boid individually
}
}
void addBoid(Boid b) {
boids.add(b);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Flocking
* by Daniel Shiffman.
*
* An implementation of Craig Reynold's Boids program to simulate
* the flocking behavior of birds. Each boid steers itself based on
* rules of avoidance, alignment, and coherence.
*
* Click the mouse to add a new boid.
*/
Flock flock;
void setup() {
size(640, 360);
flock = new Flock();
// Add an initial set of boids into the system
for (int i = 0; i < 150; i++) {
flock.addBoid(new Boid(width/2,height/2));
}
}
void draw() {
background(50);
flock.run();
}
// Add a new boid into the System
void mousePressed() {
flock.addBoid(new Boid(mouseX,mouseY));
}

View File

@@ -0,0 +1,68 @@
/**
* Forces (Gravity and Fluid Resistence) with Vectors
* by Daniel Shiffman.
*
* Demonstration of multiple force acting on bodies (Mover class)
* Bodies experience gravity continuously
* Bodies experience fluid resistance when in "water"
*
* For the basics of working with PVector, see
* http://processing.org/learning/pvector/
* as well as examples in Topics/Vectors/
*
*/
// Five moving bodies
Mover[] movers = new Mover[10];
// Liquid
Liquid liquid;
void setup() {
size(640, 360);
reset();
// Create liquid object
liquid = new Liquid(0, height/2, width, height/2, 0.1);
}
void draw() {
background(0);
// Draw water
liquid.display();
for (Mover mover : movers) {
// Is the Mover in the liquid?
if (liquid.contains(mover)) {
// Calculate drag force
PVector drag = liquid.drag(mover);
// Apply drag force to Mover
mover.applyForce(drag);
}
// Gravity is scaled by mass here!
PVector gravity = new PVector(0, 0.1*mover.mass);
// Apply gravity
mover.applyForce(gravity);
// Update and display
mover.update();
mover.display();
mover.checkEdges();
}
fill(255);
text("click mouse to reset", 10, 30);
}
void mousePressed() {
reset();
}
// Restart all the Mover objects randomly
void reset() {
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.5, 3), 40+i*70, 0);
}
}

View File

@@ -0,0 +1,57 @@
/**
* Forces (Gravity and Fluid Resistence) with Vectors
* by Daniel Shiffman.
*
* Demonstration of multiple force acting on bodies (Mover class)
* Bodies experience gravity continuously
* Bodies experience fluid resistance when in "water"
*/
// Liquid class
class Liquid {
// Liquid is a rectangle
float x, y, w, h;
// Coefficient of drag
float c;
Liquid(float x_, float y_, float w_, float h_, float c_) {
x = x_;
y = y_;
w = w_;
h = h_;
c = c_;
}
// Is the Mover in the Liquid?
boolean contains(Mover m) {
PVector l = m.position;
if (l.x > x && l.x < x + w && l.y > y && l.y < y + h) {
return true;
} else {
return false;
}
}
// Calculate drag force
PVector drag(Mover m) {
// Magnitude is coefficient * speed squared
float speed = m.velocity.mag();
float dragMagnitude = c * speed * speed;
// Direction is inverse of velocity
PVector drag = m.velocity.copy();
drag.mult(-1);
// Scale according to magnitude
drag.setMag(dragMagnitude);
return drag;
}
void display() {
noStroke();
fill(127);
rect(x, y, w, h);
}
}

View File

@@ -0,0 +1,62 @@
/**
* Forces (Gravity and Fluid Resistence) with Vectors
* by Daniel Shiffman.
*
* Demonstration of multiple force acting on bodies (Mover class)
* Bodies experience gravity continuously
* Bodies experience fluid resistance when in "water"
*/
class Mover {
// position, velocity, and acceleration
PVector position;
PVector velocity;
PVector acceleration;
// Mass is tied to size
float mass;
Mover(float m, float x, float y) {
mass = m;
position = new PVector(x, y);
velocity = new PVector(0, 0);
acceleration = new PVector(0, 0);
}
// Newton's 2nd law: F = M * A
// or A = F / M
void applyForce(PVector force) {
// Divide by mass
PVector f = PVector.div(force, mass);
// Accumulate all forces in acceleration
acceleration.add(f);
}
void update() {
// Velocity changes according to acceleration
velocity.add(acceleration);
// position changes by velocity
position.add(velocity);
// We must clear acceleration each frame
acceleration.mult(0);
}
// Draw Mover
void display() {
stroke(255);
strokeWeight(2);
fill(255, 200);
ellipse(position.x, position.y, mass*16, mass*16);
}
// Bounce off bottom of window
void checkEdges() {
if (position.y > height) {
velocity.y *= -0.9; // A little dampening when hitting the bottom
position.y = height;
}
}
}

View File

@@ -0,0 +1,60 @@
/**
* Gravitational Attraction (3D)
* by Daniel Shiffman.
*
* Simulating gravitational attraction
* G ---> universal gravitational constant
* m1 --> mass of object #1
* m2 --> mass of object #2
* d ---> distance between objects
* F = (G*m1*m2)/(d*d)
*
* For the basics of working with PVector, see
* http://processing.org/learning/pvector/
* as well as examples in Topics/Vectors/
*
*/
// A bunch of planets
Planet[] planets = new Planet[10];
// One sun (note sun is not attracted to planets (violation of Newton's 3rd Law)
Sun s;
// An angle to rotate around the scene
float angle = 0;
void setup() {
size(640, 360, P3D);
// Some random planets
for (int i = 0; i < planets.length; i++) {
planets[i] = new Planet(random(0.1, 2), random(-width/2, width/2), random(-height/2, height/2), random(-100, 100));
}
// A single sun
s = new Sun();
}
void draw() {
background(0);
// Setup the scene
sphereDetail(8);
lights();
translate(width/2, height/2);
rotateY(angle);
// Display the Sun
s.display();
// All the Planets
for (Planet planet : planets) {
// Sun attracts Planets
PVector force = s.attract(planet);
planet.applyForce(force);
// Update and draw Planets
planet.update();
planet.display();
}
// Rotate around the scene
angle += 0.003;
}

View File

@@ -0,0 +1,43 @@
// Gravitational Attraction (3D)
// Daniel Shiffman <http://www.shiffman.net>
// A class for an orbiting Planet
class Planet {
// Basic physics model (position, velocity, acceleration, mass)
PVector position;
PVector velocity;
PVector acceleration;
float mass;
Planet(float m, float x, float y, float z) {
mass = m;
position = new PVector(x, y, z);
velocity = new PVector(1, 0); // Arbitrary starting velocity
acceleration = new PVector(0, 0);
}
// Newton's 2nd Law (F = M*A) applied
void applyForce(PVector force) {
PVector f = PVector.div(force, mass);
acceleration.add(f);
}
// Our motion algorithm (aka Euler Integration)
void update() {
velocity.add(acceleration); // Velocity changes according to acceleration
position.add(velocity); // position changes according to velocity
acceleration.mult(0);
}
// Draw the Planet
void display() {
noStroke();
fill(255);
pushMatrix();
translate(position.x, position.y, position.z);
sphere(mass*8);
popMatrix();
}
}

View File

@@ -0,0 +1,36 @@
// Gravitational Attraction (3D)
// Daniel Shiffman <http://www.shiffman.net>
// A class for an attractive body in our world
class Sun {
float mass; // Mass, tied to size
PVector position; // position
float G; // Universal gravitational constant (arbitrary value)
Sun() {
position = new PVector(0, 0);
mass = 20;
G = 0.4;
}
PVector attract(Planet m) {
PVector force = PVector.sub(position, m.position); // Calculate direction of force
float d = force.mag(); // Distance between objects
d = constrain(d, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude
force.setMag(strength); // Get force vector --> magnitude * direction
return force;
}
// Draw Sun
void display() {
stroke(255);
noFill();
pushMatrix();
translate(position.x, position.y, position.z);
sphere(mass*2);
popMatrix();
}
}

View File

@@ -0,0 +1,39 @@
// A subclass of Particle
class CrazyParticle extends Particle {
// Just adding one new variable to a CrazyParticle
// It inherits all other fields from "Particle", and we don't have to retype them!
float theta;
// The CrazyParticle constructor can call the parent class (super class) constructor
CrazyParticle(PVector l) {
// "super" means do everything from the constructor in Particle
super(l);
// One more line of code to deal with the new variable, theta
theta = 0.0;
}
// Notice we don't have the method run() here; it is inherited from Particle
// This update() method overrides the parent class update() method
void update() {
super.update();
// Increment rotation based on horizontal velocity
float theta_vel = (velocity.x * velocity.mag()) / 10.0f;
theta += theta_vel;
}
// This display() method overrides the parent class display() method
void display() {
// Render the ellipse just like in a regular particle
super.display();
// Then add a rotating line
pushMatrix();
translate(position.x, position.y);
rotate(theta);
stroke(255, lifespan);
line(0, 0, 25, 0);
popMatrix();
}
}

View File

@@ -0,0 +1,35 @@
/**
* Multiple Particle Systems
* by Daniel Shiffman.
*
* Click the mouse to generate a burst of particles
* at mouse position.
*
* Each burst is one instance of a particle system
* with Particles and CrazyParticles (a subclass of Particle)
* Note use of Inheritance and Polymorphism here.
*/
ArrayList<ParticleSystem> systems;
void setup() {
size(640, 360);
systems = new ArrayList<ParticleSystem>();
}
void draw() {
background(0);
for (ParticleSystem ps : systems) {
ps.run();
ps.addParticle();
}
if (systems.isEmpty()) {
fill(255);
textAlign(CENTER);
text("click mouse to add particle systems", width/2, height/2);
}
}
void mousePressed() {
systems.add(new ParticleSystem(1, new PVector(mouseX, mouseY)));
}

View File

@@ -0,0 +1,39 @@
// A simple Particle class
class Particle {
PVector position;
PVector velocity;
PVector acceleration;
float lifespan;
Particle(PVector l) {
acceleration = new PVector(0, 0.05);
velocity = new PVector(random(-1, 1), random(-2, 0));
position = l.copy();
lifespan = 255.0;
}
void run() {
update();
display();
}
// Method to update position
void update() {
velocity.add(acceleration);
position.add(velocity);
lifespan -= 2.0;
}
// Method to display
void display() {
stroke(255, lifespan);
fill(255, lifespan);
ellipse(position.x, position.y, 8, 8);
}
// Is the particle still useful?
boolean isDead() {
return (lifespan < 0.0);
}
}

View File

@@ -0,0 +1,48 @@
// An ArrayList is used to manage the list of Particles
class ParticleSystem {
ArrayList<Particle> particles; // An arraylist for all the particles
PVector origin; // An origin point for where particles are birthed
ParticleSystem(int num, PVector v) {
particles = new ArrayList<Particle>(); // Initialize the arraylist
origin = v.copy(); // Store the origin point
for (int i = 0; i < num; i++) {
particles.add(new Particle(origin)); // Add "num" amount of particles to the arraylist
}
}
void run() {
// Cycle through the ArrayList backwards, because we are deleting while iterating
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
particles.remove(i);
}
}
}
void addParticle() {
Particle p;
// Add either a Particle or CrazyParticle to the system
if (int(random(0, 2)) == 0) {
p = new Particle(origin);
}
else {
p = new CrazyParticle(origin);
}
particles.add(p);
}
void addParticle(Particle p) {
particles.add(p);
}
// A method to test if the particle system still has particles
boolean dead() {
return particles.isEmpty();
}
}

View File

@@ -0,0 +1,43 @@
// A simple Particle class
class Particle {
PVector position;
PVector velocity;
PVector acceleration;
float lifespan;
Particle(PVector l) {
acceleration = new PVector(0, 0.05);
velocity = new PVector(random(-1, 1), random(-2, 0));
position = l.copy();
lifespan = 255.0;
}
void run() {
update();
display();
}
// Method to update position
void update() {
velocity.add(acceleration);
position.add(velocity);
lifespan -= 1.0;
}
// Method to display
void display() {
stroke(255, lifespan);
fill(255, lifespan);
ellipse(position.x, position.y, 8, 8);
}
// Is the particle still useful?
boolean isDead() {
if (lifespan < 0.0) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,26 @@
// A class to describe a group of Particles
// An ArrayList is used to manage the list of Particles
class ParticleSystem {
ArrayList<Particle> particles;
PVector origin;
ParticleSystem(PVector position) {
origin = position.copy();
particles = new ArrayList<Particle>();
}
void addParticle() {
particles.add(new Particle(origin));
}
void run() {
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
particles.remove(i);
}
}
}
}

View File

@@ -0,0 +1,22 @@
/**
* Simple Particle System
* by Daniel Shiffman.
*
* Particles are generated each cycle through draw(),
* fall with gravity and fade out over time
* A ParticleSystem object manages a variable size (ArrayList)
* list of particles.
*/
ParticleSystem ps;
void setup() {
size(640, 360);
ps = new ParticleSystem(new PVector(width/2, 50));
}
void draw() {
background(0);
ps.addParticle();
ps.run();
}

View File

@@ -0,0 +1,59 @@
// A simple Particle class, renders the particle as an image
class Particle {
PVector loc;
PVector vel;
PVector acc;
float lifespan;
PImage img;
Particle(PVector l, PImage img_) {
acc = new PVector(0, 0);
float vx = randomGaussian()*0.3;
float vy = randomGaussian()*0.3 - 1.0;
vel = new PVector(vx, vy);
loc = l.copy();
lifespan = 100.0;
img = img_;
}
void run() {
update();
render();
}
// Method to apply a force vector to the Particle object
// Note we are ignoring "mass" here
void applyForce(PVector f) {
acc.add(f);
}
// Method to update position
void update() {
vel.add(acc);
loc.add(vel);
lifespan -= 2.5;
acc.mult(0); // clear Acceleration
}
// Method to display
void render() {
imageMode(CENTER);
tint(255, lifespan);
image(img, loc.x, loc.y);
// Drawing a circle instead
// fill(255,lifespan);
// noStroke();
// ellipse(loc.x,loc.y,img.width,img.height);
}
// Is the particle still useful?
boolean isDead() {
if (lifespan <= 0.0) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,40 @@
// A class to describe a group of Particles
// An ArrayList is used to manage the list of Particles
class ParticleSystem {
ArrayList<Particle> particles; // An arraylist for all the particles
PVector origin; // An origin point for where particles are birthed
PImage img;
ParticleSystem(int num, PVector v, PImage img_) {
particles = new ArrayList<Particle>(); // Initialize the arraylist
origin = v.copy(); // Store the origin point
img = img_;
for (int i = 0; i < num; i++) {
particles.add(new Particle(origin, img)); // Add "num" amount of particles to the arraylist
}
}
void run() {
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
particles.remove(i);
}
}
}
// Method to add a force vector to all particles currently in the system
void applyForce(PVector dir) {
// Enhanced loop!!!
for (Particle p : particles) {
p.applyForce(dir);
}
}
void addParticle() {
particles.add(new Particle(origin, img));
}
}

View File

@@ -0,0 +1,49 @@
/**
* Smoke Particle System
* by Daniel Shiffman.
*
* A basic smoke effect using a particle system. Each particle
* is rendered as an alpha masked image.
*/
ParticleSystem ps;
void setup() {
size(640, 360);
PImage img = loadImage("texture.png");
ps = new ParticleSystem(0, new PVector(width/2, height-60), img);
}
void draw() {
background(0);
// Calculate a "wind" force based on mouse horizontal position
float dx = map(mouseX, 0, width, -0.2, 0.2);
PVector wind = new PVector(dx, 0);
ps.applyForce(wind);
ps.run();
for (int i = 0; i < 2; i++) {
ps.addParticle();
}
// Draw an arrow representing the wind force
drawVector(wind, new PVector(width/2, 50, 0), 500);
}
// Renders a vector object 'v' as an arrow and a position 'loc'
void drawVector(PVector v, PVector loc, float scayl) {
pushMatrix();
float arrowsize = 4;
// Translate to position to render vector
translate(loc.x, loc.y);
stroke(255);
// Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
rotate(v.heading());
// Calculate length of vector & scale it to be bigger or smaller if necessary
float len = v.mag()*scayl;
// Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
line(0, 0, len, 0);
line(len, 0, len-arrowsize, +arrowsize/2);
line(len, 0, len-arrowsize, -arrowsize/2);
popMatrix();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,98 @@
/**
* Soft Body
* by Ira Greenberg.
*
* Softbody dynamics simulation using curveVertex() and curveTightness().
*/
// center point
float centerX = 0, centerY = 0;
float radius = 45, rotAngle = -90;
float accelX, accelY;
float springing = .0009, damping = .98;
//corner nodes
int nodes = 5;
float nodeStartX[] = new float[nodes];
float nodeStartY[] = new float[nodes];
float[]nodeX = new float[nodes];
float[]nodeY = new float[nodes];
float[]angle = new float[nodes];
float[]frequency = new float[nodes];
// soft-body dynamics
float organicConstant = 1;
void setup() {
size(640, 360);
//center shape in window
centerX = width/2;
centerY = height/2;
// iniitalize frequencies for corner nodes
for (int i=0; i<nodes; i++){
frequency[i] = random(5, 12);
}
noStroke();
frameRate(30);
}
void draw() {
//fade background
fill(0, 100);
rect(0,0,width, height);
drawShape();
moveShape();
}
void drawShape() {
// calculate node starting positions
for (int i=0; i<nodes; i++){
nodeStartX[i] = centerX+cos(radians(rotAngle))*radius;
nodeStartY[i] = centerY+sin(radians(rotAngle))*radius;
rotAngle += 360.0/nodes;
}
// draw polygon
curveTightness(organicConstant);
fill(255);
beginShape();
for (int i=0; i<nodes; i++){
curveVertex(nodeX[i], nodeY[i]);
}
for (int i=0; i<nodes-1; i++){
curveVertex(nodeX[i], nodeY[i]);
}
endShape(CLOSE);
}
void moveShape() {
//move center point
float deltaX = mouseX-centerX;
float deltaY = mouseY-centerY;
// create springing effect
deltaX *= springing;
deltaY *= springing;
accelX += deltaX;
accelY += deltaY;
// move predator's center
centerX += accelX;
centerY += accelY;
// slow down springing
accelX *= damping;
accelY *= damping;
// change curve tightness
organicConstant = 1-((abs(accelX)+abs(accelY))*.1);
//move nodes
for (int i=0; i<nodes; i++){
nodeX[i] = nodeStartX[i]+sin(radians(angle[i]))*(accelX*2);
nodeY[i] = nodeStartY[i]+sin(radians(angle[i]))*(accelY*2);
angle[i]+=frequency[i];
}
}

View File

@@ -0,0 +1,94 @@
/**
* Spring.
*
* Click, drag, and release the horizontal bar to start the spring.
*/
// Spring drawing constants for top bar
int springHeight = 32; // Height
int left; // Left position
int right; // Right position
int max = 200; // Maximum Y value
int min = 100; // Minimum Y value
boolean over = false; // If mouse over
boolean move = false; // If mouse down and over
// Spring simulation constants
float M = 0.8; // Mass
float K = 0.2; // Spring constant
float D = 0.92; // Damping
float R = 150; // Rest position
// Spring simulation variables
float ps = R; // Position
float vs = 0.0; // Velocity
float as = 0; // Acceleration
float f = 0; // Force
void setup() {
size(640, 360);
rectMode(CORNERS);
noStroke();
left = width/2 - 100;
right = width/2 + 100;
}
void draw() {
background(102);
updateSpring();
drawSpring();
}
void drawSpring() {
// Draw base
fill(0.2);
float baseWidth = 0.5 * ps + -8;
rect(width/2 - baseWidth, ps + springHeight, width/2 + baseWidth, height);
// Set color and draw top bar
if(over || move) {
fill(255);
} else {
fill(204);
}
rect(left, ps, right, ps + springHeight);
}
void updateSpring() {
// Update the spring position
if(!move) {
f = -K * (ps - R); // f=-ky
as = f / M; // Set the acceleration, f=ma == a=f/m
vs = D * (vs + as); // Set the velocity
ps = ps + vs; // Updated position
}
if(abs(vs) < 0.1) {
vs = 0.0;
}
// Test if mouse is over the top bar
if(mouseX > left && mouseX < right && mouseY > ps && mouseY < ps + springHeight) {
over = true;
} else {
over = false;
}
// Set and constrain the position of top bar
if(move) {
ps = mouseY - springHeight/2;
ps = constrain(ps, min, max);
}
}
void mousePressed() {
if(over) {
move = true;
}
}
void mouseReleased() {
move = false;
}

View File

@@ -0,0 +1,151 @@
/**
* Springs.
*
* Move the mouse over one of the circles and click to re-position.
* When you release the mouse, it will snap back into position.
* Each circle has a slightly different behavior.
*/
int num = 3;
Spring[] springs = new Spring[num];
void setup() {
size(640, 360);
noStroke();
springs[0] = new Spring(240, 260, 40, 0.98, 8.0, 0.1, springs, 0);
springs[1] = new Spring(320, 210, 120, 0.95, 9.0, 0.1, springs, 1);
springs[2] = new Spring(180, 170, 200, 0.90, 9.9, 0.1, springs, 2);
}
void draw() {
background(51);
for (Spring spring : springs) {
spring.update();
spring.display();
}
}
void mousePressed() {
for (Spring spring : springs) {
spring.pressed();
}
}
void mouseReleased() {
for (Spring spring : springs) {
spring.released();
}
}
class Spring {
// Screen values
float xpos, ypos;
float tempxpos, tempypos;
int size = 20;
boolean over = false;
boolean move = false;
// Spring simulation constants
float mass; // Mass
float k = 0.2; // Spring constant
float damp; // Damping
float rest_posx; // Rest position X
float rest_posy; // Rest position Y
// Spring simulation variables
//float pos = 20.0; // Position
float velx = 0.0; // X Velocity
float vely = 0.0; // Y Velocity
float accel = 0; // Acceleration
float force = 0; // Force
Spring[] friends;
int me;
// Constructor
Spring(float x, float y, int s, float d, float m,
float k_in, Spring[] others, int id) {
xpos = tempxpos = x;
ypos = tempypos = y;
rest_posx = x;
rest_posy = y;
size = s;
damp = d;
mass = m;
k = k_in;
friends = others;
me = id;
}
void update() {
if (move) {
rest_posy = mouseY;
rest_posx = mouseX;
}
force = -k * (tempypos - rest_posy); // f=-ky
accel = force / mass; // Set the acceleration, f=ma == a=f/m
vely = damp * (vely + accel); // Set the velocity
tempypos = tempypos + vely; // Updated position
force = -k * (tempxpos - rest_posx); // f=-ky
accel = force / mass; // Set the acceleration, f=ma == a=f/m
velx = damp * (velx + accel); // Set the velocity
tempxpos = tempxpos + velx; // Updated position
if ((overEvent() || move) && !otherOver() ) {
over = true;
} else {
over = false;
}
}
// Test to see if mouse is over this spring
boolean overEvent() {
float disX = tempxpos - mouseX;
float disY = tempypos - mouseY;
if (sqrt(sq(disX) + sq(disY)) < size/2 ) {
return true;
} else {
return false;
}
}
// Make sure no other springs are active
boolean otherOver() {
for (int i=0; i<num; i++) {
if (i != me) {
if (friends[i].over == true) {
return true;
}
}
}
return false;
}
void display() {
if (over) {
fill(153);
} else {
fill(255);
}
ellipse(tempxpos, tempypos, size, size);
}
void pressed() {
if (over) {
move = true;
} else {
move = false;
}
}
void released() {
move = false;
rest_posx = xpos;
rest_posy = ypos;
}
}