diff --git a/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Connection.pde b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Connection.pde new file mode 100644 index 000000000..0dcfe7a67 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Connection.pde @@ -0,0 +1,65 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +class Connection { + // Connection is from Neuron A to B + Neuron a; + Neuron b; + + // Connection has a weight + float weight; + + // Variables to track the animation + boolean sending = false; + PVector sender; + + // Need to store the output for when its time to pass along + float output = 0; + + Connection(Neuron from, Neuron to, float w) { + weight = w; + a = from; + b = to; + } + + + // The Connection is active + void feedforward(float val) { + output = val*weight; // Compute output + sender = a.location.get(); // Start animation at Neuron A + sending = true; // Turn on sending + } + + // Update traveling sender + void update() { + if (sending) { + // Use a simple interpolation + sender.x = lerp(sender.x, b.location.x, 0.1); + sender.y = lerp(sender.y, b.location.y, 0.1); + float d = PVector.dist(sender, b.location); + // If we've reached the end + if (d < 1) { + // Pass along the output! + b.feedforward(output); + sending = false; + } + } + } + + // Draw line and traveling circle + void display() { + stroke(0); + strokeWeight(1+weight*4); + line(a.location.x, a.location.y, b.location.x, b.location.y); + + if (sending) { + fill(0); + strokeWeight(1); + ellipse(sender.x, sender.y, 16, 16); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Exercise_10_5_LayeredNetworkAnimation.pde b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Exercise_10_5_LayeredNetworkAnimation.pde new file mode 100644 index 000000000..07903ceee --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Exercise_10_5_LayeredNetworkAnimation.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +Network network; + +void setup() { + size(750,200); + // Create the Network object + network = new Network(width/2, height/2); + + int layers = 3; + int inputs = 2; + + Neuron output = new Neuron(250, 0); + for (int i = 0; i < layers; i++) { + for (int j = 0; j < inputs; j++) { + float x = map(i, 0, layers, -300, 300); + float y = map(j, 0, inputs-1, -75, 75); + Neuron n = new Neuron(x, y); + if (i > 0) { + for (int k = 0; k < inputs; k++) { + Neuron prev = network.neurons.get(network.neurons.size()-inputs+k-j); + network.connect(prev, n, random(1)); + } + } + if (i == layers-1) { + network.connect(n, output, random(1)); + } + network.addNeuron(n); + } + } + network.addNeuron(output); +} + +void draw() { + background(255); + // Update and display the Network + network.update(); + network.display(); + + // Every 30 frames feed in an input + if (frameCount % 30 == 0) { + network.feedforward(random(1),random(1)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Network.pde b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Network.pde new file mode 100644 index 000000000..68a9f597f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Network.pde @@ -0,0 +1,68 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +class Network { + + // The Network has a list of neurons + ArrayList neurons; + + // The Network now keeps a duplicate list of all Connection objects. + // This makes it easier to draw everything in this class + ArrayList connections; + PVector location; + + Network(float x, float y) { + location = new PVector(x, y); + neurons = new ArrayList(); + connections = new ArrayList(); + } + + // We can add a Neuron + void addNeuron(Neuron n) { + neurons.add(n); + } + + // We can connection two Neurons + void connect(Neuron a, Neuron b, float weight) { + Connection c = new Connection(a, b, weight); + a.addConnection(c); + // Also add the Connection here + connections.add(c); + } + + // Sending an input to the first Neuron + // We should do something better to track multiple inputs + void feedforward(float input1, float input2) { + Neuron n1 = neurons.get(0); + n1.feedforward(input1); + + Neuron n2 = neurons.get(1); + n2.feedforward(input2); + + } + + // Update the animation + void update() { + for (Connection c : connections) { + c.update(); + } + } + + // Draw everything + void display() { + pushMatrix(); + translate(location.x, location.y); + for (Neuron n : neurons) { + n.display(); + } + + for (Connection c : connections) { + c.display(); + } + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Neuron.pde b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Neuron.pde new file mode 100644 index 000000000..819fe6750 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/Exercise_10_5_LayeredNetworkAnimation/Neuron.pde @@ -0,0 +1,64 @@ +// Daniel Shiffman +// The Nature of Code +// http://natureofcode.com + +// An animated drawing of a Neural Network + +class Neuron { + // Neuron has a location + PVector location; + + // Neuron has a list of connections + ArrayList connections; + + // We now track the inputs and sum them + float sum = 0; + + // The Neuron's size can be animated + float r = 32; + + Neuron(float x, float y) { + location = new PVector(x, y); + connections = new ArrayList(); + } + + // Add a Connection + void addConnection(Connection c) { + connections.add(c); + } + + // Receive an input + void feedforward(float input) { + // Accumulate it + sum += input; + // Activate it? + if (sum > 1) { + fire(); + sum = 0; // Reset the sum to 0 if it fires + } + } + + // The Neuron fires + void fire() { + r = 64; // It suddenly is bigger + + // We send the output through all connections + for (Connection c : connections) { + c.feedforward(sum); + } + } + + // Draw it as a circle + void display() { + stroke(0); + strokeWeight(1); + // Brightness is mapped to sum + float b = map(sum,0,1,255,0); + fill(b); + ellipse(location.x, location.y, r, r); + + // Size shrinks down back to original dimensions + r = lerp(r,32,0.1); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Connection.pde b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Connection.pde new file mode 100644 index 000000000..4d3c6d365 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Connection.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Connection { + float weight; + Neuron a; + Neuron b; + + Connection(Neuron from, Neuron to,float w) { + weight = w; + a = from; + b = to; + } + + void display() { + stroke(0); + strokeWeight(weight*4); + line(a.location.x, a.location.y, b.location.x, b.location.y); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/LayeredNetworkViz.pde b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/LayeredNetworkViz.pde new file mode 100644 index 000000000..e9a8f2de2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/LayeredNetworkViz.pde @@ -0,0 +1,16 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Network network; + +void setup() { + size(640, 360); + network = new Network(4,3,1); +} + +void draw() { + background(255); + network.display(); +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Network.pde b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Network.pde new file mode 100644 index 000000000..ec87c6e37 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Network.pde @@ -0,0 +1,47 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Network { + ArrayList neurons; + PVector location; + Network(int layers, int inputs, int outputs) { + location = new PVector(width/2, height/2); + + neurons = new ArrayList(); + + Neuron output = new Neuron(250, 0); + for (int i = 0; i < layers; i++) { + for (int j = 0; j < inputs; j++) { + float x = map(i, 0, layers, -200, 200); + float y = map(j, 0, inputs-1, -100, 100); + println(j + " " + y); + Neuron n = new Neuron(x, y); + + if (i > 0) { + for (int k = 0; k < inputs; k++) { + Neuron prev = neurons.get(neurons.size()-inputs+k-j); + prev.connect(n); + } + } + + if (i == layers-1) { + n.connect(output); + } + neurons.add(n); + } + } + neurons.add(output); + } + + + void display() { + pushMatrix(); + translate(location.x, location.y); + for (Neuron n : neurons) { + n.display(); + } + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Neuron.pde b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Neuron.pde new file mode 100644 index 000000000..e500dcb2b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/Neuron.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Neuron { + PVector location; + + ArrayList connections; + + Neuron(float x, float y) { + location = new PVector(x, y); + connections = new ArrayList(); + } + + void connect(Neuron n) { + Connection c = new Connection(this, n, random(1)); + connections.add(c); + } + + void display() { + stroke(0); + strokeWeight(1); + fill(0); + ellipse(location.x, location.y, 16, 16); + + for (Connection c : connections) { + c.display(); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/sketch.properties b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/LayeredNetworkViz/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/NOC_10_01_SimplePerceptron.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/NOC_10_01_SimplePerceptron.pde new file mode 100644 index 000000000..c702fcdb4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/NOC_10_01_SimplePerceptron.pde @@ -0,0 +1,90 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Perceptron Example +// See: http://en.wikipedia.org/wiki/Perceptron + +// Code based on text "Artificial Intelligence", George Luger + +// A list of points we will use to "train" the perceptron +Trainer[] training = new Trainer[2000]; +// A Perceptron object +Perceptron ptron; + +// We will train the perceptron with one "Point" object at a time +int count = 0; + +// Coordinate space +float xmin = -400; +float ymin = -100; +float xmax = 400; +float ymax = 100; + +// The function to describe a line +float f(float x) { + return 0.4*x+1; +} + +void setup() { + size(800, 200); + + // The perceptron has 3 inputs -- x, y, and bias + // Second value is "Learning Constant" + ptron = new Perceptron(3, 0.00001); // Learning Constant is low just b/c it's fun to watch, this is not necessarily optimal + + // Create a random set of training points and calculate the "known" answer + for (int i = 0; i < training.length; i++) { + float x = random(xmin, xmax); + float y = random(ymin, ymax); + int answer = 1; + if (y < f(x)) answer = -1; + training[i] = new Trainer(x, y, answer); + } + smooth(); +} + + +void draw() { + background(255); + translate(width/2,height/2); + + // Draw the line + strokeWeight(4); + stroke(127); + float x1 = xmin; + float y1 = f(x1); + float x2 = xmax; + float y2 = f(x2); + line(x1,y1,x2,y2); + + // Draw the line based on the current weights + // Formula is weights[0]*x + weights[1]*y + weights[2] = 0 + stroke(0); + strokeWeight(1); + float[] weights = ptron.getWeights(); + x1 = xmin; + y1 = (-weights[2] - weights[0]*x1)/weights[1]; + x2 = xmax; + y2 = (-weights[2] - weights[0]*x2)/weights[1]; + line(x1,y1,x2,y2); + + + + // Train the Perceptron with one "training" point at a time + ptron.train(training[count].inputs, training[count].answer); + count = (count + 1) % training.length; + + // Draw all the points based on what the Perceptron would "guess" + // Does not use the "known" correct answer + for (int i = 0; i < count; i++) { + stroke(0); + strokeWeight(1); + fill(0); + int guess = ptron.feedforward(training[i].inputs); + if (guess > 0) noFill(); + + ellipse(training[i].inputs[0], training[i].inputs[1], 8, 8); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/Perceptron.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/Perceptron.pde new file mode 100644 index 000000000..0eec0da5b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/Perceptron.pde @@ -0,0 +1,60 @@ +// Daniel Shiffman +// The Nature of Code +// http://natureofcode.com + +// Simple Perceptron Example +// See: http://en.wikipedia.org/wiki/Perceptron + +// Perceptron Class + +class Perceptron { + float[] weights; // Array of weights for inputs + float c; // learning constant + + // Perceptron is created with n weights and learning constant + Perceptron(int n, float c_) { + weights = new float[n]; + // Start with random weights + for (int i = 0; i < weights.length; i++) { + weights[i] = random(-1,1); + } + c = c_; + } + + // Function to train the Perceptron + // Weights are adjusted based on "desired" answer + void train(float[] inputs, int desired) { + // Guess the result + int guess = feedforward(inputs); + // Compute the factor for changing the weight based on the error + // Error = desired output - guessed output + // Note this can only be 0, -2, or 2 + // Multiply by learning constant + float error = desired - guess; + // Adjust weights based on weightChange * input + for (int i = 0; i < weights.length; i++) { + weights[i] += c * error * inputs[i]; + } + } + + // Guess -1 or 1 based on input values + int feedforward(float[] inputs) { + // Sum all values + float sum = 0; + for (int i = 0; i < weights.length; i++) { + sum += inputs[i]*weights[i]; + } + // Result is sign of the sum, -1 or 1 + return activate(sum); + } + + int activate(float sum) { + if (sum > 0) return 1; + else return -1; + } + + // Return weights + float[] getWeights() { + return weights; + } +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/Trainer.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/Trainer.pde new file mode 100644 index 000000000..69db5371c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_01_SimplePerceptron/Trainer.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Perceptron Example +// See: http://en.wikipedia.org/wiki/Perceptron + +// A class to describe a training point +// Has an x and y, a "bias" (1) and known output +// Could also add a variable for "guess" but not required here + +class Trainer { + + float[] inputs; + int answer; + + Trainer(float x, float y, int a) { + inputs = new float[3]; + inputs[0] = x; + inputs[1] = y; + inputs[2] = 1; + answer = a; + } +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/NOC_10_02_SeekingNeural.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/NOC_10_02_SeekingNeural.pde new file mode 100644 index 000000000..a99460a03 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/NOC_10_02_SeekingNeural.pde @@ -0,0 +1,62 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A Vehicle controlled by a Perceptron + +Vehicle v; + +PVector desired; + +ArrayList targets; + +void setup() { + size(800, 200); + // The Vehicle's desired location + desired = new PVector(width/2,height/2); + + + // Create a list of targets + makeTargets(); + + // Create the Vehicle (it has to know about the number of targets + // in order to configure its brain) + v = new Vehicle(targets.size(), random(width), random(height)); +} + +// Make a random ArrayList of targets to steer towards +void makeTargets() { + targets = new ArrayList(); + for (int i = 0; i < 8; i++) { + targets.add(new PVector(random(width), random(height))); + } +} + +void draw() { + background(255); + + // Draw a rectangle to show the Vehicle's goal + rectMode(CENTER); + stroke(0); + strokeWeight(2); + fill(0, 100); + rect(desired.x, desired.y, 36, 36); + + // Draw the targets + for (PVector target : targets) { + fill(0, 100); + stroke(0); + strokeWeight(2); + ellipse(target.x, target.y, 30, 30); + } + + // Update the Vehicle + v.steer(targets); + v.update(); + v.display(); +} + +void mousePressed() { + makeTargets(); +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Perceptron.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Perceptron.pde new file mode 100644 index 000000000..f52c726b3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Perceptron.pde @@ -0,0 +1,45 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Perceptron Example +// See: http://en.wikipedia.org/wiki/Perceptron + +// Perceptron Class + +class Perceptron { + float[] weights; // Array of weights for inputs + float c; // learning constant + + // Perceptron is created with n weights and learning constant + Perceptron(int n, float c_) { + weights = new float[n]; + c = c_; + // Start with random weights + for (int i = 0; i < weights.length; i++) { + weights[i] = random(0, 1); + } + } + + // Function to train the Perceptron + // Weights are adjusted based on vehicle's error + void train(PVector[] forces, PVector error) { + for (int i = 0; i < weights.length; i++) { + weights[i] += c*error.x*forces[i].x; + weights[i] += c*error.y*forces[i].y; + weights[i] = constrain(weights[i], 0, 1); + } + } + + // Give me a steering result + PVector feedforward(PVector[] forces) { + // Sum all values + PVector sum = new PVector(); + for (int i = 0; i < weights.length; i++) { + forces[i].mult(weights[i]); + sum.add(forces[i]); + } + return sum; + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde new file mode 100644 index 000000000..efd9bf287 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde @@ -0,0 +1,102 @@ +// Seek +// Daniel Shiffman + +// The "Vehicle" class + +class Vehicle { + + // Vehicle now has a brain! + Perceptron brain; + + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(int n, float x, float y) { + brain = new Perceptron(n,0.001); + acceleration = new PVector(0,0); + velocity = new PVector(0,0); + location = new PVector(x,y); + r = 3.0; + maxspeed = 4; + maxforce = 0.1; + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelerationelertion to 0 each cycle + acceleration.mult(0); + + location.x = constrain(location.x,0,width); + location.y = constrain(location.y,0,height); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // Here is where the brain processes everything + void steer(ArrayList targets) { + // Make an array of forces + PVector[] forces = new PVector[targets.size()]; + + // Steer towards all targets + for (int i = 0; i < forces.length; i++) { + forces[i] = seek(targets.get(i)); + } + + // That array of forces is the input to the brain + PVector result = brain.feedforward(forces); + + // Use the result to steer the vehicle + applyForce(result); + + // Train the brain according to the error + PVector error = PVector.sub(desired, location); + brain.train(forces,error); + + } + + // A method that calculates a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + PVector seek(PVector target) { + PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus velocity + PVector steer = PVector.sub(desired,velocity); + steer.limit(maxforce); // Limit to maximum steering force + + return steer; + } + + void display() { + + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + PI/2; + fill(175); + stroke(0); + strokeWeight(1); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(CLOSE); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Connection.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Connection.pde new file mode 100644 index 000000000..5e183e58f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Connection.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A static drawing of a Neural Network + +class Connection { + + // Connection is from Neuron A to B + Neuron a; + Neuron b; + + // Connection has a weight + float weight; + + Connection(Neuron from, Neuron to,float w) { + weight = w; + a = from; + b = to; + } + + // Drawn as a line + void display() { + stroke(0); + strokeWeight(weight*4); + line(a.location.x, a.location.y, b.location.x, b.location.y); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/NOC_10_03_NetworkViz.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/NOC_10_03_NetworkViz.pde new file mode 100644 index 000000000..bb932b9ae --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/NOC_10_03_NetworkViz.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A static drawing of a Neural Network + +Network network; + +void setup() { + size(800, 200); + // Create the Network object + network = new Network(width/2,height/2); + + // Create a bunch of Neurons + Neuron a = new Neuron(-300,0); + Neuron b = new Neuron(0,75); + Neuron c = new Neuron(0,-75); + Neuron d = new Neuron(300,0); + + // Connect them + network.connect(a,b); + network.connect(a,c); + network.connect(b,d); + network.connect(c,d); + + // Add them to the Network + network.addNeuron(a); + network.addNeuron(b); + network.addNeuron(c); + network.addNeuron(d); +} + +void draw() { + background(255); + // Draw the Network + network.display(); + noLoop(); +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Network.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Network.pde new file mode 100644 index 000000000..44b94a80f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Network.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A static drawing of a Neural Network + +class Network { + + // The Network has a list of neurons + ArrayList neurons; + PVector location; + + Network(float x, float y) { + location = new PVector(x,y); + neurons = new ArrayList(); + } + + // We can add a Neuron + void addNeuron(Neuron n) { + neurons.add(n); + } + + // We can connection two Neurons + void connect(Neuron a, Neuron b) { + Connection c = new Connection(a, b, random(1)); + a.addConnection(c); + } + + // We can draw the network + void display() { + pushMatrix(); + translate(location.x, location.y); + for (Neuron n : neurons) { + n.display(); + } + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Neuron.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Neuron.pde new file mode 100644 index 000000000..d14ed2a5e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/Neuron.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A static drawing of a Neural Network + +class Neuron { + + // Neuron has a location + PVector location; + + // Neuron has a list of connections + ArrayList connections; + + Neuron(float x, float y) { + location = new PVector(x, y); + connections = new ArrayList(); + } + + // Add a Connection + void addConnection(Connection c) { + connections.add(c); + } + + // Draw Neuron as a circle + void display() { + stroke(0); + strokeWeight(1); + fill(0); + ellipse(location.x, location.y, 16, 16); + + // Draw all its connections + for (Connection c : connections) { + c.display(); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/sketch.properties b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_03_NetworkViz/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Connection.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Connection.pde new file mode 100644 index 000000000..0dcfe7a67 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Connection.pde @@ -0,0 +1,65 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +class Connection { + // Connection is from Neuron A to B + Neuron a; + Neuron b; + + // Connection has a weight + float weight; + + // Variables to track the animation + boolean sending = false; + PVector sender; + + // Need to store the output for when its time to pass along + float output = 0; + + Connection(Neuron from, Neuron to, float w) { + weight = w; + a = from; + b = to; + } + + + // The Connection is active + void feedforward(float val) { + output = val*weight; // Compute output + sender = a.location.get(); // Start animation at Neuron A + sending = true; // Turn on sending + } + + // Update traveling sender + void update() { + if (sending) { + // Use a simple interpolation + sender.x = lerp(sender.x, b.location.x, 0.1); + sender.y = lerp(sender.y, b.location.y, 0.1); + float d = PVector.dist(sender, b.location); + // If we've reached the end + if (d < 1) { + // Pass along the output! + b.feedforward(output); + sending = false; + } + } + } + + // Draw line and traveling circle + void display() { + stroke(0); + strokeWeight(1+weight*4); + line(a.location.x, a.location.y, b.location.x, b.location.y); + + if (sending) { + fill(0); + strokeWeight(1); + ellipse(sender.x, sender.y, 16, 16); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/NOC_10_04_NetworkAnimation.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/NOC_10_04_NetworkAnimation.pde new file mode 100644 index 000000000..b2fc4178c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/NOC_10_04_NetworkAnimation.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +Network network; + +void setup() { + size(800, 200); + // Create the Network object + network = new Network(width/2, height/2); + + // Create a bunch of Neurons + Neuron a = new Neuron(-350, 0); + Neuron b = new Neuron(-200, 0); + Neuron c = new Neuron(0, 75); + Neuron d = new Neuron(0, -75); + Neuron e = new Neuron(200, 0); + Neuron f = new Neuron(350, 0); + + // Connect them + network.connect(a, b,1); + network.connect(b, c,random(1)); + network.connect(b, d,random(1)); + network.connect(c, e,random(1)); + network.connect(d, e,random(1)); + network.connect(e, f,1); + + // Add them to the Network + network.addNeuron(a); + network.addNeuron(b); + network.addNeuron(c); + network.addNeuron(d); + network.addNeuron(e); + network.addNeuron(f); +} + +void draw() { + background(255); + // Update and display the Network + network.update(); + network.display(); + + // Every 30 frames feed in an input + if (frameCount % 30 == 0) { + network.feedforward(random(1)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Network.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Network.pde new file mode 100644 index 000000000..5506414c9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Network.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +class Network { + + // The Network has a list of neurons + ArrayList neurons; + + // The Network now keeps a duplicate list of all Connection objects. + // This makes it easier to draw everything in this class + ArrayList connections; + PVector location; + + Network(float x, float y) { + location = new PVector(x, y); + neurons = new ArrayList(); + connections = new ArrayList(); + } + + // We can add a Neuron + void addNeuron(Neuron n) { + neurons.add(n); + } + + // We can connection two Neurons + void connect(Neuron a, Neuron b, float weight) { + Connection c = new Connection(a, b, weight); + a.addConnection(c); + // Also add the Connection here + connections.add(c); + } + + // Sending an input to the first Neuron + // We should do something better to track multiple inputs + void feedforward(float input) { + Neuron start = neurons.get(0); + start.feedforward(input); + } + + // Update the animation + void update() { + for (Connection c : connections) { + c.update(); + } + } + + // Draw everything + void display() { + pushMatrix(); + translate(location.x, location.y); + for (Neuron n : neurons) { + n.display(); + } + + for (Connection c : connections) { + c.display(); + } + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Neuron.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Neuron.pde new file mode 100644 index 000000000..89bc6c822 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/Neuron.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An animated drawing of a Neural Network + +class Neuron { + // Neuron has a location + PVector location; + + // Neuron has a list of connections + ArrayList connections; + + // We now track the inputs and sum them + float sum = 0; + + // The Neuron's size can be animated + float r = 32; + + Neuron(float x, float y) { + location = new PVector(x, y); + connections = new ArrayList(); + } + + // Add a Connection + void addConnection(Connection c) { + connections.add(c); + } + + // Receive an input + void feedforward(float input) { + // Accumulate it + sum += input; + // Activate it? + if (sum > 1) { + fire(); + sum = 0; // Reset the sum to 0 if it fires + } + } + + // The Neuron fires + void fire() { + r = 64; // It suddenly is bigger + + // We send the output through all connections + for (Connection c : connections) { + c.feedforward(sum); + } + } + + // Draw it as a circle + void display() { + stroke(0); + strokeWeight(1); + // Brightness is mapped to sum + float b = map(sum,0,1,255,0); + fill(b); + ellipse(location.x, location.y, r, r); + + // Size shrinks down back to original dimensions + r = lerp(r,32,0.1); + } +} + diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/sketch.properties b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_04_NetworkAnimation/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/Landscape.pde b/java/examples/Books/Nature of Code/chp10_nn/xor/Landscape.pde new file mode 100755 index 000000000..07bc45c54 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/Landscape.pde @@ -0,0 +1,75 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// "Landscape" example + +class Landscape { + + int scl; // size of each cell + int w,h; // width and height of thingie + int rows, cols; // number of rows and columns + float zoff = 0.0; // perlin noise argument + float[][] z; // using an array to store all the height values + + Landscape(int scl_, int w_, int h_) { + scl = scl_; + w = w_; + h = h_; + cols = w/scl; + rows = h/scl; + z = new float[cols][rows]; + } + + + // Calculate height values (based off a neural netork) + void calculate(Network nn) { + float x = 0; + float dx = (float) 1.0 / cols; + for (int i = 0; i < cols; i++) + { + float y = 0; + float dy = (float) 1.0 / rows; + for (int j = 0; j < rows; j++) + { + float[] input = new float[2]; + input[0] = x; + input[1] = y; + float result = nn.feedForward(input); + z[i][j] = z[i][j]*0.95 + 0.05*(float)(result*280.0f-140.0); + y += dy; + } + x += dx; + } + + } + + // Render landscape as grid of quads + void render() { + // Every cell is an individual quad + // (could use quad_strip here, but produces funny results, investigate this) + for (int x = 0; x < z.length-1; x++) + { + for (int y = 0; y < z[x].length-1; y++) + { + // one quad at a time + // each quad's color is determined by the height value at each vertex + // (clean this part up) + noStroke(); + pushMatrix(); + beginShape(QUADS); + translate(x*scl-w/2,y*scl-h/2,0); + fill(z[x][y]+127,220); + vertex(0,0,z[x][y]); + fill(z[x+1][y]+127,220); + vertex(scl,0,z[x+1][y]); + fill(z[x+1][y+1]+127,220); + vertex(scl,scl,z[x+1][y+1]); + fill(z[x][y+1]+127,220); + vertex(0,scl,z[x][y+1]); + endShape(); + popMatrix(); + } + } + } +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Connection.java b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Connection.java new file mode 100644 index 000000000..d8415d2a6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Connection.java @@ -0,0 +1,47 @@ +// Daniel Shiffman +// The Nature of Code, Fall 2006 +// Neural Network + +// Class to describe a connection between two neurons + +package nn; + +public class Connection { + + private Neuron from; // Connection goes from. . . + private Neuron to; // To. . . + private float weight; // Weight of the connection. . . + + // Constructor builds a connection with a random weight + public Connection(Neuron a_, Neuron b_) { + from = a_; + to = b_; + weight = (float) Math.random()*2-1; + } + + // In case I want to set the weights manually, using this for testing + public Connection(Neuron a_, Neuron b_, float w) { + from = a_; + to = b_; + weight = w; + } + + public Neuron getFrom() { + return from; + } + + public Neuron getTo() { + return to; + } + + public float getWeight() { + return weight; + } + + // Changing the weight of the connection + public void adjustWeight(float deltaWeight) { + weight += deltaWeight; + } + + +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/HiddenNeuron.java b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/HiddenNeuron.java new file mode 100644 index 000000000..3c8d7945d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/HiddenNeuron.java @@ -0,0 +1,20 @@ +//Daniel Shiffman +//The Nature of Code, Fall 2006 +//Neural Network + +// Hidden Neuron Class +// So far not necessary to differentiate these + +package nn; + +public class HiddenNeuron extends Neuron { + + public HiddenNeuron() { + super(); + } + + public HiddenNeuron(int i) { + super(i); + } + +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/InputNeuron.java b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/InputNeuron.java new file mode 100644 index 000000000..a2191632f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/InputNeuron.java @@ -0,0 +1,23 @@ +//Daniel Shiffman +//The Nature of Code, Fall 2006 +//Neural Network + +// Input Neuron Class +// Has additional functionality to receive beginning input + +package nn; + +public class InputNeuron extends Neuron { + public InputNeuron() { + super(); + } + + public InputNeuron(int i) { + super(i); + } + + public void input(float d) { + output = d; + } + +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Network.java b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Network.java new file mode 100644 index 000000000..c0854712d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Network.java @@ -0,0 +1,143 @@ +// Daniel Shiffman +// The Nature of Code, Fall 2006 +// Neural Network + +// Class to describe the entire network +// Arrays for input neurons, hidden neurons, and output neuron + +// Need to update this so that it would work with an array out outputs +// Rather silly that I didn't do this initially + +// Also need to build in a "Layer" class so that there can easily +// be more than one hidden layer + +package nn; + +import java.util.ArrayList; + +public class Network { + + // Layers + InputNeuron[] input; + HiddenNeuron[] hidden; + OutputNeuron output; + + public static final float LEARNING_CONSTANT = 0.5f; + + // Only One output now to start!!! (i can do better, really. . .) + // Constructor makes the entire network based on number of inputs & number of neurons in hidden layer + // Only One hidden layer!!! (fix this dood) + + public Network(int inputs, int hiddentotal) { + + input = new InputNeuron[inputs+1]; // Got to add a bias input + hidden = new HiddenNeuron[hiddentotal+1]; + + // Make input neurons + for (int i = 0; i < input.length-1; i++) { + input[i] = new InputNeuron(); + } + + // Make hidden neurons + for (int i = 0; i < hidden.length-1; i++) { + hidden[i] = new HiddenNeuron(); + } + + // Make bias neurons + input[input.length-1] = new InputNeuron(1); + hidden[hidden.length-1] = new HiddenNeuron(1); + + // Make output neuron + output = new OutputNeuron(); + + // Connect input layer to hidden layer + for (int i = 0; i < input.length; i++) { + for (int j = 0; j < hidden.length-1; j++) { + // Create the connection object and put it in both neurons + Connection c = new Connection(input[i],hidden[j]); + input[i].addConnection(c); + hidden[j].addConnection(c); + } + } + + // Connect the hidden layer to the output neuron + for (int i = 0; i < hidden.length; i++) { + Connection c = new Connection(hidden[i],output); + hidden[i].addConnection(c); + output.addConnection(c); + } + + } + + + public float feedForward(float[] inputVals) { + + // Feed the input with an array of inputs + for (int i = 0; i < inputVals.length; i++) { + input[i].input(inputVals[i]); + } + + // Have the hidden layer calculate its output + for (int i = 0; i < hidden.length-1; i++) { + hidden[i].calcOutput(); + } + + // Calculate the output of the output neuron + output.calcOutput(); + + // Return output + return output.getOutput(); + } + + public float train(float[] inputs, float answer) { + float result = feedForward(inputs); + + + // This is where the error correction all starts + // Derivative of sigmoid output function * diff between known and guess + float deltaOutput = result*(1-result) * (answer-result); + + + // BACKPROPOGATION + // This is easier b/c we just have one output + // Apply Delta to connections between hidden and output + ArrayList connections = output.getConnections(); + for (int i = 0; i < connections.size(); i++) { + Connection c = (Connection) connections.get(i); + Neuron neuron = c.getFrom(); + float output = neuron.getOutput(); + float deltaWeight = output*deltaOutput; + c.adjustWeight(LEARNING_CONSTANT*deltaWeight); + } + + // ADJUST HIDDEN WEIGHTS + for (int i = 0; i < hidden.length; i++) { + connections = hidden[i].getConnections(); + float sum = 0; + // Sum output delta * hidden layer connections (just one output) + for (int j = 0; j < connections.size(); j++) { + Connection c = (Connection) connections.get(j); + // Is this a connection from hidden layer to next layer (output)? + if (c.getFrom() == hidden[i]) { + sum += c.getWeight()*deltaOutput; + } + } + // Then adjust the weights coming in based: + // Above sum * derivative of sigmoid output function for hidden neurons + for (int j = 0; j < connections.size(); j++) { + Connection c = (Connection) connections.get(j); + // Is this a connection from previous layer (input) to hidden layer? + if (c.getTo() == hidden[i]) { + float output = hidden[i].getOutput(); + float deltaHidden = output * (1 - output); // Derivative of sigmoid(x) + deltaHidden *= sum; // Would sum for all outputs if more than one output + Neuron neuron = c.getFrom(); + float deltaWeight = neuron.getOutput()*deltaHidden; + c.adjustWeight(LEARNING_CONSTANT*deltaWeight); + } + } + } + + return result; + } +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Neuron.java b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Neuron.java new file mode 100644 index 000000000..234780016 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/Neuron.java @@ -0,0 +1,81 @@ +//Daniel Shiffman +//The Nature of Code, Fall 2006 +//Neural Network + +//Generic Neuron Class +//Can be a bias neuron (true or false) + +package nn; + +import java.util.ArrayList; + +public class Neuron { + + protected float output; + protected ArrayList connections; + protected boolean bias = false; + + // A regular Neuron + public Neuron() { + output = 0; + // Using an arraylist to store list of connections to other neurons + connections = new ArrayList(); + bias = false; + } + + // Constructor for a bias neuron + public Neuron(int i) { + output = i; + connections = new ArrayList(); + bias = true; + } + + // Function to calculate output of this neuron + // Output is sum of all inputs*weight of connections + public void calcOutput() { + if (bias) { + // do nothing + } else { + float sum = 0; + float bias = 0; + //System.out.println("Looking through " + connections.size() + " connections"); + for (int i = 0; i < connections.size(); i++) { + Connection c = (Connection) connections.get(i); + Neuron from = c.getFrom(); + Neuron to = c.getTo(); + // Is this connection moving forward to us + // Ignore connections that we send our output to + if (to == this) { + // This isn't really necessary + // But I am treating the bias individually in case I need to at some point + if (from.bias) { + bias = from.getOutput()*c.getWeight(); + } else { + sum += from.getOutput()*c.getWeight(); + } + } + } + // Output is result of sigmoid function + output = f(bias+sum); + } + } + + void addConnection(Connection c) { + connections.add(c); + } + + float getOutput() { + return output; + } + + // Sigmoid function + public static float f(float x) { + return 1.0f / (1.0f + (float) Math.exp(-x)); + } + + public ArrayList getConnections() { + return connections; + } + + +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/OutputNeuron.java b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/OutputNeuron.java new file mode 100644 index 000000000..abe8daee4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/code/src/OutputNeuron.java @@ -0,0 +1,7 @@ +package nn; + +public class OutputNeuron extends Neuron { + public OutputNeuron() { + super(); + } +} diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/data/GillSans-16.vlw b/java/examples/Books/Nature of Code/chp10_nn/xor/data/GillSans-16.vlw new file mode 100755 index 000000000..380eee76c Binary files /dev/null and b/java/examples/Books/Nature of Code/chp10_nn/xor/data/GillSans-16.vlw differ diff --git a/java/examples/Books/Nature of Code/chp10_nn/xor/xor.pde b/java/examples/Books/Nature of Code/chp10_nn/xor/xor.pde new file mode 100755 index 000000000..f7f5aa7a5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp10_nn/xor/xor.pde @@ -0,0 +1,113 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// XOR Multi-Layered Neural Network Example +// Neural network code is all in the "code" folder + +import nn.*; + +ArrayList inputs; // List of training input values +Network nn; // Neural Network Object +int count; // Total training interations +Landscape land; // Solution space +float theta = 0.0; // Angle of rotation +PFont f; // Font + + +void setup() { + + size(400,400,P3D); + + // Create a landscape object + land = new Landscape(20,300,300); + + f = createFont("Courier",12,true); + + nn = new Network(2,4); + + // Create a list of 4 training inputs + inputs = new ArrayList(); + float[] input = new float[2]; + input[0] = 1; + input[1] = 0; + inputs.add((float []) input.clone()); + input[0] = 0; + input[1] = 1; + inputs.add((float []) input.clone()); + input[0] = 1; + input[1] = 1; + inputs.add((float []) input.clone()); + input[0] = 0; + input[1] = 0; + inputs.add((float []) input.clone()); +} + +void draw() { + + int trainingIterationsPerFrame = 5; + + for (int i = 0; i < trainingIterationsPerFrame; i++) { + // Pick a random training input + int pick = int(random(inputs.size())); + // Grab that input + float[] inp = (float[]) inputs.get(pick); + // Compute XOR + float known = 1; + if ((inp[0] == 1.0 && inp[1] == 1.0) || (inp[0] == 0 && inp[1] == 0)) known = 0; + // Train that sucker! + float result = nn.train(inp,known); + count++; + } + + // Ok, visualize the solution space + background(175); + pushMatrix(); + translate(width/2,height/2+20,-160); + rotateX(PI/3); + rotateZ(theta); + + // Put a little BOX on screen + pushMatrix(); + stroke(50); + noFill(); + translate(-10,-10,0); + box(280); + + // Draw the landscape + popMatrix(); + land.calculate(nn); + land.render(); + theta += 0.0025; + popMatrix(); + + // Display overal neural net stats + networkStatus(); + +} + + +void networkStatus() { + float mse = 0.0; + + textFont(f); + fill(0); + text("Your friendly neighborhood neural network solving XOR.",10,20); + text("Total iterations: " + count,10,40); + + for (int i = 0; i < inputs.size(); i++) { + float[] inp = (float[]) inputs.get(i); + float known = 1; + if ((inp[0] == 1.0 && inp[1] == 1.0) || (inp[0] == 0 && inp[1] == 0)) known = 0; + float result = nn.feedForward(inp); + //System.out.println("For: " + inp[0] + " " + inp[1] + ": " + result); + mse += (result - known)*(result - known); + } + + float rmse = sqrt(mse/4.0); + DecimalFormat df = new DecimalFormat("0.000"); + text("Root mean squared error: " + df.format(rmse), 10,60); + +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_10_motion101_acceleration/Mover.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_10_motion101_acceleration/Mover.pde new file mode 100644 index 000000000..44b00fefe --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_10_motion101_acceleration/Mover.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + // The Mover tracks location, velocity, and acceleration + PVector location; + PVector velocity; + PVector acceleration; + // The Mover's maximum speed + float topspeed; + + Mover() { + // Start in the center + location = new PVector(width/2,height/2); + velocity = new PVector(0,0); + topspeed = 5; + } + + void update() { + + // Compute a vector that points from location to mouse + PVector mouse = new PVector(mouseX,mouseY); + PVector acceleration = PVector.sub(mouse,location); + // Set magnitude of acceleration + //acceleration.setMag(0.2); + acceleration.normalize(); + acceleration.mult(0.2); + + // Velocity changes according to acceleration + velocity.add(acceleration); + // Limit the velocity by topspeed + velocity.limit(topspeed); + // Location changes by velocity + location.add(velocity); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x,location.y,48,48); + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_10_motion101_acceleration/NOC_1_10_motion101_acceleration.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_10_motion101_acceleration/NOC_1_10_motion101_acceleration.pde new file mode 100644 index 000000000..baf4b6522 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_10_motion101_acceleration/NOC_1_10_motion101_acceleration.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A Mover object +Mover mover; + +void setup() { + size(800,200); + mover = new Mover(); +} + +void draw() { + background(255); + + // Update the location + mover.update(); + // Display the Mover + mover.display(); +} + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_11_motion101_acceleration_array/Mover.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_11_motion101_acceleration_array/Mover.pde new file mode 100644 index 000000000..b0713e6ed --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_11_motion101_acceleration_array/Mover.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + // The Mover tracks location, velocity, and acceleration + PVector location; + PVector velocity; + PVector acceleration; + // The Mover's maximum speed + float topspeed; + + Mover() { + // Start in the center + location = new PVector(random(width),random(height)); + velocity = new PVector(0,0); + topspeed = 5; + } + + void update() { + + // Compute a vector that points from location to mouse + PVector mouse = new PVector(mouseX,mouseY); + PVector acceleration = PVector.sub(mouse,location); + // Set magnitude of acceleration + //acceleration.setMag(0.2); + acceleration.normalize(); + acceleration.mult(0.2); + + // Velocity changes according to acceleration + velocity.add(acceleration); + // Limit the velocity by topspeed + velocity.limit(topspeed); + // Location changes by velocity + location.add(velocity); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127,200); + ellipse(location.x,location.y,48,48); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_11_motion101_acceleration_array/NOC_1_11_motion101_acceleration_array.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_11_motion101_acceleration_array/NOC_1_11_motion101_acceleration_array.pde new file mode 100644 index 000000000..40e9b48d6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_11_motion101_acceleration_array/NOC_1_11_motion101_acceleration_array.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Demonstration of the basics of motion with vector. +// A "Mover" object stores location, velocity, and acceleration as vectors +// The motion is controlled by affecting the acceleration (in this case towards the mouse) + +Mover[] movers = new Mover[20]; + +void setup() { + size(800,200); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(); + } +} + +void draw() { + + background(255); + + for (int i = 0; i < movers.length; i++) { + movers[i].update(); + movers[i].display(); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_1_bouncingball_novectors/NOC_1_1_bouncingball_novectors.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_1_bouncingball_novectors/NOC_1_1_bouncingball_novectors.pde new file mode 100644 index 000000000..09b4224a8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_1_bouncingball_novectors/NOC_1_1_bouncingball_novectors.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example 1-1: Bouncing Ball, no vectors +float x = 100; +float y = 100; +float xspeed = 2.5; +float yspeed = 2; + +void setup() { + size(800, 200); + smooth(); +} + +void draw() { + background(255); + + + // Add the current speed to the location. + x = x + xspeed; + y = y + yspeed; + + if ((x > width) || (x < 0)) { + xspeed = xspeed * -1; + } + if ((y > height) || (y < 0)) { + yspeed = yspeed * -1; + } + + + // Display circle at x location + stroke(0); + strokeWeight(2); + fill(127); + ellipse(x, y, 48, 48); +} + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_2_bouncingball_vectors/NOC_1_2_bouncingball_vectors.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_2_bouncingball_vectors/NOC_1_2_bouncingball_vectors.pde new file mode 100644 index 000000000..232de4c48 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_2_bouncingball_vectors/NOC_1_2_bouncingball_vectors.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example 1-2: Bouncing Ball, with PVector! +PVector location; +PVector velocity; + +void setup() { + size(200,200); + background(255); + location = new PVector(100,100); + velocity = new PVector(2.5,5); +} + +void draw() { + noStroke(); + fill(255,10); + rect(0,0,width,height); + + // Add the current speed to the location. + location.add(velocity); + + if ((location.x > width) || (location.x < 0)) { + velocity.x = velocity.x * -1; + } + if ((location.y > height) || (location.y < 0)) { + velocity.y = velocity.y * -1; + } + + // Display circle at x location + stroke(0); + fill(175); + ellipse(location.x,location.y,16,16); +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_3_vector_subtraction/NOC_1_3_vector_subtraction.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_3_vector_subtraction/NOC_1_3_vector_subtraction.pde new file mode 100644 index 000000000..a9659a409 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_3_vector_subtraction/NOC_1_3_vector_subtraction.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example 1-3: Vector subtraction + +void setup() { + size(800,200); + smooth(); +} + +void draw() { + background(255); + + PVector mouse = new PVector(mouseX,mouseY); + PVector center = new PVector(width/2,height/2); + mouse.sub(center); + + translate(width/2,height/2); + strokeWeight(2); + stroke(0); + line(0,0,mouse.x,mouse.y); + +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_4_vector_multiplication/NOC_1_4_vector_multiplication.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_4_vector_multiplication/NOC_1_4_vector_multiplication.pde new file mode 100644 index 000000000..3f7f76b3f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_4_vector_multiplication/NOC_1_4_vector_multiplication.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example 1-4: Vector multiplication + +void setup() { + size(800,200); + smooth(); +} + +void draw() { + background(255); + + PVector mouse = new PVector(mouseX,mouseY); + PVector center = new PVector(width/2,height/2); + mouse.sub(center); + + // Multiplying a vector! The vector is now half its original size (multiplied by 0.5). + mouse.mult(0.5); + + translate(width/2,height/2); + strokeWeight(2); + stroke(0); + line(0,0,mouse.x,mouse.y); +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_5_vector_magnitude/NOC_1_5_vector_magnitude.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_5_vector_magnitude/NOC_1_5_vector_magnitude.pde new file mode 100644 index 000000000..53d0b99a1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_5_vector_magnitude/NOC_1_5_vector_magnitude.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example 1-5: Vector magnitude + +void setup() { + size(800,200); + smooth(); +} + +void draw() { + background(255); + + PVector mouse = new PVector(mouseX,mouseY); + PVector center = new PVector(width/2,height/2); + mouse.sub(center); + + float m = mouse.mag(); + fill(0); + noStroke(); + rect(0,0,m,10); + + translate(width/2,height/2); + stroke(0); + strokeWeight(2); + line(0,0,mouse.x,mouse.y); + +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_6_vector_normalize/NOC_1_6_vector_normalize.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_6_vector_normalize/NOC_1_6_vector_normalize.pde new file mode 100644 index 000000000..659d8a512 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_6_vector_normalize/NOC_1_6_vector_normalize.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Demonstration of normalizing a vector. +// Normalizing a vector sets its length to 1. + +void setup() { + size(800,200); + smooth(); +} + +void draw() { + background(255); + + // A vector that points to the mouse location + PVector mouse = new PVector(mouseX,mouseY); + // A vector that points to the center of the window + PVector center = new PVector(width/2,height/2); + // Subtract center from mouse which results in a vector that points from center to mouse + mouse.sub(center); + + // Normalize the vector + mouse.normalize(); + + // Multiply its length by 50 + mouse.mult(150); + + translate(width/2,height/2); + // Draw the resulting vector + stroke(0); + strokeWeight(2); + line(0,0,mouse.x,mouse.y); + +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_7_motion101/Mover.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_7_motion101/Mover.pde new file mode 100644 index 000000000..8d7abe902 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_7_motion101/Mover.pde @@ -0,0 +1,43 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + + Mover() { + location = new PVector(random(width), random(height)); + velocity = new PVector(random(-2, 2), random(-2, 2)); + } + + void update() { + location.add(velocity); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x, location.y, 48, 48); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } + else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + location.y = 0; + } + else if (location.y < 0) { + location.y = height; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_7_motion101/NOC_1_7_motion101.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_7_motion101/NOC_1_7_motion101.pde new file mode 100644 index 000000000..9f968a254 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_7_motion101/NOC_1_7_motion101.pde @@ -0,0 +1,19 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover mover; + +void setup() { + size(800,200); + mover = new Mover(); +} + +void draw() { + background(255); + + mover.update(); + mover.checkEdges(); + mover.display(); +} + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_8_motion101_acceleration/Mover.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_8_motion101_acceleration/Mover.pde new file mode 100644 index 000000000..fdf9f5093 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_8_motion101_acceleration/Mover.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float topspeed; + + Mover() { + location = new PVector(width/2, height/2); + velocity = new PVector(0, 0); + acceleration = new PVector(-0.001, 0.01); + topspeed = 10; + } + + void update() { + velocity.add(acceleration); + velocity.limit(topspeed); + location.add(velocity); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x, location.y, 48, 48); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } + else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + location.y = 0; + } + else if (location.y < 0) { + location.y = height; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_8_motion101_acceleration/NOC_1_8_motion101_acceleration.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_8_motion101_acceleration/NOC_1_8_motion101_acceleration.pde new file mode 100644 index 000000000..3d1668104 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_8_motion101_acceleration/NOC_1_8_motion101_acceleration.pde @@ -0,0 +1,20 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover mover; + +void setup() { + size(800,200); + mover = new Mover(); +} + +void draw() { + background(255); + + mover.update(); + mover.checkEdges(); + mover.display(); +} + + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_9_motion101_acceleration/Mover.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_9_motion101_acceleration/Mover.pde new file mode 100644 index 000000000..d5644bff2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_9_motion101_acceleration/Mover.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float topspeed; + + Mover() { + location = new PVector(width/2, height/2); + velocity = new PVector(0, 0); + topspeed = 6; + } + + void update() { + + acceleration = PVector.random2D(); + acceleration.mult(random(2)); + + velocity.add(acceleration); + velocity.limit(topspeed); + location.add(velocity); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x, location.y, 48, 48); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } + else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + location.y = 0; + } + else if (location.y < 0) { + location.y = height; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_9_motion101_acceleration/NOC_1_9_motion101_acceleration.pde b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_9_motion101_acceleration/NOC_1_9_motion101_acceleration.pde new file mode 100644 index 000000000..30e22723f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp1_vectors/NOC_1_9_motion101_acceleration/NOC_1_9_motion101_acceleration.pde @@ -0,0 +1,18 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover mover; + +void setup() { + size(800,200); + mover = new Mover(); +} + +void draw() { + background(255); + mover.update(); + mover.checkEdges(); + mover.display(); +} + diff --git a/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Attractor.pde b/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Attractor.pde new file mode 100644 index 000000000..bff0c1f5c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Attractor.pde @@ -0,0 +1,75 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + PVector location; // Location + boolean dragging = false; // Is the object being dragged? + boolean rollover = false; // Is the mouse over the ellipse? + PVector drag; // holds the offset for when object is clicked on + + Attractor() { + location = new PVector(width/2,height/2); + mass = 10; + drag = new PVector(0.0,0.0); + } + + PVector attract(Mover m) { + PVector force = PVector.sub(location,m.location); // 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 + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float strength = (g * mass * m.mass) / (d * d); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + // Method to display + void display() { + ellipseMode(CENTER); + stroke(0); + if (dragging) fill (50); + else if (rollover) fill(100); + else fill(0); + ellipse(location.x,location.y,mass*6,mass*6); + } + + // The methods below are for mouse interaction + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + drag.x = location.x-mx; + drag.y = location.y-my; + } + } + + void rollover(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + rollover = true; + } + else { + rollover = false; + } + } + + void stopDragging() { + dragging = false; + } + + + + void drag() { + if (dragging) { + location.x = mouseX + drag.x; + location.y = mouseY + drag.y; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Exercise_2_10_attractrepel.pde b/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Exercise_2_10_attractrepel.pde new file mode 100644 index 000000000..03eefdbc6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Exercise_2_10_attractrepel.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[20]; + +Attractor a; + +float g = 1; + +void setup() { + size(800,200); + a = new Attractor(); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(4,12),random(width),random(height)); + } +} + +void draw() { + background(255); + + a.display(); + + + for (int i = 0; i < movers.length; i++) { + for (int j = 0; j < movers.length; j++) { + if (i != j) { + PVector force = movers[j].repel(movers[i]); + movers[i].applyForce(force); + } + } + + PVector force = a.attract(movers[i]); + movers[i].applyForce(force); + movers[i].update(); + movers[i].display(); + } + + + +} + + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Mover.pde new file mode 100644 index 000000000..0725db4c9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/Exercise_2_10_attractrepel/Mover.pde @@ -0,0 +1,73 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x , float y) { + mass = m; + location = new PVector(x,y); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + fill(175,200); + ellipse(location.x,location.y,mass*2,mass*2); + } + + PVector repel(Mover m) { + PVector force = PVector.sub(location,m.location); // Calculate direction of force + float distance = force.mag(); // Distance between objects + distance = constrain(distance,1.0,10000.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction + + float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude + force.mult(-1*strength); // Get force vector --> magnitude * direction + return force; + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } + else if (location.x < 0) { + location.x = 0; + velocity.x *= -1; + } + + if (location.y > height) { + location.y = height; + velocity.y *= -1; + } + else if (location.y < 0) { + location.y = 0; + velocity.y *= -1; + } + + } + +} + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/Attractor.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/Attractor.pde new file mode 100644 index 000000000..a242a2ef2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/Attractor.pde @@ -0,0 +1,42 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Attraction + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + PVector location; // Location + float g; + + Attractor() { + location = new PVector(0,0); + mass = 20; + g = 0.4; + } + + + PVector attract(Mover m) { + PVector force = PVector.sub(location,m.location); // Calculate direction of force + float distance = force.mag(); // Distance between objects + distance = constrain(distance,5.0,25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + // Method to display + void display() { + stroke(255); + noFill(); + pushMatrix(); + translate(location.x,location.y,location.z); + sphere(mass*2); + popMatrix(); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/Mover.pde new file mode 100644 index 000000000..5a5b3dcdf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/Mover.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x, float y, float z) { + mass = m; + location = new PVector(x,y,z); + velocity = new PVector(1,0); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + noStroke(); + fill(255); + pushMatrix(); + translate(location.x,location.y,location.z); + sphere(mass*8); + popMatrix(); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } + else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/NOC_02forces_many_attraction_3D.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/NOC_02forces_many_attraction_3D.pde new file mode 100644 index 000000000..5faf4dca0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/NOC_02forces_many_attraction_3D.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +import processing.opengl.*; + +Mover[] movers = new Mover[10]; + +Attractor a; + +float angle = 0; + +void setup() { + size(800,200,OPENGL); + background(255); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(0.1,2),random(-width/2,width/2),random(-height/2,height/2),random(-100,100)); + } + a = new Attractor(); +} + +void draw() { + background(0); + sphereDetail(8); + lights(); + translate(width/2,height/2); + rotateY(angle); + + + a.display(); + + for (int i = 0; i < movers.length; i++) { + PVector force = a.attract(movers[i]); + movers[i].applyForce(force); + + movers[i].update(); + movers[i].display(); + } + + angle += 0.003; + +} + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/sketch.properties b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_attraction_3D/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/Mover.pde new file mode 100644 index 000000000..ed666c5f0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/Mover.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x, float y) { + mass = m; + location = new PVector(x, y); + velocity = new PVector(0, 0); + acceleration = new PVector(0, 0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force, mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + fill(175, 200); + ellipse(location.x, location.y, mass*16, mass*16); + } + + PVector attract(Mover m) { + PVector force = PVector.sub(location, m.location); // Calculate direction of force + float distance = force.mag(); // Distance between objects + distance = constrain(distance, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction + + float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + void boundaries() { + + float d = 50; + + PVector force = new PVector(0, 0); + + if (location.x < d) { + force.x = 1; + } + else if (location.x > width -d) { + force.x = -1; + } + + if (location.y < d) { + force.y = 1; + } + else if (location.y > height-d) { + force.y = -1; + } + + force.normalize(); + force.mult(0.1); + + applyForce(force); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/NOC_02forces_many_mutual_boundaries.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/NOC_02forces_many_mutual_boundaries.pde new file mode 100644 index 000000000..caf6d8b63 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/NOC_02forces_many_mutual_boundaries.pde @@ -0,0 +1,47 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[20]; + +float g = 0.4; + +void setup() { + size(800,200); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(1,2),random(width),random(height)); + } +} + +void draw() { + background(255); + + + for (int i = 0; i < movers.length; i++) { + for (int j = 0; j < movers.length; j++) { + if (i != j) { + PVector force = movers[j].attract(movers[i]); + movers[i].applyForce(force); + } + } + + movers[i].boundaries(); + + movers[i].update(); + movers[i].display(); + } + +} + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/sketch.properties b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/sketch.properties new file mode 100644 index 000000000..6d28cd598 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_02forces_many_mutual_boundaries/sketch.properties @@ -0,0 +1 @@ +mode=JavaScript diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/Mover.pde new file mode 100644 index 000000000..839b1afdc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/Mover.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover() { + location = new PVector(30,30); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + mass = 1; + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x,location.y,48,48); + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } else if (location.x < 0) { + velocity.x *= -1; + location.x = 0; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde new file mode 100644 index 000000000..0972f6e9a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover m; + +void setup() { + size(800,200); + m = new Mover(); +} + +void draw() { + background(255); + + PVector wind = new PVector(0.01,0); + PVector gravity = new PVector(0,0.1); + m.applyForce(wind); + m.applyForce(gravity); + + + m.update(); + m.display(); + m.checkEdges(); + +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_2_forces_many/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_2_forces_many/Mover.pde new file mode 100644 index 000000000..6b008918c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_2_forces_many/Mover.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x , float y) { + mass = m; + location = new PVector(x,y); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(0,127); + ellipse(location.x,location.y,mass*16,mass*16); + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } else if (location.x < 0) { + velocity.x *= -1; + location.x = 0; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_2_forces_many/NOC_2_2_forces_many.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_2_forces_many/NOC_2_2_forces_many.pde new file mode 100644 index 000000000..db74a7634 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_2_forces_many/NOC_2_2_forces_many.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[20]; + +void setup() { + size(800,200); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(0.1,4),0,0); + } +} + +void draw() { + background(255); + + for (int i = 0; i < movers.length; i++) { + + PVector wind = new PVector(0.01,0); + PVector gravity = new PVector(0,0.1); + + movers[i].applyForce(wind); + movers[i].applyForce(gravity); + + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } + +} + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_3_forces_many_realgravity/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_3_forces_many_realgravity/Mover.pde new file mode 100644 index 000000000..6b008918c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_3_forces_many_realgravity/Mover.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x , float y) { + mass = m; + location = new PVector(x,y); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(0,127); + ellipse(location.x,location.y,mass*16,mass*16); + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } else if (location.x < 0) { + velocity.x *= -1; + location.x = 0; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_3_forces_many_realgravity/NOC_2_3_forces_many_realgravity.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_3_forces_many_realgravity/NOC_2_3_forces_many_realgravity.pde new file mode 100644 index 000000000..c3ecd8488 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_3_forces_many_realgravity/NOC_2_3_forces_many_realgravity.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[20]; + +void setup() { + size(800, 200); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(1, 4), 0, 0); + } +} + +void draw() { + background(255); + + for (int i = 0; i < movers.length; i++) { + + PVector wind = new PVector(0.01, 0); + PVector gravity = new PVector(0, 0.1*movers[i].mass); + + movers[i].applyForce(wind); + movers[i].applyForce(gravity); + + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } +} + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_friction/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_friction/Mover.pde new file mode 100644 index 000000000..263724c51 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_friction/Mover.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x , float y) { + mass = m; + location = new PVector(x,y); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(0,127); + ellipse(location.x,location.y,mass*16,mass*16); + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } else if (location.x < 0) { + location.x = 0; + velocity.x *= -1; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_friction/NOC_2_4_forces_friction.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_friction/NOC_2_4_forces_friction.pde new file mode 100644 index 000000000..02c417066 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_friction/NOC_2_4_forces_friction.pde @@ -0,0 +1,45 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[5]; + +void setup() { + size(383, 200); + randomSeed(1); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(1, 4), random(width), 0); + } +} + +void draw() { + background(255); + + for (int i = 0; i < movers.length; i++) { + + PVector wind = new PVector(0.01, 0); + PVector gravity = new PVector(0, 0.1*movers[i].mass); + + float c = 0.05; + PVector friction = movers[i].velocity.get(); + friction.mult(-1); + friction.normalize(); + friction.mult(c); + + movers[i].applyForce(friction); + movers[i].applyForce(wind); + movers[i].applyForce(gravity); + + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } +} + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_nofriction/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_nofriction/Mover.pde new file mode 100644 index 000000000..263724c51 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_nofriction/Mover.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x , float y) { + mass = m; + location = new PVector(x,y); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(0,127); + ellipse(location.x,location.y,mass*16,mass*16); + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } else if (location.x < 0) { + location.x = 0; + velocity.x *= -1; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_nofriction/NOC_2_4_forces_nofriction.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_nofriction/NOC_2_4_forces_nofriction.pde new file mode 100644 index 000000000..029236deb --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_4_forces_nofriction/NOC_2_4_forces_nofriction.pde @@ -0,0 +1,45 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[5]; + +void setup() { + size(383, 200); + randomSeed(1); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(1, 4), random(width), 0); + } +} + +void draw() { + background(255); + + for (int i = 0; i < movers.length; i++) { + + PVector wind = new PVector(0.01, 0); + PVector gravity = new PVector(0, 0.1*movers[i].mass); + + float c = 0.05; + PVector friction = movers[i].velocity.get(); + friction.mult(-1); + friction.normalize(); + friction.mult(c); + + //movers[i].applyForce(friction); + movers[i].applyForce(wind); + movers[i].applyForce(gravity); + + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } +} + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/Liquid.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/Liquid.pde new file mode 100644 index 000000000..b0ea9b736 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/Liquid.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + + // 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.location; + 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 dragForce = m.velocity.get(); + dragForce.mult(-1); + + // Scale according to magnitude + // dragForce.setMag(dragMagnitude); + dragForce.normalize(); + dragForce.mult(dragMagnitude); + return dragForce; + } + + void display() { + noStroke(); + fill(50); + rect(x,y,w,h); + } + +} + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/Mover.pde new file mode 100644 index 000000000..791e90954 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/Mover.pde @@ -0,0 +1,58 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + // location, velocity, and acceleration + PVector location; + PVector velocity; + PVector acceleration; + + // Mass is tied to size + float mass; + + Mover(float m, float x, float y) { + mass = m; + location = 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); + // Location changes by velocity + location.add(velocity); + // We must clear acceleration each frame + acceleration.mult(0); + } + + // Draw Mover + void display() { + stroke(0); + strokeWeight(2); + fill(127, 200); + ellipse(location.x, location.y, mass*16, mass*16); + } + + // Bounce off bottom of window + void checkEdges() { + if (location.y > height) { + velocity.y *= -0.9; // A little dampening when hitting the bottom + location.y = height; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/NOC_2_5_fluidresistance.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/NOC_2_5_fluidresistance.pde new file mode 100644 index 000000000..ff9573d6d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance/NOC_2_5_fluidresistance.pde @@ -0,0 +1,72 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Forces (Gravity and Fluid Resistence) with Vectors + +// Demonstration of multiple force acting on bodies (Mover class) +// Bodies experience gravity continuously +// Bodies experience fluid resistance when in "water" + +// Five moving bodies +Mover[] movers = new Mover[11]; + +// Liquid +Liquid liquid; + +void setup() { + size(800, 200); + reset(); + // Create liquid object + liquid = new Liquid(0, height/2, width, height/2, 0.1); +} + +void draw() { + background(255); + + // Draw water + liquid.display(); + + for (int i = 0; i < movers.length; i++) { + + // Is the Mover in the liquid? + if (liquid.contains(movers[i])) { + // Calculate drag force + PVector dragForce = liquid.drag(movers[i]); + // Apply drag force to Mover + movers[i].applyForce(dragForce); + } + + // Gravity is scaled by mass here! + PVector gravity = new PVector(0, 0.1*movers[i].mass); + // Apply gravity + movers[i].applyForce(gravity); + + // Update and display + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } + + fill(0); + 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); + } +} + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/Liquid.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/Liquid.pde new file mode 100644 index 000000000..bce05cc7c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/Liquid.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + + // 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.location; + 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 dragForce = m.velocity.get(); + dragForce.mult(-1); + + // Scale according to magnitude + // dragForce.setMag(dragMagnitude); + dragForce.normalize(); + dragForce.mult(dragMagnitude); + return dragForce; + } + + void display() { + noStroke(); + fill(50); + rect(x,y,w,h); + } + +} + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/Mover.pde new file mode 100644 index 000000000..d45e3b664 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/Mover.pde @@ -0,0 +1,58 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + // location, velocity, and acceleration + PVector location; + PVector velocity; + PVector acceleration; + + // Mass is tied to size + float mass; + + Mover(float m, float x, float y) { + mass = m; + location = 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); + // Location changes by velocity + location.add(velocity); + // We must clear acceleration each frame + acceleration.mult(0); + } + + // Draw Mover + void display() { + stroke(0); + strokeWeight(2*2.25); + fill(127,200); + ellipse(location.x, location.y, mass*16, mass*16); + } + + // Bounce off bottom of window + void checkEdges() { + if (location.y > height) { + velocity.y *= -0.9; // A little dampening when hitting the bottom + location.y = height; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/NOC_2_5_fluidresistance_sequence.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/NOC_2_5_fluidresistance_sequence.pde new file mode 100644 index 000000000..99d47915b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_5_fluidresistance_sequence/NOC_2_5_fluidresistance_sequence.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Forces (Gravity and Fluid Resistence) with Vectors + +// Demonstration of multiple force acting on bodies (Mover class) +// Bodies experience gravity continuously +// Bodies experience fluid resistance when in "water" + +// Five moving bodies +Mover[] movers = new Mover[5]; + +// Liquid +Liquid liquid; + +void setup() { + size(450, 450); + randomSeed(1); + reset(); + // Create liquid object + liquid = new Liquid(0, height/2, width, height/2, 0.1); +} + +void draw() { + background(255); + + // Draw water + liquid.display(); + + for (int i = 0; i < movers.length; i++) { + + // Is the Mover in the liquid? + if (liquid.contains(movers[i])) { + // Calculate drag force + PVector dragForce = liquid.drag(movers[i]); + // Apply drag force to Mover + movers[i].applyForce(dragForce); + } + + // Gravity is scaled by mass here! + PVector gravity = new PVector(0, 0.1*movers[i].mass); + // Apply gravity + movers[i].applyForce(gravity); + + // Update and display + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } + + fill(255); + //text("click mouse to reset",10,30); + + if (frameCount % 20 == 0) saveFrame("ch2_05_####.png"); +} + +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*2.25,3*2.25), 20*2.25+i*40*2.25, 0); + } +} + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/Attractor.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/Attractor.pde new file mode 100644 index 000000000..556605cb7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/Attractor.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + float G; // Gravitational Constant + PVector location; // Location + boolean dragging = false; // Is the object being dragged? + boolean rollover = false; // Is the mouse over the ellipse? + PVector dragOffset; // holds the offset for when object is clicked on + + Attractor() { + location = new PVector(width/2,height/2); + mass = 20; + G = 1; + dragOffset = new PVector(0.0,0.0); + } + + PVector attract(Mover m) { + PVector force = PVector.sub(location,m.location); // 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 + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + // Method to display + void display() { + ellipseMode(CENTER); + strokeWeight(4); + stroke(0); + if (dragging) fill (50); + else if (rollover) fill(100); + else fill(175,200); + ellipse(location.x,location.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + dragOffset.x = location.x-mx; + dragOffset.y = location.y-my; + } + } + + void hover(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + rollover = true; + } + else { + rollover = false; + } + } + + void stopDragging() { + dragging = false; + } + + + + void drag() { + if (dragging) { + location.x = mouseX + dragOffset.x; + location.y = mouseY + dragOffset.y; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/Mover.pde new file mode 100644 index 000000000..7c35ead44 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/Mover.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover() { + location = new PVector(400,50); + velocity = new PVector(1,0); + acceleration = new PVector(0,0); + mass = 1; + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x,location.y,16,16); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde new file mode 100644 index 000000000..d747ee9b3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover m; +Attractor a; + +void setup() { + size(800,200); + m = new Mover(); + a = new Attractor(); +} + +void draw() { + background(255); + + PVector force = a.attract(m); + m.applyForce(force); + m.update(); + + a.drag(); + a.hover(mouseX,mouseY); + + a.display(); + m.display(); +} + +void mousePressed() { + a.clicked(mouseX,mouseY); +} + +void mouseReleased() { + a.stopDragging(); +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/Attractor.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/Attractor.pde new file mode 100644 index 000000000..556605cb7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/Attractor.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + float G; // Gravitational Constant + PVector location; // Location + boolean dragging = false; // Is the object being dragged? + boolean rollover = false; // Is the mouse over the ellipse? + PVector dragOffset; // holds the offset for when object is clicked on + + Attractor() { + location = new PVector(width/2,height/2); + mass = 20; + G = 1; + dragOffset = new PVector(0.0,0.0); + } + + PVector attract(Mover m) { + PVector force = PVector.sub(location,m.location); // 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 + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + // Method to display + void display() { + ellipseMode(CENTER); + strokeWeight(4); + stroke(0); + if (dragging) fill (50); + else if (rollover) fill(100); + else fill(175,200); + ellipse(location.x,location.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + dragOffset.x = location.x-mx; + dragOffset.y = location.y-my; + } + } + + void hover(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + rollover = true; + } + else { + rollover = false; + } + } + + void stopDragging() { + dragging = false; + } + + + + void drag() { + if (dragging) { + location.x = mouseX + dragOffset.x; + location.y = mouseY + dragOffset.y; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/Mover.pde new file mode 100644 index 000000000..575cda064 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/Mover.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x, float y) { + mass = m; + location = new PVector(random(width), random(height)); + velocity = new PVector(1, 0); + acceleration = new PVector(0, 0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force, mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(0,100); + ellipse(location.x, location.y, mass*25, mass*25); + } +} + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/NOC_2_7_attraction_many.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/NOC_2_7_attraction_many.pde new file mode 100644 index 000000000..e7f5b1c5b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_7_attraction_many/NOC_2_7_attraction_many.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[10]; + +Attractor a; + +void setup() { + size(800, 200); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(0.1, 2), random(width), random(height)); + } + a = new Attractor(); + } + +void draw() { + background(255); + + a.display(); + a.drag(); + a.hover(mouseX, mouseY); + + for (int i = 0; i < movers.length; i++) { + PVector force = a.attract(movers[i]); + movers[i].applyForce(force); + + movers[i].update(); + movers[i].display(); + } +} + +void mousePressed() { + a.clicked(mouseX, mouseY); +} + +void mouseReleased() { + a.stopDragging(); +} + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_8_mutual_attraction/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_8_mutual_attraction/Mover.pde new file mode 100644 index 000000000..63b9dbc67 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_8_mutual_attraction/Mover.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover(float m, float x, float y) { + mass = m; + location = new PVector(x, y); + velocity = new PVector(0, 0); + acceleration = new PVector(0, 0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force, mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(0, 100); + ellipse(location.x, location.y, mass*24, mass*24); + } + + PVector attract(Mover m) { + PVector force = PVector.sub(location, m.location); // Calculate direction of force + float distance = force.mag(); // Distance between objects + distance = constrain(distance, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction + + float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_8_mutual_attraction/NOC_2_8_mutual_attraction.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_8_mutual_attraction/NOC_2_8_mutual_attraction.pde new file mode 100644 index 000000000..3a6ef45a8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_8_mutual_attraction/NOC_2_8_mutual_attraction.pde @@ -0,0 +1,45 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[20]; + +float g = 0.4; + +void setup() { + size(800,200); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(0.1,2),random(width),random(height)); + } +} + +void draw() { + background(255); + + + for (int i = 0; i < movers.length; i++) { + for (int j = 0; j < movers.length; j++) { + if (i != j) { + PVector force = movers[j].attract(movers[i]); + movers[i].applyForce(force); + } + } + + movers[i].update(); + movers[i].display(); + } + +} + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/AdditiveWave/AdditiveWave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/AdditiveWave/AdditiveWave.pde new file mode 100644 index 000000000..2636374b8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/AdditiveWave/AdditiveWave.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Additive Wave +// Create a more complex wave by adding two waves together. + +// Maybe better for this answer to be OOP??? + +int xspacing = 8; // How far apart should each horizontal location be spaced +int w; // Width of entire wave +int maxwaves = 5; // total # of waves to add together + +float theta = 0.0; +float[] amplitude = new float[maxwaves]; // Height of wave +float[] dx = new float[maxwaves]; // Value for incrementing X, to be calculated as a function of period and xspacing +float[] yvalues; // Using an array to store height values for the wave (not entirely necessary) + +void setup() { + size(640,360); + colorMode(RGB, 255, 255, 255, 100); + w = width + 16; + + for (int i = 0; i < maxwaves; i++) { + amplitude[i] = random(10,30); + float period = random(100,300); // How many pixels before the wave repeats + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new float[w/xspacing]; +} + +void draw() { + background(0); + calcWave(); + renderWave(); +} + +void calcWave() { + // Increment theta (try different values for 'angular velocity' here + theta += 0.02; + + // Set all height values to zero + for (int i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // Accumulate wave height values + for (int j = 0; j < maxwaves; j++) { + float x = theta; + for (int i = 0; i < yvalues.length; i++) { + // Every other wave is cosine instead of sine + if (j % 2 == 0) yvalues[i] += sin(x)*amplitude[j]; + else yvalues[i] += cos(x)*amplitude[j]; + x+=dx[j]; + } + } +} + +void renderWave() { + // A simple way to draw the wave with an ellipse at each location + noStroke(); + fill(255,50); + ellipseMode(CENTER); + for (int x = 0; x < yvalues.length; x++) { + ellipse(x*xspacing,height/2+yvalues[x],16,16); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/AttractionArrayWithOscillation.pde b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/AttractionArrayWithOscillation.pde new file mode 100644 index 000000000..8f58c9712 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/AttractionArrayWithOscillation.pde @@ -0,0 +1,46 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Attraction Array with Oscillating objects around each Crawler + +// Click and drag attractive body to move throughout space + +Crawler[] crawlers = new Crawler[6]; +Attractor a; + +void setup() { + size(640,360); + // Some random bodies + for (int i = 0; i < crawlers.length; i++) { + crawlers[i] = new Crawler(); + } + // Create an attractive body + a = new Attractor(new PVector(width/2,height/2),20,0.4); +} + +void draw() { + background(255); + a.rollover(mouseX,mouseY); + a.go(); + + for (int i = 0; i < crawlers.length; i++) { + // Calculate a force exerted by "attractor" on "Crawler" + PVector f = a.attract(crawlers[i]); + // Apply that force to the Crawler + crawlers[i].applyForce(f); + // Update and render + crawlers[i].update(); + crawlers[i].display(); + } + + +} + +void mousePressed() { + a.clicked(mouseX,mouseY); +} + +void mouseReleased() { + a.stopDragging(); +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Attractor.pde b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Attractor.pde new file mode 100644 index 000000000..4e97f0cab --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Attractor.pde @@ -0,0 +1,82 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Attraction + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + float G; // Gravitational Constant + PVector loc; // Location + boolean dragging = false; // Is the object being dragged? + boolean rollover = false; // Is the mouse over the ellipse? + PVector drag; // holds the offset for when object is clicked on + + Attractor(PVector l_,float m_, float g_) { + loc = l_.get(); + mass = m_; + G = g_; + drag = new PVector(0.0,0.0); + } + + void go() { + render(); + drag(); + } + + PVector attract(Crawler c) { + PVector dir = PVector.sub(loc,c.loc); // Calculate direction of force + float d = dir.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 + dir.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float force = (G * mass * c.mass) / (d * d); // Calculate gravitional force magnitude + dir.mult(force); // Get force vector --> magnitude * direction + return dir; + } + + // Method to display + void render() { + ellipseMode(CENTER); + stroke(0,100); + if (dragging) fill (50); + else if (rollover) fill(100); + else fill(175,50); + ellipse(loc.x,loc.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + void clicked(int mx, int my) { + float d = dist(mx,my,loc.x,loc.y); + if (d < mass) { + dragging = true; + drag.x = loc.x-mx; + drag.y = loc.y-my; + } + } + + void rollover(int mx, int my) { + float d = dist(mx,my,loc.x,loc.y); + if (d < mass) { + rollover = true; + } else { + rollover = false; + } + } + + void stopDragging() { + dragging = false; + } + + + + void drag() { + if (dragging) { + loc.x = mouseX + drag.x; + loc.y = mouseY + drag.y; + } + } + +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde new file mode 100644 index 000000000..7c03641ee --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde @@ -0,0 +1,58 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Attraction + +// A class to describe a thing in our world, has vectors for location, velocity, and acceleration +// Also includes scalar values for mass, maximum velocity, and elasticity + +class Crawler { + PVector loc; + PVector vel; + PVector acc; + float mass; + + Oscillator osc; + + Crawler() { + acc = new PVector(); + vel = new PVector(random(-1,1),random(-1,1)); + loc = new PVector(random(width),random(height)); + mass = random(8,16); + osc = new Oscillator(mass*2); + } + + void applyForce(PVector force) { + PVector f = force.get(); + f.div(mass); + acc.add(f); + } + + // Method to update location + void update() { + vel.add(acc); + loc.add(vel); + // Multiplying by 0 sets the all the components to 0 + acc.mult(0); + + osc.update(vel.mag()/10); + } + + // Method to display + void display() { + float angle = vel.heading2D(); + pushMatrix(); + translate(loc.x,loc.y); + rotate(angle); + ellipseMode(CENTER); + stroke(0); + fill(175,100); + ellipse(0,0,mass*2,mass*2); + + osc.display(loc); + popMatrix(); + + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Oscillator.pde b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Oscillator.pde new file mode 100644 index 000000000..2f4d4506d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Oscillator.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Attraction Array with Oscillating objects around each thing + +class Oscillator { + + // Because we are going to oscillate along the x and y axis we can use PVector for two angles, amplitudes, etc.! + float theta; + float amplitude; + + Oscillator(float r) { + + // Initialize randomly + theta = 0; + amplitude = r; + + } + + // Update theta and offset + void update(float thetaVel) { + theta += thetaVel; + } + + // Display based on a location + void display(PVector loc) { + float x = map(cos(theta),-1,1,0,amplitude); + + stroke(0); + fill(50); + line(0,0,x,0); + ellipse(x,0,8,8); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_01_exercise_baton/Exercise_3_01_exercise_baton.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_01_exercise_baton/Exercise_3_01_exercise_baton.pde new file mode 100644 index 000000000..590ea83ab --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_01_exercise_baton/Exercise_3_01_exercise_baton.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float angle = 0; + +void setup() { + size(750, 150); + smooth(); +} + +void draw() { + background(255); + + fill(127); + stroke(0); + rectMode(CENTER); + translate(width/2, height/2); + rotate(angle); + line(-50, 0, 50, 0); + stroke(0); + strokeWeight(2); + fill(127); + ellipse(50, 0, 16, 16); + ellipse(-50, 0, 16, 16); + angle += 0.05; +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_04_spiral/Exercise_3_04_spiral.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_04_spiral/Exercise_3_04_spiral.pde new file mode 100644 index 000000000..90b7fea95 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_04_spiral/Exercise_3_04_spiral.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A Polar coordinate, radius now starts at 0 to spiral outwards +float r = 0; +float theta = 0; + +void setup() { + size(750,200); + background(255); + smooth(); +} + +void draw() { + // Polar to Cartesian conversion + float x = r * cos(theta); + float y = r * sin(theta); + + // Draw an ellipse at x,y + noStroke(); + fill(0); + // Adjust for center of window + ellipse(x+width/2, y+height/2, 16, 16); + + // Increment the angle + theta += 0.01; + // Increment the radius + r += 0.05; +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde new file mode 100644 index 000000000..8f031f272 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde @@ -0,0 +1,41 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Chapter 3: Asteroids exercise + +// Mover object +Spaceship ship; + +void setup() { + size(750, 200); + ship = new Spaceship(); +} + +void draw() { + background(255); + + // Update location + ship.update(); + // Wrape edges + ship.wrapEdges(); + // Draw ship + ship.display(); + + + fill(0); + //text("left right arrows to turn, z to thrust",10,height-5); + + // Turn or thrust the ship depending on what key is pressed + if (keyPressed) { + if (key == CODED && keyCode == LEFT) { + ship.turn(-0.03); + } else if (key == CODED && keyCode == RIGHT) { + ship.turn(0.03); + } else if (key == 'z' || key == 'Z') { + ship.thrust(); + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Spaceship.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Spaceship.pde new file mode 100644 index 000000000..3a8682da7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Spaceship.pde @@ -0,0 +1,99 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Chapter 3: Asteroids + +class Spaceship { + // All of our regular motion stuff + PVector location; + PVector velocity; + PVector acceleration; + + // Arbitrary damping to slow down ship + float damping = 0.995; + float topspeed = 6; + + // Variable for heading! + float heading = 0; + + // Size + float r = 16; + + // Are we thrusting (to color boosters) + boolean thrusting = false; + + Spaceship() { + location = new PVector(width/2,height/2); + velocity = new PVector(); + acceleration = new PVector(); + } + + // Standard Euler integration + void update() { + velocity.add(acceleration); + velocity.mult(damping); + velocity.limit(topspeed); + location.add(velocity); + acceleration.mult(0); + } + + // Newton's law: F = M * A + void applyForce(PVector force) { + PVector f = force.get(); + //f.div(mass); // ignoring mass right now + acceleration.add(f); + } + + // Turn changes angle + void turn(float a) { + heading += a; + } + + // Apply a thrust force + void thrust() { + // Offset the angle since we drew the ship vertically + float angle = heading - PI/2; + // Polar to cartesian for force vector! + PVector force = new PVector(cos(angle),sin(angle)); + force.mult(0.1); + applyForce(force); + // To draw booster + thrusting = true; + } + + void wrapEdges() { + float buffer = r*2; + if (location.x > width + buffer) location.x = -buffer; + else if (location.x < -buffer) location.x = width+buffer; + if (location.y > height + buffer) location.y = -buffer; + else if (location.y < -buffer) location.y = height+buffer; + } + + + // Draw the ship + void display() { + stroke(0); + strokeWeight(2); + pushMatrix(); + translate(location.x,location.y+r); + rotate(heading); + fill(175); + if (thrusting) fill(255,0,0); + // Booster rockets + rect(-r/2,r,r/3,r/2); + rect(r/2,r,r/3,r/2); + fill(175); + // A triangle + beginShape(); + vertex(-r,r); + vertex(0,-r); + vertex(r,r); + endShape(CLOSE); + rectMode(CENTER); + popMatrix(); + + thrusting = false; + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_10_OOPWave/Exercise_3_10_OOPWave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_10_OOPWave/Exercise_3_10_OOPWave.pde new file mode 100644 index 000000000..f8b759970 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_10_OOPWave/Exercise_3_10_OOPWave.pde @@ -0,0 +1,32 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Sine Wave + +// Two wave objects +Wave wave0; +Wave wave1; + +void setup() { + size(750,200); + // Initialize a wave with starting point, width, amplitude, and period + wave0 = new Wave(new PVector(50,75),100,20,500); + wave1 = new Wave(new PVector(300,100),300,40,220); + +} + +void draw() { + background(255); + + // Update and display waves + wave0.calculate(); + wave0.display(); + + wave1.calculate(); + wave1.display(); + + +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_10_OOPWave/Wave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_10_OOPWave/Wave.pde new file mode 100644 index 000000000..df88f7cd0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_10_OOPWave/Wave.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Wave { + + int xspacing = 8; // How far apart should each horizontal location be spaced + int w; // Width of entire wave + + PVector origin; // Where does the wave's first point start + float theta = 0.0; // Start angle at 0 + float amplitude; // Height of wave + float period; // How many pixels before the wave repeats + float dx; // Value for incrementing X, to be calculated as a function of period and xspacing + float[] yvalues; // Using an array to store height values for the wave (not entirely necessary) + + Wave(PVector o, int w_, float a, float p) { + origin = o.get(); + w = w_; + period = p; + amplitude = a; + dx = (TWO_PI / period) * xspacing; + yvalues = new float[w/xspacing]; + } + + + void calculate() { + // Increment theta (try different values for 'angular velocity' here + theta += 0.02; + + // For every x value, calculate a y value with sine function + float x = theta; + for (int i = 0; i < yvalues.length; i++) { + yvalues[i] = sin(x)*amplitude; + x+=dx; + } + } + + void display() { + // A simple way to draw the wave with an ellipse at each location + for (int x = 0; x < yvalues.length; x++) { + stroke(0); + fill(0,50); + ellipseMode(CENTER); + ellipse(origin.x+x*xspacing,origin.y+yvalues[x],48,48); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_11_AdditiveWave/Exercise_3_11_AdditiveWave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_11_AdditiveWave/Exercise_3_11_AdditiveWave.pde new file mode 100644 index 000000000..ccf0975a3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_11_AdditiveWave/Exercise_3_11_AdditiveWave.pde @@ -0,0 +1,66 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Additive Wave +// Create a more complex wave by adding two waves together. + +int xspacing = 8; // How far apart should each horizontal location be spaced +int w; // Width of entire wave +int maxwaves = 5; // total # of waves to add together + +float theta = 0.0; +float[] amplitude = new float[maxwaves]; // Height of wave +float[] dx = new float[maxwaves]; // Value for incrementing X, to be calculated as a function of period and xspacing +float[] yvalues; // Using an array to store height values for the wave (not entirely necessary) + +void setup() { + size(750,200); + w = width + 16; + + for (int i = 0; i < maxwaves; i++) { + amplitude[i] = random(10,30); + float period = random(100,300); // How many pixels before the wave repeats + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new float[w/xspacing]; +} + +void draw() { + background(255); + calcWave(); + renderWave(); +} + +void calcWave() { + // Increment theta (try different values for 'angular velocity' here + theta += 0.02; + + // Set all height values to zero + for (int i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // Accumulate wave height values + for (int j = 0; j < maxwaves; j++) { + float x = theta; + for (int i = 0; i < yvalues.length; i++) { + // Every other wave is cosine instead of sine + if (j % 2 == 0) yvalues[i] += sin(x)*amplitude[j]; + else yvalues[i] += cos(x)*amplitude[j]; + x+=dx[j]; + } + } +} + +void renderWave() { + // A simple way to draw the wave with an ellipse at each location + stroke(0); + fill(127,50); + ellipseMode(CENTER); + for (int x = 0; x < yvalues.length; x++) { + ellipse(x*xspacing,height/2+yvalues[x],48,48); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_03spring_exercise_sine/NOC_03spring_exercise_sine.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_03spring_exercise_sine/NOC_03spring_exercise_sine.pde new file mode 100644 index 000000000..4645efce7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_03spring_exercise_sine/NOC_03spring_exercise_sine.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float angle = 0; +float aVelocity = 0.05; + +void setup() { + size(640,360); + smooth(); +} + +void draw() { + background(255); + + float x = width/2; + float y = map(sin(angle),-1,1,50,250); + angle += aVelocity; + + ellipseMode(CENTER); + stroke(0); + fill(175); + line(x,0,x,y); + ellipse(x,y,20,20); +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_01_angular_motion/NOC_3_01_angular_motion.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_01_angular_motion/NOC_3_01_angular_motion.pde new file mode 100644 index 000000000..e36c11dd8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_01_angular_motion/NOC_3_01_angular_motion.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float angle = 0; +float aVelocity = 0; +float aAcceleration = 0.0001; + +void setup() { + size(800, 200); + smooth(); +} + +void draw() { + background(255); + + + fill(127); + stroke(0); + + translate(width/2, height/2); + rectMode(CENTER); + rotate(angle); + stroke(0); + strokeWeight(2); + fill(127); + line(-60, 0, 60, 0); + ellipse(60, 0, 16, 16); + ellipse(-60, 0, 16, 16); + + angle += aVelocity; + aVelocity += aAcceleration; +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/Attractor.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/Attractor.pde new file mode 100644 index 000000000..c7c457db7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/Attractor.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Attraction + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + PVector location; // Location + float g; + + Attractor() { + location = new PVector(width/2, height/2); + mass = 20; + g = 0.4; + } + + + PVector attract(Mover m) { + PVector force = PVector.sub(location, m.location); // Calculate direction of force + float distance = force.mag(); // Distance between objects + distance = constrain(distance, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + // Method to display + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x, location.y, 48, 48); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/Mover.pde new file mode 100644 index 000000000..be9646c09 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/Mover.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + float angle = 0; + float aVelocity = 0; + float aAcceleration = 0; + + Mover(float m, float x, float y) { + mass = m; + location = new PVector(x,y); + velocity = new PVector(random(-1,1),random(-1,1)); + acceleration = new PVector(0,0); + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + + velocity.add(acceleration); + location.add(velocity); + + aAcceleration = acceleration.x / 10.0; + aVelocity += aAcceleration; + aVelocity = constrain(aVelocity,-0.1,0.1); + angle += aVelocity; + + acceleration.mult(0); + } + + void display() { + stroke(0); + fill(175,200); + rectMode(CENTER); + pushMatrix(); + translate(location.x,location.y); + rotate(angle); + rect(0,0,mass*16,mass*16); + popMatrix(); + } + +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/NOC_3_02_forces_angular_motion.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/NOC_3_02_forces_angular_motion.pde new file mode 100644 index 000000000..4d4302aff --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_02_forces_angular_motion/NOC_3_02_forces_angular_motion.pde @@ -0,0 +1,42 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover[] movers = new Mover[20]; + +Attractor a; + +void setup() { + size(800,200); + background(255); + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(0.1,2),random(width),random(height)); + } + a = new Attractor(); +} + +void draw() { + background(255); + + a.display(); + + for (int i = 0; i < movers.length; i++) { + PVector force = a.attract(movers[i]); + movers[i].applyForce(force); + + movers[i].update(); + movers[i].display(); + } + +} + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde new file mode 100644 index 000000000..399d93a4d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float topspeed; + + float xoff, yoff; + + float r = 16; + + Mover() { + location = new PVector(width/2, height/2); + velocity = new PVector(0, 0); + topspeed = 4; + xoff = 1000; + yoff = 0; + } + + void update() { + + PVector mouse = new PVector(mouseX, mouseY); + PVector dir = PVector.sub(mouse, location); + dir.normalize(); + dir.mult(0.5); + acceleration = dir; + + velocity.add(acceleration); + velocity.limit(topspeed); + location.add(velocity); + } + + void display() { + float theta = velocity.heading2D(); + + stroke(0); + strokeWeight(2); + fill(127); + pushMatrix(); + rectMode(CENTER); + translate(location.x, location.y); + rotate(theta); + rect(0, 0, 30, 10); + popMatrix(); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } + else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + location.y = 0; + } + else if (location.y < 0) { + location.y = height; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/NOC_3_03_pointing_velocity.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/NOC_3_03_pointing_velocity.pde new file mode 100644 index 000000000..df09af915 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/NOC_3_03_pointing_velocity.pde @@ -0,0 +1,20 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover mover; + +void setup() { + size(800,200); + mover = new Mover(); +} + +void draw() { + background(255); + + mover.update(); + mover.checkEdges(); + mover.display(); +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_04_PolarToCartesian/NOC_3_04_PolarToCartesian.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_04_PolarToCartesian/NOC_3_04_PolarToCartesian.pde new file mode 100644 index 000000000..8be1f3bd1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_04_PolarToCartesian/NOC_3_04_PolarToCartesian.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// PolarToCartesian +// Convert a polar coordinate (r,theta) to cartesian (x,y): +// x = r * cos(theta) +// y = r * sin(theta) + +float r; +float theta; + + +void setup() { + size(800, 200); + // Initialize all values + r = height * 0.45; + theta = 0; +} + +void draw() { + + background(255); + + // Translate the origin point to the center of the screen + translate(width/2, height/2); + + // Convert polar to cartesian + float x = r * cos(theta); + float y = r * sin(theta); + + // Draw the ellipse at the cartesian coordinate + ellipseMode(CENTER); + fill(127); + stroke(0); + strokeWeight(2); + line(0,0,x,y); + ellipse(x, y, 48, 48); + + // Increase the angle over time + theta += 0.02; + + +} + + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_04_PolarToCartesian_trail/NOC_3_04_PolarToCartesian_trail.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_04_PolarToCartesian_trail/NOC_3_04_PolarToCartesian_trail.pde new file mode 100644 index 000000000..928afe73a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_04_PolarToCartesian_trail/NOC_3_04_PolarToCartesian_trail.pde @@ -0,0 +1,52 @@ +/** + * PolarToCartesian + * by Daniel Shiffman. + * + * Convert a polar coordinate (r,theta) to cartesian (x,y): + * x = r * cos(theta) + * y = r * sin(theta) + */ + +float r; +float theta; + + +void setup() { + size(800, 200); + background(255); + // Initialize all values + r = height * 0.45; + theta = 0; +} + +void draw() { + + //background(255); + noStroke(); + fill(255,5); + rect(0,0,width,height); + + // Translate the origin point to the center of the screen + translate(width/2, height/2); + + // Convert polar to cartesian + float x = r * cos(theta); + float y = r * sin(theta); + + // Draw the ellipse at the cartesian coordinate + ellipseMode(CENTER); + fill(127); + stroke(0); + strokeWeight(2); + line(0,0,x,y); + ellipse(x, y, 48, 48); + + // Increase the angle over time + theta += 0.02; + + +} + + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_05_simple_harmonic_motion/NOC_3_05_simple_harmonic_motion.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_05_simple_harmonic_motion/NOC_3_05_simple_harmonic_motion.pde new file mode 100644 index 000000000..e2830e6ca --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_05_simple_harmonic_motion/NOC_3_05_simple_harmonic_motion.pde @@ -0,0 +1,22 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +void setup() { + size(800,200); +} + +void draw() { + background(255); + + float period = 120; + float amplitude = 300; + // Calculating horizontal location according to formula for simple harmonic motion + float x = amplitude * cos(TWO_PI * frameCount / period); + stroke(0); + strokeWeight(2); + fill(127); + translate(width/2,height/2); + line(0,0,x,0); + ellipse(x,0,48,48); +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_06_simple_harmonic_motion/NOC_3_06_simple_harmonic_motion.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_06_simple_harmonic_motion/NOC_3_06_simple_harmonic_motion.pde new file mode 100644 index 000000000..4ab3782c0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_06_simple_harmonic_motion/NOC_3_06_simple_harmonic_motion.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float angle = 0; +float aVelocity = 0.03; + +void setup() { + size(640,360); + + smooth(); +} + +void draw() { + background(255); + + float amplitude = 300; + float x = amplitude * cos(angle); + angle += aVelocity; + + ellipseMode(CENTER); + stroke(0); + fill(175); + translate(width/2,height/2); + line(0,0,x,0); + ellipse(x,0,20,20); +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_07_oscillating_objects/NOC_3_07_oscillating_objects.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_07_oscillating_objects/NOC_3_07_oscillating_objects.pde new file mode 100644 index 000000000..20af612ed --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_07_oscillating_objects/NOC_3_07_oscillating_objects.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An array of objects +Oscillator[] oscillators = new Oscillator[10]; + +void setup() { + size(800,200); + smooth(); + // Initialize all objects + for (int i = 0; i < oscillators.length; i++) { + oscillators[i] = new Oscillator(); + } + background(255); +} + +void draw() { + background(255); + // Run all objects + for (int i = 0; i < oscillators.length; i++) { + oscillators[i].oscillate(); + oscillators[i].display(); + } +} + + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_07_oscillating_objects/Oscillator.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_07_oscillating_objects/Oscillator.pde new file mode 100644 index 000000000..da9a7d6ca --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_07_oscillating_objects/Oscillator.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Oscillator { + + PVector angle; + PVector velocity; + PVector amplitude; + + Oscillator() { + angle = new PVector(); + velocity = new PVector(random(-0.05, 0.05), random(-0.05, 0.05)); + amplitude = new PVector(random(20,width/2), random(20,height/2)); + } + + void oscillate() { + angle.add(velocity); + } + + void display() { + + float x = sin(angle.x)*amplitude.x; + float y = sin(angle.y)*amplitude.y; + + pushMatrix(); + translate(width/2, height/2); + stroke(0); + strokeWeight(2); + fill(127,127); + line(0, 0, x, y); + ellipse(x, y, 32, 32); + popMatrix(); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_08_static_wave_lines/NOC_3_08_static_wave_lines.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_08_static_wave_lines/NOC_3_08_static_wave_lines.pde new file mode 100644 index 000000000..1149e065d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_08_static_wave_lines/NOC_3_08_static_wave_lines.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float angle = 0; +float angleVel = 0.1; + +size(800,200); +background(255); +stroke(0); +strokeWeight(2); +noFill(); + +beginShape(); +for (int x = 0; x <= width; x += 5) { + float y = map(sin(angle),-1,1,0,height); + vertex(x,y); + angle +=angleVel; +} +endShape(); + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_exercise_additive_wave/NOC_3_09_exercise_additive_wave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_exercise_additive_wave/NOC_3_09_exercise_additive_wave.pde new file mode 100644 index 000000000..fd7f4bc7b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_exercise_additive_wave/NOC_3_09_exercise_additive_wave.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Additive Wave +// Create a more complex wave by adding two waves together. + +// Maybe better for this answer to be OOP??? + +int xspacing = 8; // How far apart should each horizontal location be spaced +int w; // Width of entire wave +int maxwaves = 5; // total # of waves to add together + +float theta = 0.0; +float[] amplitude = new float[maxwaves]; // Height of wave +float[] dx = new float[maxwaves]; // Value for incrementing X, to be calculated as a function of period and xspacing +float[] yvalues; // Using an array to store height values for the wave (not entirely necessary) + +void setup() { + size(640,360); + colorMode(RGB, 255, 255, 255, 100); + w = width + 16; + + for (int i = 0; i < maxwaves; i++) { + amplitude[i] = random(10,30); + float period = random(100,300); // How many pixels before the wave repeats + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new float[w/xspacing]; +} + +void draw() { + background(0); + calcWave(); + renderWave(); +} + +void calcWave() { + // Increment theta (try different values for 'angular velocity' here + theta += 0.02; + + // Set all height values to zero + for (int i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // Accumulate wave height values + for (int j = 0; j < maxwaves; j++) { + float x = theta; + for (int i = 0; i < yvalues.length; i++) { + // Every other wave is cosine instead of sine + if (j % 2 == 0) yvalues[i] += sin(x)*amplitude[j]; + else yvalues[i] += cos(x)*amplitude[j]; + x+=dx[j]; + } + } +} + +void renderWave() { + // A simple way to draw the wave with an ellipse at each location + noStroke(); + fill(255,50); + ellipseMode(CENTER); + for (int x = 0; x < yvalues.length; x++) { + ellipse(x*xspacing,height/2+yvalues[x],16,16); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave/NOC_3_09_wave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave/NOC_3_09_wave.pde new file mode 100644 index 000000000..5eb61b28b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave/NOC_3_09_wave.pde @@ -0,0 +1,28 @@ + +float startAngle = 0; +float angleVel = 0.23; + +void setup() { + size(800,200); + smooth(); +} + +void draw() { + background(255); + + startAngle += 0.015; + float angle = startAngle; + + for (int x = 0; x <= width; x += 24) { + float y = map(sin(angle),-1,1,0,height); + stroke(0); + fill(0,50); + strokeWeight(2); + ellipse(x,y,48,48); + angle += angleVel; + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_a/NOC_3_09_wave_a.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_a/NOC_3_09_wave_a.pde new file mode 100644 index 000000000..95c824eb5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_a/NOC_3_09_wave_a.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float startAngle = 0; +float angleVel = 0.05; + +void setup() { + size(250,200); + smooth(); +} + +void draw() { + background(255); + + startAngle += 0.015; + float angle = startAngle; + + for (int x = 0; x <= width; x += 24) { + float y = map(sin(angle),-1,1,0,height); + stroke(0); + fill(0,50); + strokeWeight(2); + ellipse(x,y,48,48); + angle += angleVel; + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_b/NOC_3_09_wave_b.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_b/NOC_3_09_wave_b.pde new file mode 100644 index 000000000..9749647db --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_b/NOC_3_09_wave_b.pde @@ -0,0 +1,28 @@ + +float startAngle = 0; +float angleVel = 0.2; + +void setup() { + size(250,200); + smooth(); +} + +void draw() { + background(255); + + startAngle += 0.015; + float angle = startAngle; + + for (int x = 0; x <= width; x += 24) { + float y = map(sin(angle),-1,1,0,height); + stroke(0); + fill(0,50); + strokeWeight(2); + ellipse(x,y,48,48); + angle += angleVel; + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_c/NOC_3_09_wave_c.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_c/NOC_3_09_wave_c.pde new file mode 100644 index 000000000..88a1e396d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_09_wave_c/NOC_3_09_wave_c.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float startAngle = 0; +float angleVel = 0.4; + +void setup() { + size(250,200); + smooth(); +} + +void draw() { + background(255); + + startAngle += 0.015; + float angle = startAngle; + + for (int x = 0; x <= width; x += 24) { + float y = map(sin(angle),-1,1,0,height); + stroke(0); + fill(0,50); + strokeWeight(2); + ellipse(x,y,48,48); + angle += angleVel; + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExample/NOC_3_10_PendulumExample.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExample/NOC_3_10_PendulumExample.pde new file mode 100644 index 000000000..80fe915bb --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExample/NOC_3_10_PendulumExample.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pendulum + +// A simple pendulum simulation +// Given a pendulum with an angle theta (0 being the pendulum at rest) and a radius r +// we can use sine to calculate the angular component of the gravitational force. + +// Gravity Force = Mass * Gravitational Constant; +// Pendulum Force = Gravity Force * sine(theta) +// Angular Acceleration = Pendulum Force / Mass = gravitational acceleration * sine(theta); + +// Note this is an ideal world scenario with no tension in the +// pendulum arm, a more realistic formula might be: +// Angular Acceleration = (g / R) * sine(theta) + +// For a more substantial explanation, visit: +// http://www.myphysicslab.com/pendulum1.html + +Pendulum p; + +void setup() { + size(800,200); + // Make a new Pendulum with an origin location and armlength + p = new Pendulum(new PVector(width/2,0),175); + +} + +void draw() { + + background(255); + p.go(); +} + +void mousePressed() { + p.clicked(mouseX,mouseY); +} + +void mouseReleased() { + p.stopDragging(); +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExample/Pendulum.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExample/Pendulum.pde new file mode 100644 index 000000000..02d400155 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExample/Pendulum.pde @@ -0,0 +1,98 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pendulum + +// A Simple Pendulum Class +// Includes functionality for user can click and drag the pendulum + +class Pendulum { + + PVector location; // Location of pendulum ball + PVector origin; // Location of arm origin + float r; // Length of arm + float angle; // Pendulum arm angle + float aVelocity; // Angle velocity + float aAcceleration; // Angle acceleration + + float ballr; // Ball radius + float damping; // Arbitary damping amount + + boolean dragging = false; + + // This constructor could be improved to allow a greater variety of pendulums + Pendulum(PVector origin_, float r_) { + // Fill all variables + origin = origin_.get(); + location = new PVector(); + r = r_; + angle = PI/4; + + aVelocity = 0.0; + aAcceleration = 0.0; + damping = 0.995; // Arbitrary damping + ballr = 48.0; // Arbitrary ball radius + } + + void go() { + update(); + drag(); //for user interaction + display(); + } + + // Function to update location + void update() { + // As long as we aren't dragging the pendulum, let it swing! + if (!dragging) { + float gravity = 0.4; // Arbitrary constant + aAcceleration = (-1 * gravity / r) * sin(angle); // Calculate acceleration (see: http://www.myphysicslab.com/pendulum1.html) + aVelocity += aAcceleration; // Increment velocity + aVelocity *= damping; // Arbitrary damping + angle += aVelocity; // Increment angle + } + } + + void display() { + location.set(r*sin(angle), r*cos(angle), 0); // Polar to cartesian conversion + location.add(origin); // Make sure the location is relative to the pendulum's origin + + stroke(0); + strokeWeight(2); + // Draw the arm + line(origin.x, origin.y, location.x, location.y); + ellipseMode(CENTER); + fill(175); + if (dragging) fill(0); + // Draw the ball + ellipse(location.x, location.y, ballr, ballr); + } + + + // The methods below are for mouse interaction + + // This checks to see if we clicked on the pendulum ball + void clicked(int mx, int my) { + float d = dist(mx, my, location.x, location.y); + if (d < ballr) { + dragging = true; + } + } + + // This tells us we are not longer clicking on the ball + void stopDragging() { + aVelocity = 0; // No velocity once you let go + dragging = false; + } + + void drag() { + // If we are draging the ball, we calculate the angle between the + // pendulum origin and mouse location + // we assign that angle to the pendulum + if (dragging) { + PVector diff = PVector.sub(origin, new PVector(mouseX, mouseY)); // Difference between 2 points + angle = atan2(-1*diff.y, diff.x) - radians(90); // Angle relative to vertical axis + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExampleSimplified/NOC_3_10_PendulumExampleSimplified.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExampleSimplified/NOC_3_10_PendulumExampleSimplified.pde new file mode 100644 index 000000000..07c09ed46 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExampleSimplified/NOC_3_10_PendulumExampleSimplified.pde @@ -0,0 +1,35 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pendulum + +// A simple pendulum simulation +// Given a pendulum with an angle theta (0 being the pendulum at rest) and a radius r +// we can use sine to calculate the angular component of the gravitational force. + +// Gravity Force = Mass * Gravitational Constant; +// Pendulum Force = Gravity Force * sine(theta) +// Angular Acceleration = Pendulum Force / Mass = Gravitational Constant * sine(theta); + +// Note this is an ideal world scenario with no tension in the +// pendulum arm, a more realistic formula might be: +// Angular Acceleration = (G / R) * sine(theta) + +// For a more substantial explanation, visit: +// http://www.myphysicslab.com/pendulum1.html + +Pendulum p; + +void setup() { + size(800,200); + // Make a new Pendulum with an origin location and armlength + p = new Pendulum(new PVector(width/2,0),175); + +} + +void draw() { + background(255); + p.go(); +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExampleSimplified/Pendulum.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExampleSimplified/Pendulum.pde new file mode 100644 index 000000000..1b63fd3cc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_10_PendulumExampleSimplified/Pendulum.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pendulum + +// A Simple Pendulum Class +// Includes functionality for user can click and drag the pendulum + +class Pendulum { + + PVector location; // Location of pendulum ball + PVector origin; // Location of arm origin + float r; // Length of arm + float angle; // Pendulum arm angle + float aVelocity; // Angle velocity + float aAcceleration; // Angle acceleration + float damping; // Arbitary damping amount + + // This constructor could be improved to allow a greater variety of pendulums + Pendulum(PVector origin_, float r_) { + // Fill all variables + origin = origin_.get(); + location = new PVector(); + r = r_; + angle = PI/4; + + aVelocity = 0.0; + aAcceleration = 0.0; + damping = 0.995; // Arbitrary damping + } + + void go() { + update(); + display(); + } + + // Function to update location + void update() { + float gravity = 0.4; // Arbitrary constant + aAcceleration = (-1 * gravity / r) * sin(angle); // Calculate acceleration (see: http://www.myphysicslab.com/pendulum1.html) + aVelocity += aAcceleration; // Increment velocity + aVelocity *= damping; // Arbitrary damping + angle += aVelocity; // Increment angle + } + + void display() { + location.set(r*sin(angle), r*cos(angle), 0); // Polar to cartesian conversion + location.add(origin); // Make sure the location is relative to the pendulum's origin + + stroke(0); + strokeWeight(2); + // Draw the arm + line(origin.x, origin.y, location.x, location.y); + ellipseMode(CENTER); + fill(175); + // Draw the ball + ellipse(location.x, location.y, 48, 48); + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/Mover.pde new file mode 100644 index 000000000..4545f5cd1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/Mover.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Bob class, just like our regular Mover (location, velocity, acceleration, mass) + +class Bob { + PVector location; + PVector velocity; + PVector acceleration; + float mass = 24; + + // Arbitrary damping to simulate friction / drag + float damping = 0.98; + + // For mouse interaction + PVector dragOffset; + boolean dragging = false; + + // Constructor + Bob(float x, float y) { + location = new PVector(x,y); + velocity = new PVector(); + acceleration = new PVector(); + dragOffset = new PVector(); + } + + // Standard Euler integration + void update() { + velocity.add(acceleration); + velocity.mult(damping); + location.add(velocity); + acceleration.mult(0); + } + + // Newton's law: F = M * A + void applyForce(PVector force) { + PVector f = force.get(); + f.div(mass); + acceleration.add(f); + } + + + // Draw the bob + void display() { + stroke(0); + strokeWeight(2); + fill(175); + if (dragging) { + fill(50); + } + ellipse(location.x,location.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + + // This checks to see if we clicked on the mover + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + dragOffset.x = location.x-mx; + dragOffset.y = location.y-my; + } + } + + void stopDragging() { + dragging = false; + } + + void drag(int mx, int my) { + if (dragging) { + location.x = mx + dragOffset.x; + location.y = my + dragOffset.y; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde new file mode 100644 index 000000000..06532f8c9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Mover object +Bob bob; + +// Spring object +Spring spring; + +void setup() { + size(800,200); + // Create objects at starting location + // Note third argument in Spring constructor is "rest length" + spring = new Spring(width/2,10,100); + bob = new Bob(width/2,100); + +} + +void draw() { + background(255); + // Apply a gravity force to the bob + PVector gravity = new PVector(0,2); + bob.applyForce(gravity); + + // Connect the bob to the spring (this calculates the force) + spring.connect(bob); + // Constrain spring distance between min and max + spring.constrainLength(bob,30,200); + + // Update bob + bob.update(); + // If it's being dragged + bob.drag(mouseX,mouseY); + + // Draw everything + spring.displayLine(bob); // Draw a line between spring and bob + bob.display(); + spring.display(); + + fill(0); + text("click on bob to drag",10,height-5); +} + + +// For mouse interaction with bob + +void mousePressed() { + bob.clicked(mouseX,mouseY); +} + +void mouseReleased() { + bob.stopDragging(); +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/Spring.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/Spring.pde new file mode 100644 index 000000000..565fbb307 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/Spring.pde @@ -0,0 +1,75 @@ +// Nature of Code 2011 +// Daniel Shiffman +// Chapter 3: Oscillation + +// Class to describe an anchor point that can connect to "Bob" objects via a spring +// Thank you: http://www.myphysicslab.com/spring2d.html + +class Spring { + + // Location + PVector anchor; + + // Rest length and spring constant + float len; + float k = 0.2; + + // Constructor + Spring(float x, float y, int l) { + anchor = new PVector(x, y); + len = l; + } + + // Calculate spring force + void connect(Bob b) { + // Vector pointing from anchor to bob location + PVector force = PVector.sub(b.location, anchor); + // What is distance + float d = force.mag(); + // Stretch is difference between current distance and rest length + float stretch = d - len; + + // Calculate force according to Hooke's Law + // F = k * stretch + force.normalize(); + force.mult(-1 * k * stretch); + b.applyForce(force); + } + + // Constrain the distance between bob and anchor between min and max + void constrainLength(Bob b, float minlen, float maxlen) { + PVector dir = PVector.sub(b.location, anchor); + float d = dir.mag(); + // Is it too short? + if (d < minlen) { + dir.normalize(); + dir.mult(minlen); + // Reset location and stop from moving (not realistic physics) + b.location = PVector.add(anchor, dir); + b.velocity.mult(0); + // Is it too long? + } + else if (d > maxlen) { + dir.normalize(); + dir.mult(maxlen); + // Reset location and stop from moving (not realistic physics) + b.location = PVector.add(anchor, dir); + b.velocity.mult(0); + } + } + + void display() { + stroke(0); + fill(175); + strokeWeight(2); + rectMode(CENTER); + rect(anchor.x, anchor.y, 10, 10); + } + + void displayLine(Bob b) { + strokeWeight(2); + stroke(0); + line(b.location.x, b.location.y, anchor.x, anchor.y); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties new file mode 100644 index 000000000..b3cbe600e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties @@ -0,0 +1,2 @@ +mode.id=processing.mode.java.JavaMode +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/OOPWaveParticles.pde b/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/OOPWaveParticles.pde new file mode 100644 index 000000000..423afa435 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/OOPWaveParticles.pde @@ -0,0 +1,32 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Sine Wave + +// Two wave objects +Wave wave0; +Wave wave1; + +void setup() { + size(640,360); + // Initialize a wave with starting point, width, amplitude, and period + wave0 = new Wave(new PVector(200,75),100,20,500); + wave1 = new Wave(new PVector(150,250),300,40,220); + +} + +void draw() { + background(255); + + // Update and display waves + wave0.calculate(); + wave0.display(); + + wave1.calculate(); + wave1.display(); + + +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/Particle.pde b/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/Particle.pde new file mode 100644 index 000000000..d04daea97 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/Particle.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Particle { + PVector location; + + Particle() { + location = new PVector(); + } + + void setLocation(float x, float y) { + location.x = x; + location.y = y; + } + + void display() { + fill(random(255)); + ellipse(location.x,location.y,16,16); + } + + +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/Wave.pde b/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/Wave.pde new file mode 100644 index 000000000..9763ba892 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/OOPWaveParticles/Wave.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Wave { + + int xspacing = 8; // How far apart should each horizontal location be spaced + int w; // Width of entire wave + + PVector origin; // Where does the wave's first point start + float theta = 0.0; // Start angle at 0 + float amplitude; // Height of wave + float period; // How many pixels before the wave repeats + float dx; // Value for incrementing X, to be calculated as a function of period and xspacing + //float[] yvalues; // Using an array to store height values for the wave (not entirely necessary) + Particle[] particles; + + Wave(PVector o, int w_, float a, float p) { + origin = o.get(); + w = w_; + period = p; + amplitude = a; + dx = (TWO_PI / period) * xspacing; + particles = new Particle[w/xspacing]; + for (int i = 0; i < particles.length; i++) { + particles[i] = new Particle(); + } + } + + + void calculate() { + // Increment theta (try different values for 'angular velocity' here + theta += 0.02; + + // For every x value, calculate a y value with sine function + float x = theta; + for (int i = 0; i < particles.length; i++) { + particles[i].setLocation(origin.x+i*xspacing,origin.y+sin(x)*amplitude); + x+=dx; + } + } + + void manipulate() { + // Loop through the array of particles and check stuff regarding the mouse + + } + + void display() { + + // A simple way to draw the wave with an ellipse at each location + for (int i = 0; i < particles.length; i++) { + particles[i].display(); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/CircleVsBlob.pde b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/CircleVsBlob.pde new file mode 100644 index 000000000..a81a4ed84 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/CircleVsBlob.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +void setup() { + size(200,200); + PImage img = loadImage("texture.png"); + background(0); + image(img,0,0,width,height); + save("blob.tif"); + + background(0); + fill(255); + noStroke(); + ellipse(100,100,width,height); + save("circle.tif"); +} + +void draw() { + + +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/blob.tif b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/blob.tif new file mode 100644 index 000000000..62b3058e4 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/blob.tif differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/circle.tif b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/circle.tif new file mode 100644 index 000000000..101ae8775 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/circle.tif differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/data/texture.gif b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/data/texture.gif new file mode 100644 index 000000000..17e84e806 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/data/texture.gif differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/data/texture.psd b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/data/texture.psd new file mode 100644 index 000000000..8208feb02 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/CircleVsBlob/data/texture.psd differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle/NOC_4_01_SingleParticle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle/NOC_4_01_SingleParticle.pde new file mode 100644 index 000000000..1ab939148 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle/NOC_4_01_SingleParticle.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Particle p; + +void setup() { + size(800,200); + p = new Particle(new PVector(width/2,20)); + background(255); + smooth(); +} + +void draw() { + background(255); + + p.run(); + if (p.isDead()) { + p = new Particle(new PVector(width/2,20)); + //println("Particle dead!"); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle/Particle.pde new file mode 100644 index 000000000..ca927c34a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle/Particle.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +// A simple Particle class + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0, 0.05); + velocity = new PVector(random(-1, 1), random(-1, 0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0, lifespan); + strokeWeight(2); + fill(127, lifespan); + ellipse(location.x, location.y, 12, 12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle_trail/NOC_4_01_SingleParticle_trail.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle_trail/NOC_4_01_SingleParticle_trail.pde new file mode 100644 index 000000000..e372ea14e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle_trail/NOC_4_01_SingleParticle_trail.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Particle p; + +void setup() { + size(800, 200); + p = new Particle(new PVector(width/2, 20)); + background(255); + smooth(); +} + +void draw() { + if (mousePressed) { + noStroke(); + fill(255, 5); + rect(0, 0, width, height); + + p.run(); + if (p.isDead()) { + println("Particle dead!"); + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle_trail/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle_trail/Particle.pde new file mode 100644 index 000000000..5e78f8545 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_01_SingleParticle_trail/Particle.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0, 0.05); + velocity = new PVector(random(-1, 1), -1); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0, lifespan); + strokeWeight(2); + fill(127); + ellipse(location.x, location.y, 12, 12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_02_ArrayListParticles/NOC_4_02_ArrayListParticles.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_02_ArrayListParticles/NOC_4_02_ArrayListParticles.pde new file mode 100644 index 000000000..1734f0d41 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_02_ArrayListParticles/NOC_4_02_ArrayListParticles.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ArrayList particles; + +void setup() { + size(800,200); + particles = new ArrayList(); + smooth(); +} + +void draw() { + background(255); + + particles.add(new Particle(new PVector(width/2,50))); + + // Using the iterator + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } +} + + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_02_ArrayListParticles/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_02_ArrayListParticles/Particle.pde new file mode 100644 index 000000000..a4c372ac4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_02_ArrayListParticles/Particle.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0, 0.05); + velocity = new PVector(random(-1, 1), random(-2, 0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0, lifespan); + strokeWeight(2); + fill(127, lifespan); + ellipse(location.x, location.y, 12, 12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde new file mode 100644 index 000000000..d3268cc8e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde @@ -0,0 +1,16 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(800,200); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + ps.addParticle(); + ps.run(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/Particle.pde new file mode 100644 index 000000000..12d1ef02a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/Particle.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde new file mode 100644 index 000000000..895e5f6aa --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde @@ -0,0 +1,35 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Using Generics now! comment and annotate, etc. + +class ParticleSystem { + ArrayList particles; + PVector origin; + + ParticleSystem(PVector location) { + origin = location.get(); + particles = new ArrayList(); + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + void run() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde new file mode 100644 index 000000000..ca95f10c5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde @@ -0,0 +1,32 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Simple Particle System + +// 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. + +ArrayList systems; + +void setup() { + size(800,200); + systems = new ArrayList(); + smooth(); +} + +void draw() { + background(255); + for (ParticleSystem ps: systems) { + ps.run(); + ps.addParticle(); + } +} + +void mousePressed() { + systems.add(new ParticleSystem(1,new PVector(mouseX,mouseY))); +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/Particle.pde new file mode 100644 index 000000000..12d1ef02a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/Particle.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde new file mode 100644 index 000000000..3d237a8b1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList 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(); // Initialize the arraylist + origin = v.get(); // 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() { + // Using the Iterator b/c we are deleting from list while iterating + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } else { + return false; + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/NOC_4_04_SystemofSystems_b.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/NOC_4_04_SystemofSystems_b.pde new file mode 100644 index 000000000..259705bb1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/NOC_4_04_SystemofSystems_b.pde @@ -0,0 +1,35 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +// 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. + +ArrayList systems; + +void setup() { + size(800,200); + systems = new ArrayList(); + systems.add(new ParticleSystem(1,new PVector(100,25))); + + smooth(); +} + +void draw() { + background(255); + for (ParticleSystem ps: systems) { + ps.run(); + ps.addParticle(); + } +} + +void mousePressed() { + systems.add(new ParticleSystem(1,new PVector(mouseX,mouseY))); +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/Particle.pde new file mode 100644 index 000000000..a019abea2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/Particle.pde @@ -0,0 +1,49 @@ +// Simple Particle System +// Daniel Shiffman + +// A simple Particle class + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/ParticleSystem.pde new file mode 100644 index 000000000..3d237a8b1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_b/ParticleSystem.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList 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(); // Initialize the arraylist + origin = v.get(); // 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() { + // Using the Iterator b/c we are deleting from list while iterating + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } else { + return false; + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/NOC_4_04_SystemofSystems_c.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/NOC_4_04_SystemofSystems_c.pde new file mode 100644 index 000000000..153537fea --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/NOC_4_04_SystemofSystems_c.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +// 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. + +ArrayList systems; + +void setup() { + size(800,200); + systems = new ArrayList(); + systems.add(new ParticleSystem(1,new PVector(100,25))); + for (int i = 0; i < 6; i++) { + systems.add(new ParticleSystem(1,new PVector(random(width),random(height)))); + } + + smooth(); +} + +void draw() { + background(255); + for (ParticleSystem ps: systems) { + ps.run(); + ps.addParticle(); + } +} + +void mousePressed() { + systems.add(new ParticleSystem(1,new PVector(mouseX,mouseY))); +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/Particle.pde new file mode 100644 index 000000000..12d1ef02a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/Particle.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/ParticleSystem.pde new file mode 100644 index 000000000..870908e47 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems_c/ParticleSystem.pde @@ -0,0 +1,52 @@ +// Simple Particle System +// Daniel Shiffman + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList 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(); // Initialize the arraylist + origin = v.get(); // 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() { + // Using the Iterator b/c we are deleting from list while iterating + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } else { + return false; + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/Confetti.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/Confetti.pde new file mode 100644 index 000000000..e86ce8d5b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/Confetti.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Confetti extends Particle { + + // We could add variables for only Confetti here if we so + + Confetti(PVector l) { + super(l); + } + + // Inherits update() from parent + + // Override the display method + void display() { + rectMode(CENTER); + fill(127,lifespan); + stroke(0,lifespan); + strokeWeight(2); + pushMatrix(); + translate(location.x,location.y); + float theta = map(location.x,0,width,0,TWO_PI*2); + rotate(theta); + rect(0,0,12,12); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde new file mode 100644 index 000000000..d3268cc8e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde @@ -0,0 +1,16 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(800,200); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + ps.addParticle(); + ps.run(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/Particle.pde new file mode 100644 index 000000000..b38b30cf7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/Particle.pde @@ -0,0 +1,51 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde new file mode 100644 index 000000000..33a0e6353 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class ParticleSystem { + ArrayList particles; + PVector origin; + + ParticleSystem(PVector location) { + origin = location.get(); + particles = new ArrayList(); + } + + void addParticle() { + float r = random(1); + if (r < 0.5) { + particles.add(new Particle(origin)); + } else { + particles.add(new Confetti(origin)); + } + } + + void run() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } +} + + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde new file mode 100644 index 000000000..6fcac8462 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(800,200); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + + // Apply gravity force to all Particles + PVector gravity = new PVector(0,0.1); + ps.applyForce(gravity); + + ps.addParticle(); + ps.run(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/Particle.pde new file mode 100644 index 000000000..971ea0c5c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/Particle.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + float mass = 1; // Let's do something better here! + + Particle(PVector l) { + acceleration = new PVector(0,0); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + void applyForce(PVector force) { + PVector f = force.get(); + f.div(mass); + acceleration.add(f); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde new file mode 100644 index 000000000..8bf9f10ba --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class ParticleSystem { + ArrayList particles; + PVector origin; + + ParticleSystem(PVector location) { + origin = location.get(); + particles = new ArrayList(); + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + // A function to apply a force to all Particles + void applyForce(PVector f) { + for (Particle p: particles) { + p.applyForce(f); + } + } + + void run() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde new file mode 100644 index 000000000..ac4a29c08 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; +Repeller repeller; + +void setup() { + size(800,200); + ps = new ParticleSystem(new PVector(width/2,50)); + repeller = new Repeller(width/2-20,height/2); +} + +void draw() { + background(255); + ps.addParticle(); + + // Apply gravity force to all Particles + PVector gravity = new PVector(0,0.1); + ps.applyForce(gravity); + + ps.applyRepeller(repeller); + + repeller.display(); + ps.run(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/Particle.pde new file mode 100644 index 000000000..971ea0c5c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/Particle.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + float mass = 1; // Let's do something better here! + + Particle(PVector l) { + acceleration = new PVector(0,0); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + void applyForce(PVector force) { + PVector f = force.get(); + f.div(mass); + acceleration.add(f); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde new file mode 100644 index 000000000..34725b859 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde @@ -0,0 +1,46 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class ParticleSystem { + ArrayList particles; + PVector origin; + + ParticleSystem(PVector location) { + origin = location.get(); + particles = new ArrayList(); + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + // A function to apply a force to all Particles + void applyForce(PVector f) { + for (Particle p: particles) { + p.applyForce(f); + } + } + + void applyRepeller(Repeller r) { + for (Particle p: particles) { + PVector force = r.repel(p); + p.applyForce(force); + } + } + + + void run() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/Repeller.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/Repeller.pde new file mode 100644 index 000000000..351780121 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/Repeller.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Particles + Forces + +// A very basic Repeller class +class Repeller { + + // Gravitational Constant + float G = 100; + // Location + PVector location; + float r = 10; + + Repeller(float x, float y) { + location = new PVector(x,y); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(175); + ellipse(location.x,location.y,48,48); + } + + // Calculate a force to push particle away from repeller + PVector repel(Particle p) { + PVector dir = PVector.sub(location,p.location); // Calculate direction of force + float d = dir.mag(); // Distance between objects + dir.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + d = constrain(d,5,100); // Keep distance within a reasonable range + float force = -1 * G / (d * d); // Repelling force is inversely proportional to distance + dir.mult(force); // Get force vector --> magnitude * direction + return dir; + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde new file mode 100644 index 000000000..61a662565 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Smoke Particle System + +// A basic smoke effect using a particle system +// Each particle is rendered as an alpha masked image + +/* @pjs preload="processingjs/chapter04/_4_08_ParticleSystemSmoke/data/texture.png"; */ + +ParticleSystem ps; +Random generator; + +void setup() { + size(383,200); + generator = new Random(); + PImage img = loadImage("texture.png"); + ps = new ParticleSystem(0,new PVector(width/2,height-25),img); + smooth(); +} + +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 location 'loc' +void drawVector(PVector v, PVector loc, float scayl) { + pushMatrix(); + float arrowsize = 4; + // Translate to location 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.heading2D()); + // 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(); +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde new file mode 100644 index 000000000..3edc523b2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Particle { + PVector loc; + PVector vel; + PVector acc; + float lifespan; + PImage img; + + Particle(PVector l,PImage img_) { + acc = new PVector(0,0); + float vx = (float) generator.nextGaussian()*0.3; + float vy = (float) generator.nextGaussian()*0.3 - 1.0; + vel = new PVector(vx,vy); + loc = l.get(); + 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 location + 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 dead() { + if (lifespan <= 0.0) { + return true; + } else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde new file mode 100644 index 000000000..742306f75 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde @@ -0,0 +1,65 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Smoke Particle System + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList 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(); // Initialize the arraylist + origin = v.get(); // 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() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.dead()) { + it.remove(); + } + } + } + + // 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)); + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } else { + return false; + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/data/texture.psd b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/data/texture.psd new file mode 100644 index 000000000..8208feb02 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/data/texture.psd differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/sketch.properties b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde new file mode 100644 index 000000000..61a662565 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Smoke Particle System + +// A basic smoke effect using a particle system +// Each particle is rendered as an alpha masked image + +/* @pjs preload="processingjs/chapter04/_4_08_ParticleSystemSmoke/data/texture.png"; */ + +ParticleSystem ps; +Random generator; + +void setup() { + size(383,200); + generator = new Random(); + PImage img = loadImage("texture.png"); + ps = new ParticleSystem(0,new PVector(width/2,height-25),img); + smooth(); +} + +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 location 'loc' +void drawVector(PVector v, PVector loc, float scayl) { + pushMatrix(); + float arrowsize = 4; + // Translate to location 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.heading2D()); + // 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(); +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde new file mode 100644 index 000000000..7a06982e7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Simple Particle System + +// 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 = (float) generator.nextGaussian()*0.3; + float vy = (float) generator.nextGaussian()*0.3 - 1.0; + vel = new PVector(vx,vy); + loc = l.get(); + 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 location + 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 dead() { + if (lifespan <= 0.0) { + return true; + } else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde new file mode 100644 index 000000000..ecd805fa4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Smoke Particle Syste + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList 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(); // Initialize the arraylist + origin = v.get(); // 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() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.dead()) { + it.remove(); + } + } + } + + // 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)); + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } else { + return false; + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/data/texture.psd b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/data/texture.psd new file mode 100644 index 000000000..8208feb02 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/data/texture.psd differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/sketch.properties b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/sketch.properties new file mode 100644 index 000000000..b3cbe600e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/sketch.properties @@ -0,0 +1,2 @@ +mode.id=processing.mode.java.JavaMode +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde new file mode 100644 index 000000000..6cecff78d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Smoke Particle System + +// A basic smoke effect using a particle system +// Each particle is rendered as an alpha masked image + +ParticleSystem ps; + +PImage img; + +void setup() { + size(800, 200, P2D); + + // Create an alpha masked image to be applied as the particle's texture + img = loadImage("texture.png"); + + ps = new ParticleSystem(0, new PVector(width/2, 50)); + } + +void draw() { + + blendMode(ADD); + + background(0); + + ps.run(); + for (int i = 0; i < 10; i++) { + ps.addParticle(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde new file mode 100644 index 000000000..9c1fbaf66 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector loc; + PVector vel; + PVector acc; + float lifespan; + + // Another constructor (the one we are using here) + Particle(PVector l) { + // Boring example with constant acceleration + acc = new PVector(0,0.05,0); + vel = new PVector(random(-1,1),random(-1,0),0); + vel.mult(2); + loc = l.get(); + lifespan = 255; + } + + void run() { + update(); + render(); + } + + // Method to update location + void update() { + vel.add(acc); + loc.add(vel); + lifespan -= 2.0; + } + + // Method to display + void render() { + imageMode(CENTER); + tint(lifespan); + image(img,loc.x,loc.y); + } + + // Is the particle still useful? + boolean dead() { + if (lifespan <= 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde new file mode 100644 index 000000000..9b733792d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde @@ -0,0 +1,54 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList particles; // An arraylist for all the particles + PVector origin; // An origin point for where particles are birthed + + PImage tex; + + ParticleSystem(int num, PVector v) { + particles = new ArrayList(); // Initialize the arraylist + origin = v.get(); // 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() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.dead()) { + it.remove(); + } + } + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } else { + return false; + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/data/texture.psd b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/data/texture.psd new file mode 100644 index 000000000..d532f15aa Binary files /dev/null and b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/data/texture.psd differ diff --git a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/NOC_04_6ParticleSystemInheritance_pushpop.pde b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/NOC_04_6ParticleSystemInheritance_pushpop.pde new file mode 100644 index 000000000..348016540 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/NOC_04_6ParticleSystemInheritance_pushpop.pde @@ -0,0 +1,16 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(200,200); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + ps.addParticle(); + ps.run(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/Particle.pde new file mode 100644 index 000000000..bc2e58cb3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/Particle.pde @@ -0,0 +1,61 @@ +// Simple Particle System +// Daniel Shiffman + +// A simple Particle class + +class Particle { + + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + push(); + display(); + pop(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + + void push() { + pushMatrix(); + } + + void pop() { + popMatrix(); + } + + // Method to display + void display() { + stroke(0,lifespan); + fill(0,lifespan); + translate(location.x,location.y); + ellipse(0,0,8,8); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleChild.pde b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleChild.pde new file mode 100644 index 000000000..95b089aa3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleChild.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class ParticleChild extends Particle { + + // We could add variables for only Confetti here if we so + + ParticleChild(PVector l) { + super(l); + } + + // Inherits update() from parent + + // Override the display method + void display() { + super.display(); + float theta = map(location.x,0,width,0,TWO_PI*2); + rotate(theta); + stroke(0); + line(0,0,50,0); + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde new file mode 100644 index 000000000..22a78969f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class ParticleSystem { + ArrayList particles; + PVector origin; + + ParticleSystem(PVector location) { + origin = location.get(); + particles = new ArrayList(); + } + + void addParticle() { + float r = random(1); + if (r < 0.5) { + particles.add(new Particle(origin)); + } else { + particles.add(new ParticleChild(origin)); + } + } + + void run() { + Iterator it = particles.iterator(); + while (it.hasNext()) { + Particle p = it.next(); + p.run(); + if (p.isDead()) { + it.remove(); + } + } + } +} + + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/NOC_gl.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/NOC_gl.pde new file mode 100644 index 000000000..f96fc9d07 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/NOC_gl.pde @@ -0,0 +1,13 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +void renderImage(PImage img, Vec3D _loc, float _diam, color _col, float _alpha ) { + pushMatrix(); + translate( _loc.x, _loc.y, _loc.z ); + tint(red(_col), green(_col), blue(_col), _alpha); + imageMode(CENTER); + image(img,0,0,_diam,_diam); + popMatrix(); +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde new file mode 100644 index 000000000..479138397 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde @@ -0,0 +1,89 @@ + +/* +The emitter is just an object that follows the cursor and +can spawn new particle objects. It would be easier to just make +the location vector match the cursor position but I have opted +to use a velocity vector because later I will be allowing for +multiple emitters. +*/ + +class Emitter{ + Vec3D loc; + Vec3D vel; + Vec3D velToMouse; + + color myColor; + + ArrayList particles; + + Emitter( ){ + loc = new Vec3D(); + vel = new Vec3D(); + velToMouse = new Vec3D(); + + myColor = color( 1, 1, 1 ); + + particles = new ArrayList(); + } + + void exist(){ + setVelToMouse(); + findVelocity(); + setPosition(); + iterateListExist(); + render(); + + gl.glDisable( GL.GL_TEXTURE_2D ); + + if( ALLOWTRAILS ) + iterateListRenderTrails(); + } + + void setVelToMouse(){ + velToMouse.set( mouseX - loc.x, mouseY - loc.y, 0 ); + } + + void findVelocity(){ + vel.interpolateToSelf( velToMouse, .35 ); + } + + void setPosition(){ + loc.addSelf( vel ); + + if( ALLOWFLOOR ){ + if( loc.y > floorLevel ){ + loc.y = floorLevel; + vel.y = 0; + } + } + } + + void iterateListExist(){ + for( Iterator it = particles.iterator(); it.hasNext(); ){ + Particle p = (Particle) it.next(); + if( !p.ISDEAD ){ + p.exist(); + } else { + it.remove(); + } + } + } + + + void render(){ + renderImage( emitterImg, loc, 150, myColor, 1.0 ); + } + + void iterateListRenderTrails(){ + for( Iterator it = particles.iterator(); it.hasNext(); ){ + Particle p = (Particle) it.next(); + p.renderTrails(); + } + } + + void addParticles( int _amt ){ + for( int i=0; i<_amt; i++ ){ + particles.add( new Particle( loc, vel ) ); + } + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde new file mode 100644 index 000000000..6b26364bf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde @@ -0,0 +1,164 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Updated version of flight404 Particle Emitter release 1 +// This works with Processing 1.0 +// All of the advanced openGL direct calls that use display lists, etc. have been stripped out +// It's my intention to redo this example using GlGraphics (http://glgraphics.sourceforge.net/) +// But for now, just want to make sure it works in principal + +// February 28 2011 +// Daniel Shiffman + +// Source Code release 1 +// Particle Emitter +// +// February 11th 2008 +// +// Built with Processing v.135 which you can download at http://www.processing.org/download +// +// Robert Hodgin +// flight404.com +// barbariangroup.com + +// features: +// Toxi's magnificent Vec3D library +// perlin noise flow fields +// ribbon trails +// OpenGL additive blending +// OpenGL display lists +// +// Uses the very useful Vec3D library by Karsten Schmidt (toxi) +// You can download it at http://code.google.com/p/toxiclibs/downloads/list +// +// Please post suggestions and improvements at the flight404 blog. When nicer/faster/better +// practices are suggested, I will incorporate them into the source and repost. I think that +// will be a reasonable system for now. +// +// Future additions will include: +// Rudimentary camera movement +// Magnetic repulsion +// More textures means more iron +// +// UPDATES +// +// February 11th 2008 +// Reorganized some of the OpenGL calls as per Simon Gelfius' suggestion. +// http://www.kinesis.be/ + + +import toxi.geom.*; +import processing.opengl.*; +import javax.media.opengl.*; + +PGraphicsOpenGL pgl; +GL gl; + + +Emitter emitter; +Vec3D gravity; +float floorLevel; + +PImage particleImg; +PImage emitterImg; + +int counter; + + +boolean ALLOWGRAVITY; // add gravity vector? +boolean ALLOWPERLIN; // add perlin noise flow field vector? +boolean ALLOWTRAILS; // render particle trails? +boolean ALLOWFLOOR; // add a floor? + // Turning on all of these options will make things + // slow down. + +void setup(){ + size( 600, 600, OPENGL ); + // Lately I have gotten into the habit of limiting the color range to be + // 0.0 to 1.0. It works this way in OpenGL so I might as well get used to it. + colorMode( RGB, 1.0 ); + + // Turn on 4X antialiasing + hint( ENABLE_OPENGL_4X_SMOOTH ); + + // More OpenGL necessity. + pgl = (PGraphicsOpenGL) g; + gl = pgl.gl; + + // Loads in a particle image from the data folder. Image size should be a power of 2. + particleImg = loadImage( "particle.png" ); + emitterImg = loadImage( "emitter.png" ); + + emitter = new Emitter(); + gravity = new Vec3D( 0, .35, 0 ); // gravity vector + floorLevel = 400; +} + +void draw(){ + background( 0.0 ); + perspective( PI/3.0, (float)width/(float)height, 1, 5000 ); + + // Turns on additive blending so we can draw a bunch of glowing images without + // needing to do any depth testing. + gl.glDepthMask(false); + gl.glEnable( GL.GL_BLEND ); + gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE); + + emitter.exist(); + + // If the mouse button is pressed, then add 10 new particles. + if( mousePressed ){ + if( ALLOWTRAILS && ALLOWFLOOR ){ + emitter.addParticles( 5 ); + } else { + emitter.addParticles( 10 ); + } + } + + counter ++; +} + + +void keyPressed(){ + if( key == 'g' || key == 'G' ) + ALLOWGRAVITY = !ALLOWGRAVITY; + + if( key == 'p' || key == 'P' ) + ALLOWPERLIN = !ALLOWPERLIN; + + if( key == 't' || key == 'T' ) + ALLOWTRAILS = !ALLOWTRAILS; + + if( key == 'f' || key == 'F' ) + ALLOWFLOOR = !ALLOWFLOOR; + +} + + +// This method should be nicer, but it isnt. I use getRads to get a perlin noise +// based angle in radians based on the x and y position of the object asking for it. +// Perlin noise is supposed to give you back a number between 0 and 1, but it wont +// necessarily give you numbers that range from 0 to 1. A usual result is more like +// .25 to .75. +// +// So the point of this method is to try to normalize the values to a +// range of 0 to 1. It's not perfect, and I still get weird results. +// For instance, the mult variable is supposed to be the multiplier for the range. +// So if i wanted a random angle between 0 and TWO_PI, I would set the mult = TWO_PI. +// But when I do that, I find the Perlin noise tends to give me a left-pointing angle. +// To counteract, I end up setting the mult to 10.0 in order to increase the chances +// that I get a nice range from at least 0 to TWO_PI. +float minNoise = 0.499; +float maxNoise = 0.501; +float getRads(float val1, float val2, float mult, float div){ + float rads = noise(val1/div, val2/div, counter/div); + + if (rads < minNoise) minNoise = rads; + if (rads > maxNoise) maxNoise = rads; + + rads -= minNoise; + rads *= 1.0/(maxNoise - minNoise); + + return rads * mult; +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/particle.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/particle.pde new file mode 100644 index 000000000..16441c9c5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/particle.pde @@ -0,0 +1,208 @@ +/* +General Structure notes. + My classes tend to have a similar naming scheme and flow. I start with the 'exist' method. + Exist is what an object needs to do every frame. Usually 'existing' consists of four main things. + 1) Find the velocity. This involves determining what influences there are on the velocity. + 2) Apply the velocity to the location. + 3) Render the object. + 4) Age the object. + + I also use the metaphor of aging and death. When first made, a particle's age will be zero. + Every frame, the age will increment. If the age reaches the lifeSpan (which is a random number + that I set in the constructor), then the boolean ISDEAD is set to true and the arraylist iterator + removes the dead element from the list. + */ + + + +class Particle { + int len; // number of elements in position array + Vec3D[] loc; // array of position vectors + Vec3D startLoc; // just used to make sure every loc[] is initialized to the same position + Vec3D vel; // velocity vector + Vec3D perlin; // perlin noise vector + float radius; // particle's size + float age; // current age of particle + int lifeSpan; // max allowed age of particle + float agePer; // range from 1.0 (birth) to 0.0 (death) + float bounceAge; // amount to age particle when it bounces off floor + boolean ISDEAD; // if age == lifeSpan, make particle die + boolean ISBOUNCING; // if particle hits the floor... + + + Particle( Vec3D _loc, Vec3D _vel ) { + radius = random( 10, 40 ); + len = (int)( radius ); + loc = new Vec3D[ len ]; + + // This confusing-looking line does three things at once. + // First, you make a random vector. + // new Vec3D().randomVector() + // Next, you multiply that vector by a random number from 0.0 to 5.0. + // scaleSelf( 5.0 ); + // Finally, you add this new vector to the original sent vector. + // _loc.add( ); + // This is just a way to make sure all the particles made this frame + // don't all start on the exact same pixel. This staggering will be useful + // when we incorporate magnetic repulsion in a later tutorial. + startLoc = new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random( 5.0 ) ) ) ); + + for( int i=0; i floorLevel ) { + ISBOUNCING = true; + } + else { + ISBOUNCING = false; + } + } + + if( ISBOUNCING ) { + vel.scaleSelf( .75 ); + vel.y *= -.5; + } + } + + void setPosition() { + // Every frame, the current location will be passed on to + // the next element in the location array. Think 'cursor trail effect'. + for( int i=len-1; i>0; i-- ) { + loc[i].set( loc[i-1] ); + } + + // Set the initial location. + // loc[0] represents the current position of the particle. + loc[0].addSelf( vel ); + } + + void render() { + // As the particle ages, it will gain blue but will lose red and green. + color c = color( agePer, agePer*.75, 1.0 - agePer ); + renderImage(particleImg, loc[0], radius * agePer, c, 1.0 ); + } + + void renderTrails() { + float xp, yp, zp; + float xOff, yOff, zOff; + beginShape(QUAD_STRIP); + for ( int i=0; i lifeSpan ) { + ISDEAD = true; + } + else { + // When spawned, the agePer is 1.0. + // When death occurs, the agePer is 0.0. + agePer = 1.0 - age/(float)lifeSpan; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/NOC_gl.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/NOC_gl.pde new file mode 100644 index 000000000..2f91c0f1b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/NOC_gl.pde @@ -0,0 +1,49 @@ + +int squareList; +void initGL(){ + pgl.beginGL(); + squareList = gl.glGenLists(1); + gl.glNewList(squareList, GL.GL_COMPILE); + gl.glBegin(GL.GL_POLYGON); + gl.glTexCoord2f(0, 0); gl.glVertex2f(-.5, -.5); + gl.glTexCoord2f(1, 0); gl.glVertex2f( .5, -.5); + gl.glTexCoord2f(1, 1); gl.glVertex2f( .5, .5); + gl.glTexCoord2f(0, 1); gl.glVertex2f(-.5, .5); + gl.glEnd(); + gl.glEndList(); + pgl.endGL(); +} + +void renderImage( Vec3D _loc, float _diam, color _col, float _alpha ){ + gl.glPushMatrix(); + gl.glTranslatef( _loc.x, -_loc.y, _loc.z ); + pov.glReverseCamera(); + gl.glScalef( _diam, _diam, _diam ); + gl.glColor4f( red(_col), green(_col), blue(_col), _alpha ); + gl.glCallList( squareList ); + gl.glPopMatrix(); +} + +// This will allow you to draw images that are oriented to the floor plane. +void renderImageOnFloor( Vec3D _loc, float _diam, color _col, float _aa ){ + gl.glPushMatrix(); + gl.glTranslatef( _loc.x, -_loc.y, _loc.z ); + gl.glScalef( _diam, _diam, _diam ); + gl.glRotatef( 90, 1.0, 0.0, 0.0 ); + gl.glColor4f( red(_col), green(_col), blue(_col), _aa ); + gl.glCallList( squareList ); + gl.glPopMatrix(); +} + +// This will allow you to specify a rotation for images that are oriented perpendicular to the eyeNormal +// which is the vector pointing from the camera's eye to the camera's point of interest. +void renderImageAndRotate( Vec3D _loc, float _diam, color _col, float _aa, float _rot ){ + gl.glPushMatrix(); + gl.glTranslatef( _loc.x, -_loc.y, _loc.z ); + gl.glRotatef( degrees( _rot ), pov.eyeNormal.x, pov.eyeNormal.y, pov.eyeNormal.z ); + pov.glReverseCamera(); + gl.glScalef( _diam, _diam, _diam ); + gl.glColor4f( red(_col), green(_col), blue(_col), _aa ); + gl.glCallList( squareList ); + gl.glPopMatrix(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/cursor.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/cursor.pde new file mode 100644 index 000000000..ee2909cb9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/cursor.pde @@ -0,0 +1,25 @@ +class Cursor{ + Vec3D loc; + Vec3D vel; + + Cursor(){ + loc = new Vec3D(); + vel = new Vec3D(); + } + + void exist(){ + // 2.35 is an arbitrary number. Ideally, this cursor would function + // properly regardless of the camera's rotation and distance from the object. + // Im not sure how to make that happen... 3D interaction with the cursor has + // been low on my research list. Think of this as a crappy placeholder. + loc.set( ( mouseX - xMid ) * 2.25, ( mouseY - yMid ) * 2.25, 0 ); + } + + void render(){ + pushMatrix(); + translate( loc.x, loc.y, loc.z ); + fill( 1, 0, 0 ); + sphere( 10 ); + popMatrix(); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/emitter.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/emitter.pde new file mode 100644 index 000000000..04eb2045a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/emitter.pde @@ -0,0 +1,182 @@ +class Emitter{ + Vec3D loc; + Vec3D vel; + Vec3D velToMouse; + float radius; + + Texture coronaTex; + Texture emitterTex; + Texture particleTex; + Texture reflectionTex; + + color myColor; + + ArrayList particles; + ArrayList nebulae; + + Emitter( ){ + + try { + coronaTex = TextureIO.newTexture(new File(dataPath("corona.png")), true); + emitterTex = TextureIO.newTexture(new File(dataPath("emitter.png")), true); + particleTex = TextureIO.newTexture(new File(dataPath("particle.png")), true); + reflectionTex = TextureIO.newTexture(new File(dataPath("reflection.png")), true); + } + catch (IOException e) { + println("Texture file is missing"); + exit(); // or handle it some other way + } + + loc = new Vec3D(); + vel = new Vec3D(); + velToMouse = new Vec3D(); + + radius = 100; + + myColor = color( 1, 1, 1 ); + + particles = new ArrayList(); + nebulae = new ArrayList(); + } + + void exist(){ + findVelocity(); + setPosition(); + iterateListExist(); + render(); + + gl.glDisable( GL.GL_TEXTURE_2D ); + + if( ALLOWTRAILS ) + iterateListRenderTrails(); + } + + void findVelocity(){ + Vec3D dirToMouse = new Vec3D( mouse.loc.sub( loc ).scale( .15 ) ); + vel.set( dirToMouse ); + } + + void setPosition(){ + loc.addSelf( vel ); + + if( ALLOWFLOOR ){ + if( loc.y > floorLevel ){ + loc.y = floorLevel; + vel.y = 0; + } + } + } + + void iterateListExist(){ + gl.glEnable( GL.GL_TEXTURE_2D ); + + + int mylength = particles.size(); + for( int i=mylength-1; i>=0; i-- ){ + Particle p = ( Particle )particles.get(i); + if( p.ISSPLIT ) + addParticles( p ); + + if ( !p.ISDEAD ){ + // pgl.bindTexture( images.particle ); + particleTex.bind(); + particleTex.enable(); + p.exist(); + particleTex.disable(); + + } + else { + particles.set( i, particles.get( particles.size() - 1 ) ); + particles.remove( particles.size() - 1 ); + } + } + + if( ALLOWFLOOR ){ + // pgl.bindTexture( images.reflection ); + reflectionTex.bind(); + reflectionTex.enable(); + for( Iterator it = particles.iterator(); it.hasNext(); ){ + Particle p = (Particle) it.next(); + p.renderReflection(); + } + reflectionTex.disable(); + } + + // pgl.bindTexture( images.corona ); + coronaTex.bind(); + coronaTex.enable(); + for( Iterator it = nebulae.iterator(); it.hasNext(); ){ + Nebula n = (Nebula) it.next(); + if( !n.ISDEAD ){ + n.exist(); + } + else { + it.remove(); + } + } + coronaTex.disable(); + } + + + void render(){ + // pgl.bindTexture( images.emitter ); + emitterTex.bind(); + emitterTex.enable(); + renderImage( loc, radius, myColor, 1.0 ); + emitterTex.enable(); + + if( ALLOWNEBULA ){ + nebulae.add( new Nebula( loc, 15.0, true ) ); + nebulae.add( new Nebula( loc, 45.0, true ) ); + } + + + if( ALLOWFLOOR ){ + // pgl.bindTexture( images.reflection ); + reflectionTex.bind(); + reflectionTex.enable(); + renderReflection(); + reflectionTex.disable(); + } + } + + void renderReflection(){ + float altitude = floorLevel - loc.y; + float reflectMaxAltitude = 300.0; + float yPer = 1.0 - altitude/reflectMaxAltitude; + + if( yPer > .05 ) + renderImageOnFloor( new Vec3D( loc.x, floorLevel, loc.z ), radius * 10.0, color( 0.5, 1.0, yPer*.25 ), yPer ); + + if( mousePressed ) + renderImageOnFloor( new Vec3D( loc.x, floorLevel, loc.z ), radius + ( yPer + 1.0 ) * radius * random( 2.0, 3.5 ), color( 1.0, 0, 0 ), yPer ); + } + + void iterateListRenderTrails(){ + for( Iterator it = particles.iterator(); it.hasNext(); ){ + Particle p = (Particle) it.next(); + p.renderTrails(); + } + } + + void addParticles( int _amt ){ + for( int i=0; i<_amt; i++ ){ + particles.add( new Particle( 1, loc, vel ) ); + } + + if( ALLOWNEBULA ){ + nebulae.add( new Nebula( loc, 40.0, false ) ); + nebulae.add( new Nebula( loc, 100.0, false ) ); + } + } + + void addParticles( Particle _p ){ + // play with amt if you want to control how many particles spawn when splitting + int amt = (int)( _p.radius * .15 ); + for( int i=0; i maxNoise) maxNoise = rads; + + rads -= minNoise; + rads *= 1.0/(maxNoise - minNoise); + + return rads * mult; +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/images.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/images.pde new file mode 100644 index 000000000..821c91230 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/images.pde @@ -0,0 +1,13 @@ +class Images{ + PImage particle; + PImage emitter; + PImage corona; + PImage reflection; + + Images(){ + particle = loadImage( "particle.png" ); + emitter = loadImage( "emitter.png" ); + corona = loadImage( "corona.png" ); + reflection = loadImage( "reflection.png" ); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/nebula.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/nebula.pde new file mode 100644 index 000000000..573378708 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/nebula.pde @@ -0,0 +1,56 @@ +class Nebula{ + Vec3D loc; + Vec3D vel; + float radius; + float scaleFac; + float age; + int lifeSpan; + float agePer; + float rot; + color c; + + boolean ISDEAD; + boolean ISGROUNDED; + + Nebula( Vec3D _loc, float _radius, boolean _ISGROUNDED ){ + loc = new Vec3D( _loc ); + vel = new Vec3D( pov.eyeNormal.scale( 2.0 ) ); + radius = random( _radius*.8, _radius*1.75 ); + + scaleFac = random( 1.005, 1.10 ); + age = 0; + lifeSpan = (int)random(10,30); + rot = random( TWO_PI ); + c = color( random(.75, 1.0), random(.5,.75), random(.2,.8) ); + ISGROUNDED = _ISGROUNDED; + + if( ISGROUNDED ){ + scaleFac = random( 1.01, 1.025 ); + vel.y -= random( 1.0 ); + radius *= 2.0; + } + } + + void exist(){ + move(); + render(); + checkAge(); + } + + void move(){ + radius *= scaleFac; + loc.addSelf( vel ); + } + + void render(){ + renderImageAndRotate( loc, radius, c, sin(agePer*PI) * .4, rot ); + } + + void checkAge(){ + age ++; + agePer = 1.0 - age/(float)lifeSpan; + + if (age > lifeSpan) + ISDEAD = true; + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/particle.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/particle.pde new file mode 100644 index 000000000..53cbf839b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/particle.pde @@ -0,0 +1,171 @@ + +class Particle{ + int len; // number of elements in position array + Vec3D[] loc; // array of position vectors + Vec3D startLoc; // just used to make sure every loc[] is initialized to the same position + Vec3D vel; // velocity vector + Vec3D perlin; // perlin noise vector + float radius; // particle's size + float age; // current age of particle + int lifeSpan; // max allowed age of particle + float agePer; // range from 1.0 (birth) to 0.0 (death) + int gen; // number of times particle has been involved in a SPLIT + float bounceAge; // amount to age particle when it bounces off floor + float bounceVel; // speed at impact + boolean ISDEAD; // if age == lifeSpan, make particle die + boolean ISBOUNCING; // if particle hits the floor... + boolean ISSPLIT; // if particle hits the floor with enough speed... + + + Particle( int _gen, Vec3D _loc, Vec3D _vel ){ + gen = _gen; + radius = random( 10 - gen, 50 - ( gen-1)*10 ); + + len = (int)( radius*.5 ); + loc = new Vec3D[ len ]; + startLoc = new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random( 1.0 ) ) ) ); + + for( int i=0; i 1 ){ + vel.addSelf( new Vec3D().randomVector().scaleSelf( random( 7.0 ) ) ); + } else { + vel.addSelf( new Vec3D().randomVector().scaleSelf( random( 10.0 ) ) ); + } + + perlin = new Vec3D(); + + age = 0; + bounceAge = 2; + lifeSpan = (int)( radius ); + } + + void exist(){ + if( ALLOWPERLIN ) + findPerlin(); + + findVelocity(); + setPosition(); + render(); + setAge(); + } + + void findPerlin(){ + float xyRads = getRads( loc[0].x, loc[0].z, 20.0, 50.0 ); + float yRads = getRads( loc[0].x, loc[0].y, 20.0, 50.0 ); + perlin.set( cos(xyRads), -sin(yRads), sin(xyRads) ); + perlin.scaleSelf( .5 ); + } + + void findVelocity(){ + if( ALLOWGRAVITY ) + vel.addSelf( gravity ); + + if( ALLOWPERLIN ) + vel.addSelf( perlin ); + + if( ALLOWFLOOR ){ + if( loc[0].y + vel.y > floorLevel ){ + ISBOUNCING = true; + } else { + ISBOUNCING = false; + } + } + + // if the particle is moving fast enough, when it hits the ground it can + // split into a bunch of smaller particles. + if( ISBOUNCING ){ + bounceVel = vel.magnitude(); + + vel.scaleSelf( .7 ); + vel.y *= -( ( radius/40.0 ) * .5 ); + + if( bounceVel > 15.0 && gen < 4 ) + ISSPLIT = true; + + } else { + ISSPLIT = false; + } + } + + void setPosition(){ + for( int i=len-1; i>0; i-- ){ + loc[i].set( loc[i-1] ); + } + + loc[0].addSelf( vel ); + } + + void render(){ + color c = color( agePer - .5, agePer*.25, 1.5 - agePer ); + renderImage( loc[0], radius * agePer, c, 1.0 ); + + // Rendering two graphics here. Makes the particles more vivid, + // but will hinder the performance. + c = color( 1, agePer, agePer ); + renderImage( loc[0], radius * agePer * .5, c, agePer ); + } + + void renderReflection(){ + float altitude = floorLevel - loc[0].y; + float reflectMaxAltitude = 25.0; + float yPer = ( 1.0 - ( altitude/reflectMaxAltitude ) ) * .5; + + if( yPer > .05 ) + renderImageOnFloor( new Vec3D( loc[0].x, floorLevel, loc[0].z ), radius * agePer * 8.0 * yPer, color( agePer, agePer*.25, 0 ), yPer + random( .2 ) ); + } + + void renderTrails(){ + float xp, yp, zp; + float xOff, yOff, zOff; + + gl.glBegin( GL.GL_QUAD_STRIP ); + + for ( int i=0; i lifeSpan ){ + ISDEAD = true; + } else { + agePer = 1.0 - age/(float)lifeSpan; + } + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/pov.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/pov.pde new file mode 100644 index 000000000..1d5bf01d7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/pov.pde @@ -0,0 +1,62 @@ +// Camera class which uses Kristian Damkjer's OCD library +// http://www.cise.ufl.edu/~kdamkjer/processing/libraries/ocd/ + +class POV{ + PApplet parent; + Camera cam; + + Vec3D eye; + Vec3D center; + + Vec3D eyeNormal; + + boolean ISDRAGGING; + + POV( PApplet _parent ){ + parent = _parent; + cam = new Camera( parent, 0, 100, 1500 ); + + eye = new Vec3D(); + center = new Vec3D(); + eyeNormal = new Vec3D(); + } + + void exist(){ + perspective( PI/3.0, (float)xSize/(float)ySize, .5, 5000 ); + if( ISDRAGGING ){ + cam.circle( radians( ( mouseX - pmouseX ) * .25 ) ); + cam.arc( radians( ( mouseY - pmouseY ) * .25 ) ); + } + + cam.feed(); + setPosition(); + } + + + // Code by JohnG from the Processing forum + // http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1170790832 + // + // Does the camera transformations in reverse to allow for images that always face the camera. + void glReverseCamera(){ + float deltaX = eye.x - center.x; + float deltaY = eye.y - center.y; + float deltaZ = eye.z - center.z; + + float angleZ = atan2( deltaY,deltaX ); + float hyp = sqrt( sq( deltaX ) + sq( deltaY ) ); + float angleY = atan2( hyp,deltaZ ); + + gl.glRotatef( degrees( angleZ ), 0, 0, 1.0 ); + gl.glRotatef( degrees( angleY ), 0, 1.0, 0 ); + } + + + void setPosition(){ + float[] e = cam.position(); + float[] c = cam.target(); + + eye.set( e[0], e[1], e[2] ); + center.set( c[0], c[1], c[2] ); + eyeNormal = eye.sub(center).normalize(); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/sketch.properties b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_GLtexture/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/NOC_gl.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/NOC_gl.pde new file mode 100644 index 000000000..44705cdbd --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/NOC_gl.pde @@ -0,0 +1,31 @@ + +void renderImage(PImage img, Vec3D _loc, float _diam, color _col, float _alpha ) { + pushMatrix(); + translate( _loc.x, _loc.y, _loc.z ); + pov.glReverseCamera(); + tint(red(_col), green(_col), blue(_col), _alpha); + imageMode(CENTER); + image(img,0,0,_diam,_diam); + popMatrix(); +} + +void renderImageOnFloor(PImage img, Vec3D _loc, float _diam, color _col, float _aa ) { + pushMatrix(); + translate( _loc.x, _loc.y, _loc.z ); + rotateX(PI/2); + //pov.glReverseCamera(); + tint(red(_col), green(_col), blue(_col), _aa); + imageMode(CENTER); + image(img,0,0,_diam,_diam); + popMatrix(); +} + +void renderImageAndRotate(PImage img, Vec3D _loc, float _diam, color _col, float _aa, float _rot ) { + pushMatrix(); + translate( _loc.x, _loc.y, _loc.z ); + pov.glReverseCamera(); + tint(red(_col), green(_col), blue(_col), _aa); + imageMode(CENTER); + image(img,0,0,_diam,_diam); + popMatrix(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/cursor.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/cursor.pde new file mode 100644 index 000000000..ee2909cb9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/cursor.pde @@ -0,0 +1,25 @@ +class Cursor{ + Vec3D loc; + Vec3D vel; + + Cursor(){ + loc = new Vec3D(); + vel = new Vec3D(); + } + + void exist(){ + // 2.35 is an arbitrary number. Ideally, this cursor would function + // properly regardless of the camera's rotation and distance from the object. + // Im not sure how to make that happen... 3D interaction with the cursor has + // been low on my research list. Think of this as a crappy placeholder. + loc.set( ( mouseX - xMid ) * 2.25, ( mouseY - yMid ) * 2.25, 0 ); + } + + void render(){ + pushMatrix(); + translate( loc.x, loc.y, loc.z ); + fill( 1, 0, 0 ); + sphere( 10 ); + popMatrix(); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde new file mode 100644 index 000000000..c22f45bdf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde @@ -0,0 +1,149 @@ +class Emitter{ + Vec3D loc; + Vec3D vel; + Vec3D velToMouse; + float radius; + + color myColor; + + ArrayList particles; + ArrayList nebulae; + + Emitter( ){ + loc = new Vec3D(); + vel = new Vec3D(); + velToMouse = new Vec3D(); + + radius = 100; + + myColor = color( 1, 1, 1 ); + + particles = new ArrayList(); + nebulae = new ArrayList(); + } + + void exist(){ + findVelocity(); + setPosition(); + iterateListExist(); + render(); + + gl.glDisable( GL.GL_TEXTURE_2D ); + + if( ALLOWTRAILS ) + iterateListRenderTrails(); + } + + void findVelocity(){ + Vec3D dirToMouse = new Vec3D( mouse.loc.sub( loc ).scale( .15 ) ); + vel.set( dirToMouse ); + } + + void setPosition(){ + loc.addSelf( vel ); + + if( ALLOWFLOOR ){ + if( loc.y > floorLevel ){ + loc.y = floorLevel; + vel.y = 0; + } + } + } + + void iterateListExist(){ + gl.glEnable( GL.GL_TEXTURE_2D ); + + + int mylength = particles.size(); + for( int i=mylength-1; i>=0; i-- ){ + Particle p = ( Particle )particles.get(i); + if( p.ISSPLIT ) + addParticles( p ); + + if ( !p.ISDEAD ){ + //pgl.bindTexture( images.particle ); + p.exist(); + + } else { + particles.set( i, particles.get( particles.size() - 1 ) ); + particles.remove( particles.size() - 1 ); + } + } + + if( ALLOWFLOOR ){ + //pgl.bindTexture( images.reflection ); + for( Iterator it = particles.iterator(); it.hasNext(); ){ + Particle p = (Particle) it.next(); + p.renderReflection(); + } + } + + //pgl.bindTexture( images.corona ); + for( Iterator it = nebulae.iterator(); it.hasNext(); ){ + Nebula n = (Nebula) it.next(); + if( !n.ISDEAD ){ + n.exist(); + } else { + it.remove(); + } + } + } + + + void render(){ + //pgl.bindTexture( images.emitter ); + renderImage( images.emitter,loc, radius, myColor, 1.0 ); + + + if( ALLOWNEBULA ){ + nebulae.add( new Nebula( loc, 15.0, true ) ); + nebulae.add( new Nebula( loc, 45.0, true ) ); + } + + + if( ALLOWFLOOR ){ + //pgl.bindTexture( images.reflection ); + renderReflection(images.reflection); + } + } + + void renderReflection(PImage img){ + float altitude = floorLevel - loc.y; + float reflectMaxAltitude = 300.0; + float yPer = 1.0 - altitude/reflectMaxAltitude; + + if( yPer > .05 ) + renderImageOnFloor(img, new Vec3D( loc.x, floorLevel, loc.z ), radius * 10.0, color( 0.5, 1.0, yPer*.25 ), yPer ); + + if( mousePressed ) + renderImageOnFloor(img, new Vec3D( loc.x, floorLevel, loc.z ), radius + ( yPer + 1.0 ) * radius * random( 2.0, 3.5 ), color( 1.0, 0, 0 ), yPer ); + } + + void iterateListRenderTrails(){ + for( Iterator it = particles.iterator(); it.hasNext(); ){ + Particle p = (Particle) it.next(); + p.renderTrails(); + } + } + + void addParticles( int _amt ){ + for( int i=0; i<_amt; i++ ){ + particles.add( new Particle( 1, loc, vel ) ); + } + + if( ALLOWNEBULA ){ + nebulae.add( new Nebula( loc, 40.0, false ) ); + nebulae.add( new Nebula( loc, 100.0, false ) ); + } + } + + void addParticles( Particle _p ){ + // play with amt if you want to control how many particles spawn when splitting + int amt = (int)( _p.radius * .15 ); + for( int i=0; i maxNoise) maxNoise = rads; + + rads -= minNoise; + rads *= 1.0/(maxNoise - minNoise); + + return rads * mult; +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/images.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/images.pde new file mode 100644 index 000000000..821c91230 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/images.pde @@ -0,0 +1,13 @@ +class Images{ + PImage particle; + PImage emitter; + PImage corona; + PImage reflection; + + Images(){ + particle = loadImage( "particle.png" ); + emitter = loadImage( "emitter.png" ); + corona = loadImage( "corona.png" ); + reflection = loadImage( "reflection.png" ); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/nebula.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/nebula.pde new file mode 100644 index 000000000..3412c110f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/nebula.pde @@ -0,0 +1,56 @@ +class Nebula{ + Vec3D loc; + Vec3D vel; + float radius; + float scaleFac; + float age; + int lifeSpan; + float agePer; + float rot; + color c; + + boolean ISDEAD; + boolean ISGROUNDED; + + Nebula( Vec3D _loc, float _radius, boolean _ISGROUNDED ){ + loc = new Vec3D( _loc ); + vel = new Vec3D( pov.eyeNormal.scale( 2.0 ) ); + radius = random( _radius*.8, _radius*1.75 ); + + scaleFac = random( 1.005, 1.10 ); + age = 0; + lifeSpan = (int)random(10,30); + rot = random( TWO_PI ); + c = color( random(.75, 1.0), random(.5,.75), random(.2,.8) ); + ISGROUNDED = _ISGROUNDED; + + if( ISGROUNDED ){ + scaleFac = random( 1.01, 1.025 ); + vel.y -= random( 1.0 ); + radius *= 2.0; + } + } + + void exist(){ + move(); + render(); + checkAge(); + } + + void move(){ + radius *= scaleFac; + loc.addSelf( vel ); + } + + void render(){ + renderImageAndRotate(images.corona, loc, radius, c, sin(agePer*PI) * .4, rot ); + } + + void checkAge(){ + age ++; + agePer = 1.0 - age/(float)lifeSpan; + + if (age > lifeSpan) + ISDEAD = true; + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/particle.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/particle.pde new file mode 100644 index 000000000..893d3631f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/particle.pde @@ -0,0 +1,172 @@ + +class Particle{ + int len; // number of elements in position array + Vec3D[] loc; // array of position vectors + Vec3D startLoc; // just used to make sure every loc[] is initialized to the same position + Vec3D vel; // velocity vector + Vec3D perlin; // perlin noise vector + float radius; // particle's size + float age; // current age of particle + int lifeSpan; // max allowed age of particle + float agePer; // range from 1.0 (birth) to 0.0 (death) + int gen; // number of times particle has been involved in a SPLIT + float bounceAge; // amount to age particle when it bounces off floor + float bounceVel; // speed at impact + boolean ISDEAD; // if age == lifeSpan, make particle die + boolean ISBOUNCING; // if particle hits the floor... + boolean ISSPLIT; // if particle hits the floor with enough speed... + + + Particle( int _gen, Vec3D _loc, Vec3D _vel ){ + gen = _gen; + radius = random( 10 - gen, 50 - ( gen-1)*10 ); + + len = (int)( radius*.5 ); + loc = new Vec3D[ len ]; + startLoc = new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random( 1.0 ) ) ) ); + + for( int i=0; i 1 ){ + vel.addSelf( new Vec3D().randomVector().scaleSelf( random( 7.0 ) ) ); + } else { + vel.addSelf( new Vec3D().randomVector().scaleSelf( random( 10.0 ) ) ); + } + + perlin = new Vec3D(); + + age = 0; + bounceAge = 2; + lifeSpan = (int)( radius ); + } + + void exist(){ + if( ALLOWPERLIN ) + findPerlin(); + + findVelocity(); + setPosition(); + render(); + setAge(); + } + + void findPerlin(){ + float xyRads = getRads( loc[0].x, loc[0].z, 20.0, 50.0 ); + float yRads = getRads( loc[0].x, loc[0].y, 20.0, 50.0 ); + perlin.set( cos(xyRads), -sin(yRads), sin(xyRads) ); + perlin.scaleSelf( .5 ); + } + + void findVelocity(){ + if( ALLOWGRAVITY ) + vel.addSelf( gravity ); + + if( ALLOWPERLIN ) + vel.addSelf( perlin ); + + if( ALLOWFLOOR ){ + if( loc[0].y + vel.y > floorLevel ){ + ISBOUNCING = true; + } else { + ISBOUNCING = false; + } + } + + // if the particle is moving fast enough, when it hits the ground it can + // split into a bunch of smaller particles. + if( ISBOUNCING ){ + bounceVel = vel.magnitude(); + + vel.scaleSelf( .7 ); + vel.y *= -( ( radius/40.0 ) * .5 ); + + if( bounceVel > 15.0 && gen < 4 ) + ISSPLIT = true; + + } else { + ISSPLIT = false; + } + } + + void setPosition(){ + for( int i=len-1; i>0; i-- ){ + loc[i].set( loc[i-1] ); + } + + loc[0].addSelf( vel ); + } + + void render(){ + color c = color( agePer - .5, agePer*.25, 1.5 - agePer ); + renderImage(images.particle, loc[0], radius * agePer, c, 1.0 ); + + // Rendering two graphics here. Makes the particles more vivid, + // but will hinder the performance. + c = color( 1, agePer, agePer ); + renderImage(images.particle, loc[0], radius * agePer * .5, c, agePer ); + } + + void renderReflection(){ + float altitude = floorLevel - loc[0].y; + float reflectMaxAltitude = 25.0; + float yPer = ( 1.0 - ( altitude/reflectMaxAltitude ) ) * .5; + + if( yPer > .05 ) + renderImageOnFloor(images.particle, new Vec3D( loc[0].x, floorLevel, loc[0].z ), radius * agePer * 8.0 * yPer, color( agePer, agePer*.25, 0 ), yPer + random( .2 ) ); + } + + void renderTrails(){ + float xp, yp, zp; + float xOff, yOff, zOff; + + beginShape(QUAD_STRIP); + + for ( int i=0; i lifeSpan ){ + ISDEAD = true; + } else { + agePer = 1.0 - age/(float)lifeSpan; + } + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/pov.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/pov.pde new file mode 100644 index 000000000..cc41c1360 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/pov.pde @@ -0,0 +1,64 @@ +// Camera class which uses Kristian Damkjer's OCD library +// http://www.cise.ufl.edu/~kdamkjer/processing/libraries/ocd/ + +class POV{ + PApplet parent; + Camera cam; + + Vec3D eye; + Vec3D center; + + Vec3D eyeNormal; + + boolean ISDRAGGING; + + POV( PApplet _parent ){ + parent = _parent; + cam = new Camera( parent, 0, -100, 1500 ); + + eye = new Vec3D(); + center = new Vec3D(); + eyeNormal = new Vec3D(); + } + + void exist(){ + perspective( PI/3.0, (float)xSize/(float)ySize, .5, 5000 ); + if( ISDRAGGING ){ + cam.circle( radians( ( mouseX - pmouseX ) * .25 ) ); + cam.arc( radians( ( mouseY - pmouseY ) * .25 ) ); + } + + cam.feed(); + setPosition(); + } + + + // Code by JohnG from the Processing forum + // http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1170790832 + // + // Does the camera transformations in reverse to allow for images that always face the camera. + void glReverseCamera(){ + float deltaX = eye.x - center.x; + float deltaY = eye.y - center.y; + float deltaZ = eye.z - center.z; + + float angleZ = atan2( deltaY,deltaX ); + float hyp = sqrt( sq( deltaX ) + sq( deltaY ) ); + float angleY = atan2( hyp,deltaZ ); + + rotateZ(angleZ); + rotateY(angleY); + //gl.glRotatef( degrees( angleZ ), 0, 0, 1.0 ); + //gl.glRotatef( degrees( angleY ), 0, 1.0, 0 ); + } + + + void setPosition(){ + float[] e = cam.position(); + float[] c = cam.target(); + + eye.set( e[0], e[1], e[2] ); + center.set( c[0], c[1], c[2] ); + eyeNormal = eye.sub(center).normalize(); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Circle.pde b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Circle.pde new file mode 100644 index 000000000..f45630f37 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Circle.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Circle extends Shape { + + // Inherits all instance variables from parent + adding one + color c; + + Circle(float x_, float y_, float r_, color c_) { + super(x_,y_,r_); // Call the parent constructor + c = c_; // Also deal with this new instance variable + } + + // Call the parent jiggle, but do some more stuff too + void jiggle() { + super.jiggle(); + // The Circle jiggles its size as well as its x,y location. + r += random(-1,1); + r = constrain(r,0,100); + } + + // The changeColor() function is unique to the Circle class. + void changeColor() { + c = color(random(255)); + } + + void display() { + ellipseMode(CENTER); + fill(c); + stroke(0); + ellipse(x,y,r,r); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Shape.pde b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Shape.pde new file mode 100644 index 000000000..a4d8a723a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Shape.pde @@ -0,0 +1,28 @@ +// Learning Processing +// Daniel Shiffman +// http://www.learningprocessing.com + +// Example 22-1: Inheritance + +class Shape { + float x; + float y; + float r; + + Shape(float x_, float y_, float r_) { + x = x_; + y = y_; + r = r_; + } + + void jiggle() { + x += random(-1,1); + y += random(-1,1); + } + + // A generic shape does not really know how to be displayed. + // This will be overridden in the child classes. + void display() { + point(x,y); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Square.pde b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Square.pde new file mode 100644 index 000000000..72831cabe --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/Square.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Square extends Shape { + // Variables are inherited from the parent. + // We could also add variables unique to the Square class if we so desire + + Square(float x_, float y_, float r_) { + // If the parent constructor takes arguments then super() needs to pass in those arguments. + super(x_,y_,r_); + } + + // Inherits jiggle() from parent + + // The square overrides its parent for display. + void display() { + rectMode(CENTER); + fill(175); + stroke(0); + rect(x,y,r,r); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/simpleInheritance.pde b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/simpleInheritance.pde new file mode 100644 index 000000000..d76add5e3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simpleInheritance/simpleInheritance.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Object oriented programming allows us to defi ne classes in terms of other classes. +// A class can be a subclass (aka " child " ) of a super class (aka "parent"). +// This is a simple example demonstrating this concept, known as "inheritance." + +Square s; +Circle c; + +void setup() { + size(200,200); + // A square and circle + s = new Square(75,75,10); + c = new Circle(125,125,20,color(175)); +} + +void draw() { + background(255); + c.jiggle(); + s.jiggle(); + c.display(); + s.display(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Circle.pde b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Circle.pde new file mode 100644 index 000000000..f45630f37 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Circle.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Circle extends Shape { + + // Inherits all instance variables from parent + adding one + color c; + + Circle(float x_, float y_, float r_, color c_) { + super(x_,y_,r_); // Call the parent constructor + c = c_; // Also deal with this new instance variable + } + + // Call the parent jiggle, but do some more stuff too + void jiggle() { + super.jiggle(); + // The Circle jiggles its size as well as its x,y location. + r += random(-1,1); + r = constrain(r,0,100); + } + + // The changeColor() function is unique to the Circle class. + void changeColor() { + c = color(random(255)); + } + + void display() { + ellipseMode(CENTER); + fill(c); + stroke(0); + ellipse(x,y,r,r); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Shape.pde b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Shape.pde new file mode 100644 index 000000000..671b45edf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Shape.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Shape { + float x; + float y; + float r; + + Shape(float x_, float y_, float r_) { + x = x_; + y = y_; + r = r_; + } + + void jiggle() { + x += random(-1,1); + y += random(-1,1); + } + + // A generic shape does not really know how to be displayed. + // This will be overridden in the child classes. + void display() { + point(x,y); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Square.pde b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Square.pde new file mode 100644 index 000000000..72831cabe --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/Square.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Square extends Shape { + // Variables are inherited from the parent. + // We could also add variables unique to the Square class if we so desire + + Square(float x_, float y_, float r_) { + // If the parent constructor takes arguments then super() needs to pass in those arguments. + super(x_,y_,r_); + } + + // Inherits jiggle() from parent + + // The square overrides its parent for display. + void display() { + rectMode(CENTER); + fill(175); + stroke(0); + rect(x,y,r,r); + } +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/simplePolymorphism.pde b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/simplePolymorphism.pde new file mode 100644 index 000000000..b7e667acf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/simplePolymorphism/simplePolymorphism.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// One array of Shapes +Shape[] shapes = new Shape[30]; + +void setup() { + size(200,200); + for (int i = 0; i < shapes.length; i++ ) { + int r = int(random(2)); + // Randomly put either circles or squares in our array + if (r == 0) { + shapes[i] = new Circle(100,100,10,color(random(255),100)); + } else { + shapes[i] = new Square(100,100,10); + } + } +} + +void draw() { + background(255); + // Jiggle and display all shapes + for (int i = 0; i < shapes.length; i++ ) { + shapes[i].jiggle(); + shapes[i].display(); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/CollisionsEqualMass.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/CollisionsEqualMass.pde new file mode 100644 index 000000000..bbb54b071 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/CollisionsEqualMass.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Collisions -- Elastic, Equal Mass, Two objects only + +// Based off of Chapter 9: Resolving Collisions +// Mathematics and Physics for Programmers by Danny Kodicek + +// A Thing class for idealized collisions + +Mover a; +Mover b; + +boolean showVectors = true; + +void setup() { + size(200,200); + a = new Mover(new PVector(random(5),random(-5,5)),new PVector(10,10)); + b = new Mover(new PVector(-2,1),new PVector(150,150)); +} + +void draw() { + background(255); + a.go(); + b.go(); + + // Note this function will ONLY WORK with two objects + // Needs to be revised in the case of an array of objects + a.collideEqualMass(b); +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/Mover.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/Mover.pde new file mode 100644 index 000000000..3281a9850 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/Mover.pde @@ -0,0 +1,100 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Collisions + +class Mover { + + PVector loc; + PVector vel; + float bounce = 1.0; + float r = 20; + boolean colliding = false; + + Mover(PVector v, PVector l) { + vel = v.get(); + loc = l.get(); + } + + // Main method to operate object + void go() { + update(); + borders(); + display(); + } + + // Method to update location + void update() { + loc.add(vel); + } + + // Check for bouncing off borders + void borders() { + if (loc.y > height) { + vel.y *= -bounce; + loc.y = height; + } + else if (loc.y < 0) { + vel.y *= -bounce; + loc.y = 0; + } + if (loc.x > width) { + vel.x *= -bounce; + loc.x = width; + } + else if (loc.x < 0) { + vel.x *= -bounce; + loc.x = 0; + } + } + + // Method to display + void display() { + ellipseMode(CENTER); + stroke(0); + fill(175,200); + ellipse(loc.x,loc.y,r*2,r*2); + if (showVectors) { + drawVector(vel,loc,10); + } + } + + void collideEqualMass(Mover other) { + float d = PVector.dist(loc,other.loc); + float sumR = r + other.r; + // Are they colliding? + if (!colliding && d < sumR) { + // Yes, make new velocities! + colliding = true; + // Direction of one object another + PVector n = PVector.sub(other.loc,loc); + n.normalize(); + + // Difference of velocities so that we think of one object as stationary + PVector u = PVector.sub(vel,other.vel); + + // Separate out components -- one in direction of normal + PVector un = componentVector(u,n); + // Other component + u.sub(un); + // These are the new velocities plus the velocity of the object we consider as stastionary + vel = PVector.add(u,other.vel); + other.vel = PVector.add(un,other.vel); + } + else if (d > sumR) { + colliding = false; + } + } +} + +PVector componentVector (PVector vector, PVector directionVector) { + //--! ARGUMENTS: vector, directionVector (2D vectors) + //--! RETURNS: the component vector of vector in the direction directionVector + //-- normalize directionVector + directionVector.normalize(); + directionVector.mult(vector.dot(directionVector)); + return directionVector; +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde new file mode 100644 index 000000000..141c06960 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +void drawVector(PVector v, PVector loc, float scayl) { + pushMatrix(); + float arrowsize = 4; + // Translate to location to render vector + translate(loc.x,loc.y); + stroke(0); + // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate + rotate(v.heading2D()); + // 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(); +} + + +void mousePressed() { + showVectors = !showVectors; +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Blob.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Blob.pde new file mode 100644 index 000000000..d2cd65eb1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Blob.pde @@ -0,0 +1,195 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A blob skeleton +// Could be used to create blobbly characters a la Nokia Friends +// http://postspectacular.com/work/nokia/friends/start + +class Skeleton { + + // A list to keep track of all the bodies and joints + ArrayList bodies; + ArrayList joints; + + float bodyRadius; // The radius of each body that makes up the skeleton + float radius; // The radius of the entire blob + float totalPoints; // How many points make up the blob + + + // We should modify this constructor to receive arguments + // So that we can make many different types of blobs + Skeleton() { + + // Create the empty ArrayLists + bodies = new ArrayList(); + joints = new ArrayList(); + + // Where and how big is the blob + Vec2 center = new Vec2(width/2, height/2); + radius = 100; + totalPoints = 32; + bodyRadius = 10; + + // Initialize all the points in a circle + for (int i = 0; i < totalPoints; i++) { + // Look polar to cartesian coordinate transformation! + float theta = PApplet.map(i, 0, totalPoints, 0, TWO_PI); + float x = center.x + radius * sin(theta); + float y = center.y + radius * cos(theta); + + // Make each individual body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + + bd.fixedRotation = true; // no rotation! + bd.position.set(box2d.coordPixelsToWorld(x, y)); + Body body = box2d.createBody(bd); + + // The body is a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(bodyRadius); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + fd.density = 1; + fd.friction = 0.5; + fd.restitution = 0.3; + + // Finalize the body + body.createFixture(fd); + + // Store our own copy for later rendering + bodies.add(body); + } + + // Now connect the outline of the shape all with joints + for (int i = 0; i < bodies.size(); i++) { + DistanceJointDef djd = new DistanceJointDef(); + Body a = bodies.get(i); + int next = i+1; + if (i == bodies.size()-1) { + next = 0; + } + Body b = bodies.get(next); + // Connection between previous particle and this one + djd.bodyA = a; + djd.bodyB = b; + // Equilibrium length is distance between these bodies + Vec2 apos = a.getWorldCenter(); + Vec2 bpos = b.getWorldCenter(); + float d = dist(apos.x, apos.y, bpos.x, bpos.y); + djd.length = d; + // These properties affect how springy the joint is + djd.frequencyHz = 10; + djd.dampingRatio = 0.9; + + // Make the joint. + DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd); + joints.add(dj); + } + + + // Make some joints that cross the center of the blob between bodies + for (int i = 0; i < bodies.size(); i++) { + for (int j = i+2; j < bodies.size(); j+=4) { + DistanceJointDef djd = new DistanceJointDef(); + Body a = bodies.get(i); + Body b = bodies.get(j); + // Connection between two bides + djd.bodyA = a; + djd.bodyB = b; + // Equilibrium length is distance between these bodies + Vec2 apos = a.getWorldCenter(); + Vec2 bpos = b.getWorldCenter(); + float d = dist(apos.x, apos.y, bpos.x, bpos.y); + + djd.length = d; + // These properties affect how springy the joint is + djd.frequencyHz = 3; + djd.dampingRatio = 0.1; + + // Make the joint. + DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd); + joints.add(dj); + } + } + } + + + // Draw the skeleton as circles for bodies and lines for joints + void displaySkeleton() { + // Draw the outline + stroke(0); + strokeWeight(1); + for (Joint j: joints) { + Body a = j.getBodyA(); + Body b = j.getBodyB(); + Vec2 posa = box2d.getBodyPixelCoord(a); + Vec2 posb = box2d.getBodyPixelCoord(b); + line(posa.x, posa.y, posb.x, posb.y); + } + + // Draw the individual circles + for (Body b: bodies) { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(b); + // Get its angle of rotation + float a = b.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(175); + stroke(0); + strokeWeight(1); + ellipse(0, 0, bodyRadius*2, bodyRadius*2); + popMatrix(); + } + } + + + // Draw it as a creature + void displayCreature() { + // Let's compute the center! + Vec2 center = new Vec2(0, 0); + + // Make a curvy polygon + beginShape(); + stroke(175); + strokeWeight(bodyRadius*2); + fill(175); + for (Body b: bodies) { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(b); + curveVertex(pos.x, pos.y); + center.addLocal(pos); + } + endShape(CLOSE); + // Center is average of all points + center.mulLocal(1.0/bodies.size()); + + // Find angle between center and side body + Vec2 pos = box2d.getBodyPixelCoord(bodies.get(0)); + float dx = pos.x - center.x; + float dy = pos.y - center.y; + float angle = atan2(dy, dx)-PI/2; + + // Draw eyes and mouth relative to center + pushMatrix(); + strokeWeight(1); + stroke(0); + translate(center.x, center.y); + rotate(angle); + fill(0); + ellipse(-25, -50, 16, 16); + ellipse(25, -50, 16, 16); + line(-50, 50, 50, 50); + popMatrix(); + } + + Body getFirstBody() { + return bodies.get(0); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/BlobSkeleton.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/BlobSkeleton.pde new file mode 100644 index 000000000..c9f4ee0a0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/BlobSkeleton.pde @@ -0,0 +1,109 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A blob skeleton +// Could be used to create blobbly characters a la Nokia Friends +// http://postspectacular.com/work/nokia/friends/start + +import pbox2d.*; + +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.joints.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; + +// Our "blob" object +Skeleton blob; + +// Just a single box this time +Box box; +// The Spring that will attach to the box from the mouse +Spring spring; + +// Draw creature design or skeleton? +boolean skeleton; + +void setup() { + size(640, 360); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Add some boundaries + boundaries = new ArrayList(); + boundaries.add(new Boundary(width/2, height-5, width, 10)); + boundaries.add(new Boundary(width/2, 5, width, 10)); + boundaries.add(new Boundary(width-5, height/2, 10, height)); + boundaries.add(new Boundary(5, height/2, 10, height)); + + // Make a new blob + blob = new Skeleton(); + + // Make the box + box = new Box(width/2, 100); + + // Make the spring (it doesn't really get initialized until the mouse is clicked) + spring = new Spring(); +} + +// When the mouse is released we're done with the spring +void mouseReleased() { + spring.destroy(); +} + +// When the mouse is pressed we. . . +void mousePressed() { + // Check to see if the mouse was clicked on the box + if (box.contains(mouseX, mouseY)) { + // And if so, bind the mouse location to the box with a spring + spring.bind(mouseX, mouseY, box); + } +} + +void draw() { + background(255); + + // We must always step through time! + + box2d.step(); + + + // Show the blob! + if (skeleton) { + blob.displaySkeleton(); + } + else { + blob.displayCreature(); + } + + // Show the boundaries! + for (Boundary wall: boundaries) { + wall.display(); + } + + // Always alert the spring to the new mouse location + spring.update(mouseX, mouseY); + + // Draw the box + box.display(); + // Draw the spring (it only appears when active) + spring.display(); + + fill(0); + text("Space bar to toggle creature/skeleton.\nClick and drag the box.", 20, height-30); +} + + +void keyPressed() { + if (key == ' ') { + skeleton = !skeleton; + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Boundary.pde new file mode 100644 index 000000000..9a17026a1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Boundary.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Box.pde new file mode 100644 index 000000000..16a2c18b2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Box.pde @@ -0,0 +1,85 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x_, float y_) { + float x = x_; + float y = y_; + w = 50; + h = 50; + // Add the box to the box2d world + makeBody(new Vec2(x, y), w, h); + body.setUserData(this); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + boolean contains(float x, float y) { + Vec2 worldPoint = box2d.coordPixelsToWorld(x, y); + Fixture f = body.getFixtureList(); + boolean inside = f.testPoint(worldPoint); + return inside; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(50); + stroke(0); + rect(0, 0, w, h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + //body.setMassFromShapes(); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Spring.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Spring.pde new file mode 100644 index 000000000..02fd1612b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/BlobSkeleton/Spring.pde @@ -0,0 +1,75 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Class to describe the spring joint (displayed as a line) + +class Spring { + + // This is the box2d object we need to create + MouseJoint mouseJoint; + + Spring() { + // At first it doesn't exist + mouseJoint = null; + } + + // If it exists we set its target to the mouse location + void update(float x, float y) { + if (mouseJoint != null) { + // Always convert to world coordinates! + Vec2 mouseWorld = box2d.coordPixelsToWorld(x,y); + mouseJoint.setTarget(mouseWorld); + } + } + + void display() { + if (mouseJoint != null) { + // We can get the two anchor points + Vec2 v1 = new Vec2(0,0); + mouseJoint.getAnchorA(v1); + Vec2 v2 = new Vec2(0,0); + mouseJoint.getAnchorB(v2); + // Convert them to screen coordinates + v1 = box2d.coordWorldToPixels(v1); + v2 = box2d.coordWorldToPixels(v2); + // And just draw a line + stroke(0); + strokeWeight(1); + line(v1.x,v1.y,v2.x,v2.y); + } + } + + + // This is the key function where + // we attach the spring to an x,y location + // and the Box object's location + void bind(float x, float y, Box box) { + // Define the joint + MouseJointDef md = new MouseJointDef(); + // Body A is just a fake ground body for simplicity (there isn't anything at the mouse) + md.bodyA = box2d.getGroundBody(); + // Body 2 is the box's boxy + md.bodyB = box.body; + // Get the mouse location in world coordinates + Vec2 mp = box2d.coordPixelsToWorld(x,y); + // And that's the target + md.target.set(mp); + // Some stuff about how strong and bouncy the spring should be + md.maxForce = 1000.0 * box.body.m_mass; + md.frequencyHz = 5.0; + md.dampingRatio = 0.9; + + // Make the joint! + mouseJoint = (MouseJoint) box2d.world.createJoint(md); + } + + void destroy() { + // We can get rid of the joint when the mouse is released + if (mouseJoint != null) { + box2d.world.destroyJoint(mouseJoint); + mouseJoint = null; + } + } + +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Blob.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Blob.pde new file mode 100644 index 000000000..1919d79e2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Blob.pde @@ -0,0 +1,118 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// PBox2D example + +// A blob skeleton +// Could be used to create blobbly characters a la Nokia Friends +// http://postspectacular.com/work/nokia/friends/start + +class Blob { + + // A list to keep track of all the points in our blob + ArrayList skeleton; + + float bodyRadius; // The radius of each body that makes up the skeleton + float radius; // The radius of the entire blob + float totalPoints; // How many points make up the blob + + + // We should modify this constructor to receive arguments + // So that we can make many different types of blobs + Blob() { + + // Create the empty + skeleton = new ArrayList(); + + // Let's make a volume of joints! + ConstantVolumeJointDef cvjd = new ConstantVolumeJointDef(); + + // Where and how big is the blob + Vec2 center = new Vec2(width/2, height/2); + radius = 100; + totalPoints = 20; + bodyRadius = 12; + + + // Initialize all the points + for (int i = 0; i < totalPoints; i++) { + // Look polar to cartesian coordinate transformation! + float theta = PApplet.map(i, 0, totalPoints, 0, TWO_PI); + float x = center.x + radius * sin(theta); + float y = center.y + radius * cos(theta); + + // Make each individual body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + + bd.fixedRotation = true; // no rotation! + bd.position.set(box2d.coordPixelsToWorld(x, y)); + Body body = box2d.createBody(bd); + + // The body is a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(bodyRadius); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + + // For filtering out collisions + //fd.filter.groupIndex = -2; + + // Parameters that affect physics + fd.density = 1; + + // Finalize the body + body.createFixture(fd); + // Add it to the volume + cvjd.addBody(body); + + + // Store our own copy for later rendering + skeleton.add(body); + } + + // These parameters control how stiff vs. jiggly the blob is + cvjd.frequencyHz = 10.0f; + cvjd.dampingRatio = 1.0f; + + // Put the joint thing in our world! + box2d.world.createJoint(cvjd); + } + + + // Time to draw the blob! + // Can you make it a cute character, a la http://postspectacular.com/work/nokia/friends/start + void display() { + + // Draw the outline + beginShape(); + noFill(); + stroke(0); + strokeWeight(1); + for (Body b: skeleton) { + Vec2 pos = box2d.getBodyPixelCoord(b); + vertex(pos.x, pos.y); + } + endShape(CLOSE); + + // Draw the individual circles + for (Body b: skeleton) { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(b); + // Get its angle of rotation + float a = b.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(175); + stroke(0); + strokeWeight(1); + ellipse(0, 0, bodyRadius*2, bodyRadius*2); + popMatrix(); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Blobby.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Blobby.pde new file mode 100644 index 000000000..d5df8e919 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Blobby.pde @@ -0,0 +1,63 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A blob skeleton +// Could be used to create blobbly characters a la Nokia Friends +// http://postspectacular.com/work/nokia/friends/start + +// This seems to be broken with the Box2D 2.1.2 version I'm using + +import pbox2d.*; + +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.joints.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; + +// Our "blob" object +Blob blob; + + void setup() { + size(400,300); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Add some boundaries + boundaries = new ArrayList(); + boundaries.add(new Boundary(width/2,height-5,width,10)); + boundaries.add(new Boundary(width/2,5,width,10)); + boundaries.add(new Boundary(width-5,height/2,10,height)); + boundaries.add(new Boundary(5,height/2,10,height)); + + // Make a new blob + blob = new Blob(); +} + + void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // Show the blob! + blob.display(); + + // Show the boundaries! + for (Boundary wall: boundaries) { + wall.display(); + } + + +} + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Boundary.pde new file mode 100644 index 000000000..9a17026a1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Blobby/Boundary.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/Boundary.pde new file mode 100644 index 000000000..ff6226252 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/Boundary.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + + b.setUserData(this); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/CollisionListeningDeletionExercise.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/CollisionListeningDeletionExercise.pde new file mode 100644 index 000000000..37c6ee51d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/CollisionListeningDeletionExercise.pde @@ -0,0 +1,118 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with our own motion (by attaching a MouseJoint) +// Also demonstrates how to know which object was hit + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +Boundary wall; + +void setup() { + size(400, 300); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Turn on collision listening! + box2d.listenForCollisions(); + + // Create the empty list + particles = new ArrayList(); + + wall = new Boundary(width/2, height-5, width, 10); +} + +void draw() { + background(255); + + if (random(1) < 0.1) { + float sz = random(4, 8); + particles.add(new Particle(random(width), 20, sz)); + } + + + // We must always step through time! + box2d.step(); + + // Look at all particles + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.display(); + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + if (p.done()) { + particles.remove(i); + } + } + + wall.display(); +} + + +// Collision event functions! +void beginContact(Contact cp) { + // Get both shapes + Fixture f1 = cp.getFixtureA(); + Fixture f2 = cp.getFixtureB(); + // Get both bodies + Body b1 = f1.getBody(); + Body b2 = f2.getBody(); + + // Get our objects that reference these bodies + Object o1 = b1.getUserData(); + Object o2 = b2.getUserData(); + + if (o1.getClass() == Particle.class && o2.getClass() == Particle.class) { + Particle p1 = (Particle) o1; + p1.delete(); + Particle p2 = (Particle) o2; + p2.delete(); + } + + if (o1.getClass() == Boundary.class) { + Particle p = (Particle) o2; + p.change(); + } + if (o2.getClass() == Boundary.class) { + Particle p = (Particle) o1; + p.change(); + } + + +} + +// Objects stop touching each other +void endContact(Contact cp) { +} + + + + + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/Particle.pde new file mode 100644 index 000000000..5a4017c84 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionListeningDeletionExercise/Particle.pde @@ -0,0 +1,95 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + color col; + + boolean delete = false; + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x, y, r); + body.setUserData(this); + col = color(175); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + void delete() { + delete = true; + } + + // Change color when hit + void change() { + col = color(255, 0, 0); + } + + // Is the particle ready for deletion? + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2 || delete) { + killBody(); + return true; + } + return false; + } + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(col); + stroke(0); + strokeWeight(1); + ellipse(0, 0, r*2, r*2); + // Let's add a line so we can see the rotation + line(0, 0, r, 0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x, y); + bd.type = BodyType.DYNAMIC; + body = box2d.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + body.setAngularVelocity(random(-10, 10)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Box.pde new file mode 100644 index 000000000..1fb05d066 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Box.pde @@ -0,0 +1,85 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x_, float y_) { + float x = x_; + float y = y_; + w = 24; + h = 24; + // Add the box to the box2d world + makeBody(new Vec2(x, y), w, h); + body.setUserData(this); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + boolean contains(float x, float y) { + Vec2 worldPoint = box2d.coordPixelsToWorld(x, y); + Fixture f = body.getFixtureList(); + boolean inside = f.testPoint(worldPoint); + return inside; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(175); + stroke(0); + rect(0, 0, w, h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + //body.setMassFromShapes(); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/CollisionsAndControl.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/CollisionsAndControl.pde new file mode 100644 index 000000000..7ddaa71b6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/CollisionsAndControl.pde @@ -0,0 +1,150 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with our own motion (by attaching a MouseJoint) +// Also demonstrates how to know which object was hit + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// Just a single box this time +Box box; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +// The Spring that will attach to the box from the mouse +Spring spring; + +// Perlin noise values +float xoff = 0; +float yoff = 1000; + + +void setup() { + size(400,300); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Turn on collision listening! + box2d.listenForCollisions(); + + // Make the box + box = new Box(width/2,height/2); + + // Make the spring (it doesn't really get initialized until the mouse is clicked) + spring = new Spring(); + spring.bind(width/2,height/2,box); + + // Create the empty list + particles = new ArrayList(); + + +} + +void draw() { + background(255); + + if (random(1) < 0.2) { + float sz = random(4,8); + particles.add(new Particle(width/2,-20,sz)); + } + + + // We must always step through time! + box2d.step(); + + // Make an x,y coordinate out of perlin noise + float x = noise(xoff)*width; + float y = noise(yoff)*height; + xoff += 0.01; + yoff += 0.01; + + // This is tempting but will not work! + // box.body.setXForm(box2d.screenToWorld(x,y),0); + + // Instead update the spring which pulls the mouse along + if (mousePressed) { + spring.update(mouseX,mouseY); + spring.display(); + } else { + spring.update(x,y); + } + box.body.setAngularVelocity(0); + + // Look at all particles + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.display(); + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + if (p.done()) { + particles.remove(i); + } + } + + // Draw the box + box.display(); + + // Draw the spring + // spring.display(); +} + + +// Collision event functions! +void beginContact(Contact cp) { + // Get both fixtures + Fixture f1 = cp.getFixtureA(); + Fixture f2 = cp.getFixtureB(); + // Get both bodies + Body b1 = f1.getBody(); + Body b2 = f2.getBody(); + // Get our objects that reference these bodies + Object o1 = b1.getUserData(); + Object o2 = b2.getUserData(); + + // If object 1 is a Box, then object 2 must be a particle + // Note we are ignoring particle on particle collisions + if (o1.getClass() == Box.class) { + Particle p = (Particle) o2; + p.change(); + } + // If object 2 is a Box, then object 1 must be a particle + else if (o2.getClass() == Box.class) { + Particle p = (Particle) o1; + p.change(); + } +} + + +// Objects stop touching each other +void endContact(Contact cp) { +} + + + + + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Particle.pde new file mode 100644 index 000000000..50be57e86 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Particle.pde @@ -0,0 +1,91 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + color col; + + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x, y, r); + body.setUserData(this); + col = color(175); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Change color when hit + void change() { + col = color(255, 0, 0); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(col); + stroke(0); + strokeWeight(1); + ellipse(0, 0, r*2, r*2); + // Let's add a line so we can see the rotation + line(0, 0, r, 0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x, y); + bd.type = BodyType.DYNAMIC; + body = box2d.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + body.setAngularVelocity(random(-10, 10)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Spring.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Spring.pde new file mode 100644 index 000000000..cca069b90 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControl/Spring.pde @@ -0,0 +1,81 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Class to describe the spring joint (displayed as a line) + +class Spring { + + // This is the box2d object we need to create + MouseJoint mouseJoint; + + Spring() { + // At first it doesn't exist + mouseJoint = null; + } + + // If it exists we set its target to the mouse location + void update(float x, float y) { + if (mouseJoint != null) { + // Always convert to world coordinates! + Vec2 mouseWorld = box2d.coordPixelsToWorld(x,y); + mouseJoint.setTarget(mouseWorld); + } + } + + void display() { + if (mouseJoint != null) { + // We can get the two anchor points + Vec2 v1 = new Vec2(0,0); + mouseJoint.getAnchorA(v1); + Vec2 v2 = new Vec2(0,0); + mouseJoint.getAnchorB(v2); + // Convert them to screen coordinates + v1 = box2d.coordWorldToPixels(v1); + v2 = box2d.coordWorldToPixels(v2); + // And just draw a line + stroke(0); + strokeWeight(1); + line(v1.x,v1.y,v2.x,v2.y); + } + } + + + // This is the key function where + // we attach the spring to an x,y location + // and the Box object's location + void bind(float x, float y, Box box) { + // Define the joint + MouseJointDef md = new MouseJointDef(); + + // Body A is just a fake ground body for simplicity (there isn't anything at the mouse) + md.bodyA = box2d.getGroundBody(); + // Body 2 is the box's boxy + md.bodyB = box.body; + // Get the mouse location in world coordinates + Vec2 mp = box2d.coordPixelsToWorld(x,y); + // And that's the target + md.target.set(mp); + // Some stuff about how strong and bouncy the spring should be + md.maxForce = 1000.0 * box.body.m_mass; + md.frequencyHz = 5.0; + md.dampingRatio = 0.9; + + // Wake up body! + //box.body.wakeUp(); + + // Make the joint! + mouseJoint = (MouseJoint) box2d.world.createJoint(md); + } + + void destroy() { + // We can get rid of the joint when the mouse is released + if (mouseJoint != null) { + box2d.world.destroyJoint(mouseJoint); + mouseJoint = null; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Box.pde new file mode 100644 index 000000000..1fb05d066 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Box.pde @@ -0,0 +1,85 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x_, float y_) { + float x = x_; + float y = y_; + w = 24; + h = 24; + // Add the box to the box2d world + makeBody(new Vec2(x, y), w, h); + body.setUserData(this); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + boolean contains(float x, float y) { + Vec2 worldPoint = box2d.coordPixelsToWorld(x, y); + Fixture f = body.getFixtureList(); + boolean inside = f.testPoint(worldPoint); + return inside; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(175); + stroke(0); + rect(0, 0, w, h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + //body.setMassFromShapes(); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/CollisionsAndControlInterface.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/CollisionsAndControlInterface.pde new file mode 100644 index 000000000..08df03156 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/CollisionsAndControlInterface.pde @@ -0,0 +1,111 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with our own motion (by attaching a MouseJoint) +// Also demonstrates how to know which object was hit + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// Just a single box this time +Box box; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +// The Spring that will attach to the box from the mouse +Spring spring; + +// Perlin noise values +float xoff = 0; +float yoff = 1000; + + +void setup() { + size(400,300); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Add a listener to listen for collisions! + box2d.world.setContactListener(new CustomListener()); + + // Make the box + box = new Box(width/2,height/2); + + // Make the spring (it doesn't really get initialized until the mouse is clicked) + spring = new Spring(); + spring.bind(width/2,height/2,box); + + // Create the empty list + particles = new ArrayList(); + + +} + +void draw() { + background(255); + + if (random(1) < 0.2) { + float sz = random(4,8); + particles.add(new Particle(width/2,-20,sz)); + } + + + // We must always step through time! + box2d.step(); + + // Make an x,y coordinate out of perlin noise + float x = noise(xoff)*width; + float y = noise(yoff)*height; + xoff += 0.01; + yoff += 0.01; + + // This is tempting but will not work! + // box.body.setXForm(box2d.screenToWorld(x,y),0); + + // Instead update the spring which pulls the mouse along + if (mousePressed) { + spring.update(mouseX,mouseY); + } else { + spring.update(x,y); + } + //box.body.setAngularVelocity(0); + + // Look at all particles + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.display(); + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + if (p.done()) { + particles.remove(i); + } + } + + // Draw the box + box.display(); + + // Draw the spring + // spring.display(); +} + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/ContactListener.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/ContactListener.pde new file mode 100644 index 000000000..48b5f659e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/ContactListener.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// ContactListener to listen for collisions! + +import org.jbox2d.callbacks.ContactImpulse; +import org.jbox2d.callbacks.ContactListener; +import org.jbox2d.collision.Manifold; +import org.jbox2d.dynamics.contacts.Contact; + + class CustomListener implements ContactListener { + CustomListener() { + } + + // This function is called when a new collision occurs + void beginContact(Contact cp) { + // Get both fixtures + Fixture f1 = cp.getFixtureA(); + Fixture f2 = cp.getFixtureB(); + // Get both bodies + Body b1 = f1.getBody(); + Body b2 = f2.getBody(); + // Get our objects that reference these bodies + Object o1 = b1.getUserData(); + Object o2 = b2.getUserData(); + + // If object 1 is a Box, then object 2 must be a particle + // Note we are ignoring particle on particle collisions + if (o1.getClass() == Box.class) { + Particle p = (Particle) o2; + p.change(); + } + // If object 2 is a Box, then object 1 must be a particle + else if (o2.getClass() == Box.class) { + Particle p = (Particle) o1; + p.change(); + } + } + + void endContact(Contact contact) { + // TODO Auto-generated method stub + } + + void preSolve(Contact contact, Manifold oldManifold) { + // TODO Auto-generated method stub + } + + void postSolve(Contact contact, ContactImpulse impulse) { + // TODO Auto-generated method stub + } +} + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Particle.pde new file mode 100644 index 000000000..50be57e86 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Particle.pde @@ -0,0 +1,91 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + color col; + + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x, y, r); + body.setUserData(this); + col = color(175); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Change color when hit + void change() { + col = color(255, 0, 0); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(col); + stroke(0); + strokeWeight(1); + ellipse(0, 0, r*2, r*2); + // Let's add a line so we can see the rotation + line(0, 0, r, 0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x, y); + bd.type = BodyType.DYNAMIC; + body = box2d.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + body.setAngularVelocity(random(-10, 10)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Spring.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Spring.pde new file mode 100644 index 000000000..c16494932 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/CollisionsAndControlInterface/Spring.pde @@ -0,0 +1,81 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Class to describe the spring joint (displayed as a line) + +class Spring { + + // This is the box2d object we need to create + MouseJoint mouseJoint; + + Spring() { + // At first it doesn't exist + mouseJoint = null; + } + + // If it exists we set its target to the mouse location + void update(float x, float y) { + if (mouseJoint != null) { + // Always convert to world coordinates! + Vec2 mouseWorld = box2d.coordPixelsToWorld(x,y); + mouseJoint.setTarget(mouseWorld); + } + } + + void display() { + if (mouseJoint != null) { + // We can get the two anchor points + Vec2 v1 = null; + mouseJoint.getAnchorA(v1); + Vec2 v2 = null; + mouseJoint.getAnchorB(v2); + // Convert them to screen coordinates + v1 = box2d.coordWorldToPixels(v1); + v2 = box2d.coordWorldToPixels(v2); + // And just draw a line + stroke(0); + strokeWeight(1); + line(v1.x,v1.y,v2.x,v2.y); + } + } + + + // This is the key function where + // we attach the spring to an x,y location + // and the Box object's location + void bind(float x, float y, Box box) { + // Define the joint + MouseJointDef md = new MouseJointDef(); + + // Body A is just a fake ground body for simplicity (there isn't anything at the mouse) + md.bodyA = box2d.getGroundBody(); + // Body 2 is the box's boxy + md.bodyB = box.body; + // Get the mouse location in world coordinates + Vec2 mp = box2d.coordPixelsToWorld(x,y); + // And that's the target + md.target.set(mp); + // Some stuff about how strong and bouncy the spring should be + md.maxForce = 1000.0f * box.body.m_mass; + md.frequencyHz = 5.0f; + md.dampingRatio = 0.9f; + + // Wake up body! + //box.body.wakeUp(); + + // Make the joint! + mouseJoint = (MouseJoint) box2d.world.createJoint(md); + } + + void destroy() { + // We can get rid of the joint when the mouse is released + if (mouseJoint != null) { + box2d.world.destroyJoint(mouseJoint); + mouseJoint = null; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Boundary.pde new file mode 100644 index 000000000..9a17026a1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Boundary.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Box.pde new file mode 100644 index 000000000..7847ff65f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Box.pde @@ -0,0 +1,96 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x, float y) { + w = random(8,16); + h = w; + // Add the box to the box2d world + makeBody(new Vec2(x,y),w,h); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+w*h) { + killBody(); + return true; + } + return false; + } + + void attract(float x,float y) { + // From BoxWrap2D example + Vec2 worldTarget = box2d.coordPixelsToWorld(x,y); + Vec2 bodyVec = body.getWorldCenter(); + // First find the vector going from this body to the specified point + worldTarget.subLocal(bodyVec); + // Then, scale the vector to the specified force + worldTarget.normalize(); + worldTarget.mulLocal((float) 50); + // Now apply it to the body's center of mass. + body.applyForce(worldTarget, bodyVec); + } + + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(CENTER); + pushMatrix(); + translate(pos.x,pos.y); + rotate(-a); + fill(175); + stroke(0); + rect(0,0,w,h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + + body = box2d.createBody(bd); + body.createFixture(fd); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Exercise_5_10_ApplyForceAttractMouse.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Exercise_5_10_ApplyForceAttractMouse.pde new file mode 100644 index 000000000..63bf2617b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceAttractMouse/Exercise_5_10_ApplyForceAttractMouse.pde @@ -0,0 +1,82 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of falling rectangles + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; +// A list for all of our rectangles +ArrayList boxes; + +void setup() { + size(640,360); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -20); + + // Create ArrayLists + boxes = new ArrayList(); + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(width/4,height-5,width/2-50,10)); + boundaries.add(new Boundary(3*width/4,height-5,width/2-50,10)); + boundaries.add(new Boundary(width-5,height/2,10,height)); + boundaries.add(new Boundary(5,height/2,10,height)); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // When the mouse is clicked, add a new Box object + if (random(1) < 0.1) { + Box p = new Box(random(width),10); + boxes.add(p); + } + + if (mousePressed) { + for (Box b: boxes) { + b.attract(mouseX,mouseY); + } + } + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } + + // Display all the boxes + for (Box b: boxes) { + b.display(); + } + + // Boxes that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = boxes.size()-1; i >= 0; i--) { + Box b = boxes.get(i); + if (b.done()) { + boxes.remove(i); + } + } + + fill(0); + text("Click mouse to attract boxes",20,20); +} + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Boundary.pde new file mode 100644 index 000000000..9a17026a1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Boundary.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Box.pde new file mode 100644 index 000000000..92c4f0280 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Box.pde @@ -0,0 +1,87 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x, float y) { + w = random(8, 16); + h = w; + // Add the box to the box2d world + makeBody(new Vec2(x, y), w, h); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+w*h) { + killBody(); + return true; + } + return false; + } + + void applyForce(Vec2 force) { + Vec2 pos = body.getWorldCenter(); + body.applyForce(force, pos); + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(175); + stroke(0); + rect(0, 0, w, h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.2; + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + bd.angle = random(TWO_PI); + + body = box2d.createBody(bd); + body.createFixture(fd); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Exercise_5_10_ApplyForceSimpleWind.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Exercise_5_10_ApplyForceSimpleWind.pde new file mode 100644 index 000000000..fa0b3f89c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_ApplyForceSimpleWind/Exercise_5_10_ApplyForceSimpleWind.pde @@ -0,0 +1,83 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of falling rectangles + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; +// A list for all of our rectangles +ArrayList boxes; + +void setup() { + size(640,360); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -20); + + // Create ArrayLists + boxes = new ArrayList(); + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(width/4,height-5,width/2-100,10)); + boundaries.add(new Boundary(3*width/4,height-5,width/2-100,10)); + boundaries.add(new Boundary(width-5,height/2,10,height)); + boundaries.add(new Boundary(5,height/2,10,height)); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // When the mouse is clicked, add a new Box object + if (random(1) < 0.1) { + Box p = new Box(random(width),10); + boxes.add(p); + } + + if (mousePressed) { + for (Box b: boxes) { + Vec2 wind = new Vec2(20,0); + b.applyForce(wind); + } + } + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } + + // Display all the boxes + for (Box b: boxes) { + b.display(); + } + + // Boxes that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = boxes.size()-1; i >= 0; i--) { + Box b = boxes.get(i); + if (b.done()) { + boxes.remove(i); + } + } + + fill(0); + text("Click mouse to apply a wind force.",20,20); +} + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Attractor.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Attractor.pde new file mode 100644 index 000000000..2a9bd9e38 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Attractor.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Showing how to use applyForce() with box2d + +// Fixed Attractor (this is redundant with Mover) + +class Attractor { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Attractor(float r_, float x, float y) { + r = r_; + // Define a body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + body.createFixture(cs,1); + + } + + + // Formula for gravitational attraction + // We are computing this in "world" coordinates + // No need to convert to pixels and back + Vec2 attract(Mover m) { + float G = 100; // Strength of force + // clone() makes us a copy + Vec2 pos = body.getWorldCenter(); + Vec2 moverPos = m.body.getWorldCenter(); + // Vector pointing from mover to attractor + Vec2 force = pos.sub(moverPos); + float distance = force.length(); + // Keep force within bounds + distance = constrain(distance,1,5); + force.normalize(); + // Note the attractor's mass is 0 because it's fixed so can't use that + float strength = (G * 1 * m.body.m_mass) / (distance * distance); // Calculate gravitional force magnitude + force.mulLocal(strength); // Get force vector --> magnitude * direction + return force; + } + + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + fill(175); + stroke(0); + strokeWeight(2); + ellipse(0,0,r*2,r*2); + popMatrix(); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Exercise_5_10_AttractionApplyForce.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Exercise_5_10_AttractionApplyForce.pde new file mode 100644 index 000000000..c85c91956 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Exercise_5_10_AttractionApplyForce.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Showing how to use applyForce() with box2d + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// Movers, jsut like before! +Mover[] movers = new Mover[25]; + +// Attractor, just like before! +Attractor a; + +void setup() { + size(800,200); + box2d = new PBox2D(this); + box2d.createWorld(); + // No global gravity force + box2d.setGravity(0,0); + + for (int i = 0; i < movers.length; i++) { + movers[i] = new Mover(random(8,16),random(width),random(height)); + } + a = new Attractor(32,width/2,height/2); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + a.display(); + + for (int i = 0; i < movers.length; i++) { + // Look, this is just like what we had before! + Vec2 force = a.attract(movers[i]); + movers[i].applyForce(force); + movers[i].display(); + } +} + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Mover.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Mover.pde new file mode 100644 index 000000000..df8cafcc5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_10_AttractionApplyForce/Mover.pde @@ -0,0 +1,63 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Showing how to use applyForce() with box2d + +class Mover { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Mover(float r_, float x, float y) { + r = r_; + // Define a body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + + body.setLinearVelocity(new Vec2(random(-5,5),random(-5,-5))); + body.setAngularVelocity(random(-1,1)); + } + + void applyForce(Vec2 v) { + body.applyForce(v, body.getWorldCenter()); + } + + + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + fill(127); + stroke(0); + strokeWeight(2); + ellipse(0,0,r*2,r*2); + // Let's add a line so we can see the rotation + line(0,0,r,0); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Exercise_5_3_NoiseChain.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Exercise_5_3_NoiseChain.pde new file mode 100644 index 000000000..d4f75ecd5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Exercise_5_3_NoiseChain.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An uneven surface + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +// An object to store information about the uneven surface +Surface surface; + +void setup() { + size(383,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -20); + + // Create the empty list + particles = new ArrayList(); + // Create the surface + surface = new Surface(); +} + +void draw() { + // If the mouse is pressed, we make new particles + if (mousePressed) { + float sz = random(2,6); + particles.add(new Particle(mouseX,mouseY,sz)); + } + + // We must always step through time! + box2d.step(); + + background(255); + + // Draw the surface + surface.display(); + + // Draw all particles + for (Particle p: particles) { + p.display(); + } + + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + if (p.done()) { + particles.remove(i); + } + } +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Particle.pde new file mode 100644 index 000000000..05783d49e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Particle.pde @@ -0,0 +1,89 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x,y,r); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(-a); + fill(175); + stroke(0); + strokeWeight(1); + ellipse(0,0,r*2,r*2); + // Let's add a line so we can see the rotation + line(0,0,r,0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + bd.type = BodyType.DYNAMIC; + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + // Give it a random initial velocity (and angular velocity) + body.setLinearVelocity(new Vec2(random(-10f,10f),random(5f,10f))); + body.setAngularVelocity(random(-10,10)); + } + + + + + + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Surface.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Surface.pde new file mode 100644 index 000000000..211874b0d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_NoiseChain/Surface.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An uneven surface boundary + +class Surface { + // We'll keep track of all of the surface points + ArrayList surface; + + + Surface() { + surface = new ArrayList(); + + // This is what box2d uses to put the surface in its world + ChainShape chain = new ChainShape(); + + // Perlin noise argument + float xoff = 0.0; + + // This has to go backwards so that the objects bounce off the top of the surface + // This "edgechain" will only work in one direction! + for (float x = width+10; x > -10; x -= 5) { + + // Doing some stuff with perlin noise to calculate a surface that points down on one side + // and up on the other + float y; + if (x > width/2) { + y = 50 + (width - x)*1.1 + map(noise(xoff),0,1,-80,80); + } + else { + y = 50 + x*1.1 + map(noise(xoff),0,1,-40,40); + } + + // Store the vertex in screen coordinates + surface.add(new Vec2(x,y)); + + // Move through perlin noise + xoff += 0.1; + + } + + // Build an array of vertices in Box2D coordinates + // from the ArrayList we made + Vec2[] vertices = new Vec2[surface.size()]; + for (int i = 0; i < vertices.length; i++) { + Vec2 edge = box2d.coordPixelsToWorld(surface.get(i)); + vertices[i] = edge; + } + + // Create the chain! + chain.createChain(vertices,vertices.length); + + // The edge chain is now attached to a body via a fixture + BodyDef bd = new BodyDef(); + bd.position.set(0.0f,0.0f); + Body body = box2d.createBody(bd); + // Shortcut, we could define a fixture if we + // want to specify frictions, restitution, etc. + body.createFixture(chain,1); + + } + + // A simple function to just draw the edge chain as a series of vertex points + void display() { + strokeWeight(2); + stroke(0); + noFill(); + beginShape(); + for (Vec2 v: surface) { + vertex(v.x,v.y); + } + endShape(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Exercise_5_3_SineChain.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Exercise_5_3_SineChain.pde new file mode 100644 index 000000000..b313ef3ce --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Exercise_5_3_SineChain.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An uneven surface + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +// An object to store information about the uneven surface +Surface surface; + +void setup() { + size(383,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -10); + + // Create the empty list + particles = new ArrayList(); + // Create the surface + surface = new Surface(); +} + +void draw() { + // If the mouse is pressed, we make new particles + if (random(1) < 0.5) { + float sz = random(2,6); + particles.add(new Particle(width/2,10,sz)); + } + + // We must always step through time! + box2d.step(); + + background(255); + + // Draw the surface + surface.display(); + + // Draw all particles + for (Particle p: particles) { + p.display(); + } + + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + if (p.done()) { + particles.remove(i); + } + } +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Particle.pde new file mode 100644 index 000000000..05783d49e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Particle.pde @@ -0,0 +1,89 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x,y,r); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(-a); + fill(175); + stroke(0); + strokeWeight(1); + ellipse(0,0,r*2,r*2); + // Let's add a line so we can see the rotation + line(0,0,r,0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + bd.type = BodyType.DYNAMIC; + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + // Give it a random initial velocity (and angular velocity) + body.setLinearVelocity(new Vec2(random(-10f,10f),random(5f,10f))); + body.setAngularVelocity(random(-10,10)); + } + + + + + + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Surface.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Surface.pde new file mode 100644 index 000000000..3be00b5a9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_3_SineChain/Surface.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An uneven surface boundary + +class Surface { + // We'll keep track of all of the surface points + ArrayList surface; + + + Surface() { + surface = new ArrayList(); + + // This is what box2d uses to put the surface in its world + ChainShape chain = new ChainShape(); + + float theta = 0; + + // This has to go backwards so that the objects bounce off the top of the surface + // This "edgechain" will only work in one direction! + for (float x = width+10; x > -10; x -= 5) { + + // Doing some stuff with perlin noise to calculate a surface that points down on one side + // and up on the other + float y = map(cos(theta),-1,1,75,height-10); + theta += 0.15; + + // Store the vertex in screen coordinates + surface.add(new Vec2(x,y)); + + } + + // Build an array of vertices in Box2D coordinates + // from the ArrayList we made + Vec2[] vertices = new Vec2[surface.size()]; + for (int i = 0; i < vertices.length; i++) { + Vec2 edge = box2d.coordPixelsToWorld(surface.get(i)); + vertices[i] = edge; + } + + // Create the chain! + chain.createChain(vertices,vertices.length); + + // The edge chain is now attached to a body via a fixture + BodyDef bd = new BodyDef(); + bd.position.set(0.0f,0.0f); + Body body = box2d.createBody(bd); + // Shortcut, we could define a fixture if we + // want to specify frictions, restitution, etc. + body.createFixture(chain,1); + + } + + // A simple function to just draw the edge chain as a series of vertex points + void display() { + strokeWeight(2); + stroke(0); + noFill(); + beginShape(); + for (Vec2 v: surface) { + vertex(v.x,v.y); + } + endShape(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Box.pde new file mode 100644 index 000000000..f872679b9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Box.pde @@ -0,0 +1,88 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x, float y) { + w = random(4, 16); + h = random(4, 16); + // Add the box to the box2d world + makeBody(new Vec2(x, y), w, h); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+w*h) { + killBody(); + return true; + } + return false; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + stroke(0); + fill(127); + strokeWeight(2); + rect(0, 0, w, h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + + body = box2d.createBody(bd); + body.createFixture(fd); + //body.setMassFromShapes(); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Bridge.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Bridge.pde new file mode 100644 index 000000000..eafb42cdc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Bridge.pde @@ -0,0 +1,66 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Series of Particles connected with distance joints + +class Bridge { + + // Bridge properties + float totalLength; // How long + int numPoints; // How many points + + // Our chain is a list of particles + ArrayList particles; + + // Chain constructor + Bridge(float l, int n) { + + totalLength = l; + numPoints = n; + + particles = new ArrayList(); + + float len = totalLength / numPoints; + + // Here is the real work, go through and add particles to the chain itself + for(int i=0; i < numPoints+1; i++) { + // Make a new particle + Particle p = null; + + // First and last particles are made with density of zero + if (i == 0 || i == numPoints) p = new Particle(i*len,height/4,4,true); + else p = new Particle(i*len,height/4,4,false); + particles.add(p); + + // Connect the particles with a distance joint + if (i > 0) { + DistanceJointDef djd = new DistanceJointDef(); + Particle previous = particles.get(i-1); + // Connection between previous particle and this one + djd.bodyA = previous.body; + djd.bodyB = p.body; + // Equilibrium length + djd.length = box2d.scalarPixelsToWorld(len); + // These properties affect how springy the joint is + djd.frequencyHz = 0; + djd.dampingRatio = 0; + + // Make the joint. Note we aren't storing a reference to the joint ourselves anywhere! + // We might need to someday, but for now it's ok + DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd); + } + } + } + + // Draw the bridge + void display() { + for (Particle p: particles) { + p.display(); + } + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Exercise_5_6_Bridge.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Exercise_5_6_Bridge.pde new file mode 100644 index 000000000..2946efe93 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Exercise_5_6_Bridge.pde @@ -0,0 +1,82 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example demonstrating distance joints +// A bridge is formed by connected a series of particles with joints + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// An object to describe a Bridget (a list of particles with joint connections) +Bridge bridge; + +// A list for all of our rectangles +ArrayList boxes; + +void setup() { + size(800, 200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + + // Make the bridge + bridge = new Bridge(width, width/10); + + // Create ArrayLists + boxes = new ArrayList(); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + + // When the mouse is clicked, add a new Box object + if (mousePressed) { + Box p = new Box(mouseX, mouseY); + boxes.add(p); + } + + // Display all the boxes + for (Box b: boxes) { + b.display(); + } + + // Boxes that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = boxes.size()-1; i >= 0; i--) { + Box b = boxes.get(i); + if (b.done()) { + boxes.remove(i); + } + } + + // Draw the windmill + bridge.display(); + + + fill(0); + //text("Click mouse to add boxes.", 10, height-10); +} + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Particle.pde new file mode 100644 index 000000000..c545127cc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Exercise_5_6_Bridge/Particle.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Particle(float x, float y, float r_, boolean fixed) { + r = r_; + + // Define a body + BodyDef bd = new BodyDef(); + if (fixed) bd.type = BodyType.STATIC; + else bd.type = BodyType.DYNAMIC; + + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + stroke(0); + fill(127); + strokeWeight(2); + ellipse(0,0,r*2,r*2); + // Let's add a line so we can see the rotation + line(0,0,r,0); + popMatrix(); + } + + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/Box.pde new file mode 100644 index 000000000..c6a8aed73 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/Box.pde @@ -0,0 +1,102 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + boolean dragged = false; + + // Constructor + Box(float x_, float y_) { + float x = x_; + float y = y_; + w = 24; + h = 24; + // Add the box to the box2d world + makeBody(new Vec2(x,y),w,h); + body.setUserData(this); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + boolean contains(float x, float y) { + Vec2 worldPoint = box2d.coordPixelsToWorld(x, y); + Fixture f = body.getFixtureList(); + boolean inside = f.testPoint(worldPoint); + return inside; + } + + void setAngularVelocity(float a) { + body.setAngularVelocity(a); + } + void setVelocity(Vec2 v) { + body.setLinearVelocity(v); + } + + void setLocation(float x, float y) { + Vec2 pos = body.getWorldCenter(); + Vec2 target = box2d.coordPixelsToWorld(x,y); + Vec2 diff = new Vec2(target.x-pos.x,target.y-pos.y); + diff.mulLocal(50); + setVelocity(diff); + setAngularVelocity(0); + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + fill(175); + stroke(0); + rect(0,0,w,h); + popMatrix(); + } + + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.KINEMATIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + bd.fixedRotation = true; + body = box2d.createBody(bd); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape ps = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + ps.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = ps; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/KinematicTest.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/KinematicTest.pde new file mode 100644 index 000000000..758299639 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/KinematicTest.pde @@ -0,0 +1,141 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with our own motion (by attaching a MouseJoint) +// Also demonstrates how to know which object was hit + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// Just a single box this time +Box box; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +// Perlin noise values +float xoff = 0; +float yoff = 1000; + + +void setup() { + size(640,360); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Turn on collision listening! + box2d.listenForCollisions(); + + // Make the box + box = new Box(width/2,height/2); + + // Create the empty list + particles = new ArrayList(); + + +} + +void draw() { + background(255); + + if (random(1) < 0.2) { + float sz = random(4,8); + particles.add(new Particle(width/2,-20,sz)); + } + + + // We must always step through time! + box2d.step(); + + // Make an x,y coordinate out of perlin noise + float x = noise(xoff)*width; + float y = noise(yoff)*height; + xoff += 0.01; + yoff += 0.01; + + // This is tempting but will not work! + // box.body.setXForm(box2d.screenToWorld(x,y),0); + + // Instead update the spring which pulls the mouse along + if (mousePressed) { + box.setLocation(mouseX,mouseY); + } else { + //box.setLocation(x,y); + } + + // Look at all particles + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.display(); + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + if (p.done()) { + particles.remove(i); + } + } + + // Draw the box + box.display(); + + // Draw the spring + // spring.display(); +} + + +// Collision event functions! +void beginContact(Contact cp) { + // Get both fixtures + Fixture f1 = cp.getFixtureA(); + Fixture f2 = cp.getFixtureB(); + // Get both bodies + Body b1 = f1.getBody(); + Body b2 = f2.getBody(); + // Get our objects that reference these bodies + Object o1 = b1.getUserData(); + Object o2 = b2.getUserData(); + + // If object 1 is a Box, then object 2 must be a particle + // Note we are ignoring particle on particle collisions + if (o1.getClass() == Box.class) { + Particle p = (Particle) o2; + p.change(); + } + // If object 2 is a Box, then object 1 must be a particle + else if (o2.getClass() == Box.class) { + Particle p = (Particle) o1; + p.change(); + } +} + + +// Objects stop touching each other +void endContact(Contact cp) { +} + + + + + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/Particle.pde new file mode 100644 index 000000000..12c50f772 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/KinematicTest/Particle.pde @@ -0,0 +1,93 @@ +// The Nature of Code +// +// Spring 2010 +// PBox2D example + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + color col; + + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x, y, r); + body.setUserData(this); + col = color(175); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Change color when hit + void change() { + col = color(255, 0, 0); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(col); + stroke(0); + strokeWeight(1); + ellipse(0, 0, r*2, r*2); + // Let's add a line so we can see the rotation + line(0, 0, r, 0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x, y); + bd.type = BodyType.DYNAMIC; + + body = box2d.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + body.setAngularVelocity(random(-10, 10)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Boundary.pde new file mode 100644 index 000000000..71c6a82d0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Boundary.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class (now incorporates angle) + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_, float a) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.angle = a; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + noFill(); + stroke(0); + strokeWeight(1); + rectMode(CENTER); + + float a = b.getAngle(); + + pushMatrix(); + translate(x,y); + rotate(-a); + rect(0,0,w,h); + popMatrix(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Liquidy.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Liquidy.pde new file mode 100644 index 000000000..fa7ab19aa --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Liquidy.pde @@ -0,0 +1,71 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Box2D particle system example + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + + + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; + +// A list for all particle systems +ArrayList systems; + +void setup() { + size(400,300); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // We are setting a custom gravity + box2d.setGravity(0, -20); + + // Create ArrayLists + systems = new ArrayList(); + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(50,100,300,5,-0.3)); + boundaries.add(new Boundary(250,175,300,5,0.5)); + +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // Run all the particle systems + for (ParticleSystem system: systems) { + system.run(); + + int n = (int) random(0,2); + system.addParticles(n); + } + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } +} + + +void mousePressed() { + // Add a new Particle System whenever the mouse is clicked + systems.add(new ParticleSystem(0, new PVector(mouseX,mouseY))); +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Particle.pde new file mode 100644 index 000000000..dd1f4f564 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/Particle.pde @@ -0,0 +1,98 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A Particle + +class Particle { + + // We need to keep track of a Body + Body body; + + PVector[] trail; + + // Constructor + Particle(float x_, float y_) { + float x = x_; + float y = y_; + trail = new PVector[6]; + for (int i = 0; i < trail.length; i++) { + trail[i] = new PVector(x, y); + } + + // Add the box to the box2d world + // Here's a little trick, let's make a tiny tiny radius + // This way we have collisions, but they don't overwhelm the system + makeBody(new Vec2(x, y), 0.2f); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+20) { + killBody(); + return true; + } + return false; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + + // Keep track of a history of screen positions in an array + for (int i = 0; i < trail.length-1; i++) { + trail[i] = trail[i+1]; + } + trail[trail.length-1] = new PVector(pos.x, pos.y); + + // Draw particle as a trail + beginShape(); + noFill(); + strokeWeight(2); + stroke(0, 150); + for (int i = 0; i < trail.length; i++) { + vertex(trail[i].x, trail[i].y); + } + endShape(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float r) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-1, 1), random(-1, 1))); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + + fd.density = 1; + fd.friction = 0; // Slippery when wet! + fd.restitution = 0.5; + + // We could use this if we want to turn collisions off + //cd.filter.groupIndex = -10; + + // Attach fixture to body + body.createFixture(fd); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/ParticleSystem.pde new file mode 100644 index 000000000..08e74e0b4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/Liquidy/ParticleSystem.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Box2D Particle System + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList 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(); // Initialize the ArrayList + origin = v.get(); // Store the origin point + + for (int i = 0; i < num; i++) { + particles.add(new Particle(origin.x,origin.y)); // Add "num" amount of particles to the ArrayList + } + } + + void run() { + // Display all the particles + for (Particle p: particles) { + p.display(); + } + + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + if (p.done()) { + particles.remove(i); + } + } + } + + void addParticles(int n) { + for (int i = 0; i < n; i++) { + particles.add(new Particle(origin.x,origin.y)); + } + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } + else { + return false; + } + } + +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/Boundary.pde new file mode 100644 index 000000000..71c6a82d0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/Boundary.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class (now incorporates angle) + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_, float a) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.angle = a; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + noFill(); + stroke(0); + strokeWeight(1); + rectMode(CENTER); + + float a = b.getAngle(); + + pushMatrix(); + translate(x,y); + rotate(-a); + rect(0,0,w,h); + popMatrix(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/Box.pde new file mode 100644 index 000000000..806f51daa --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/Box.pde @@ -0,0 +1,105 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + boolean dragged = false; + + // Constructor + Box(float x_, float y_) { + float x = x_; + float y = y_; + w = 24; + h = 24; + // Add the box to the box2d world + makeBody(new Vec2(x,y),w,h); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + boolean contains(float x, float y) { + Vec2 worldPoint = box2d.coordPixelsToWorld(x, y); + Fixture f = body.getFixtureList(); + boolean inside = f.testPoint(worldPoint); + return inside; + } + + void setAngularVelocity(float a) { + body.setAngularVelocity(a); + } + void setVelocity(Vec2 v) { + body.setLinearVelocity(v); + } + + void setLocation(float x, float y) { + Vec2 pos = body.getWorldCenter(); + Vec2 target = box2d.coordPixelsToWorld(x,y); + Vec2 diff = target.sub(pos); + diff.mulLocal(50); + setVelocity(diff); + setAngularVelocity(0); + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + fill(175); + stroke(0); + rect(0,0,w,h); + popMatrix(); + } + + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.KINEMATIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + //body.setMassFromShapes(); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/MouseKinematic.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/MouseKinematic.pde new file mode 100644 index 000000000..a2e2bdba3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/MouseKinematic/MouseKinematic.pde @@ -0,0 +1,75 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with the mouse (by attaching a spring) + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; + +// Just a single box this time +Box box; + +void setup() { + size(640,360); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Make the box + box = new Box(width/2,height/2); + + // Add a bunch of fixed boundaries + boundaries = new ArrayList(); + boundaries.add(new Boundary(width/2,height-5,width,10,0)); + boundaries.add(new Boundary(width/2,5,width,10,0)); + boundaries.add(new Boundary(width-5,height/2,10,height,0)); + boundaries.add(new Boundary(5,height/2,10,height,0)); +} + + +void draw() { + background(255); + + // We must always step through time! + + //if (box.dragged) { + box.setLocation(mouseX,mouseY); + //} + + box2d.step(); + + // Draw the boundaries + for (Boundary wall : boundaries) { + wall.display(); + } + + // Draw the box + box.display(); + + +} + +void mousePressed() { + if (box.contains(mouseX,mouseY)) { + box.dragged = true; + } +} + +void mouseReleased() { + box.dragged = false; +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/Box.pde new file mode 100644 index 000000000..e9774abf0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/Box.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Box { + + float x,y; + float w,h; + + // Constructor + Box(float x_, float y_) { + x = x_; + y = y_; + w = 16; + h = 16; + } + + // Drawing the box + void display() { + fill(127); + stroke(0); + strokeWeight(2); + rectMode(CENTER); + rect(x,y,w,h); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde new file mode 100644 index 000000000..ca8a2decc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A list for all of our rectangles +ArrayList boxes; + +void setup() { + size(800,200); + // Create ArrayLists + boxes = new ArrayList(); +} + +void draw() { + background(255); + + // When the mouse is clicked, add a new Box object + if (mousePressed) { + Box p = new Box(mouseX,mouseY); + boxes.add(p); + } + + // Display all the boxes + for (Box b: boxes) { + b.display(); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/Box.pde new file mode 100644 index 000000000..2be8fa137 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/Box.pde @@ -0,0 +1,59 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Box { + // Instead of any of the usual variables, we will store a reference to a Box2D Body + Body body; + + float w,h; + + Box(float x, float y) { + w = 16; + h = 16; + + // Build Body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + body = box2d.createBody(bd); + + + // Define a polygon (this is what we use for a rectangle) + PolygonShape ps = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); // Box2D considers the width and height of a + ps.setAsBox(box2dW, box2dH); // rectangle to be the distance from the + // center to the edge (so half of what we + // normally think of as width or height.) + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = ps; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + // Attach Fixture to Body + body.createFixture(fd); + } + + void display() { + // We need the Body’s location and angle + Vec2 pos = box2d.getBodyPixelCoord(body); + float a = body.getAngle(); + + pushMatrix(); + translate(pos.x,pos.y); // Using the Vec2 position and float angle to + rotate(-a); // translate and rotate the rectangle + fill(127); + stroke(0); + strokeWeight(2); + rectMode(CENTER); + rect(0,0,w,h); + popMatrix(); + } + +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde new file mode 100644 index 000000000..dce205f42 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde @@ -0,0 +1,40 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A list for all of our rectangles +ArrayList boxes; + +PBox2D box2d; + +void setup() { + size(800, 200); + // Initialize and create the Box2D world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Create ArrayLists + boxes = new ArrayList(); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // When the mouse is clicked, add a new Box object + Box p = new Box(mouseX, mouseY); + boxes.add(p); + + // Display all the boxes + for (Box b: boxes) { + b.display(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/Boundary.pde new file mode 100644 index 000000000..54e662ceb --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/Boundary.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape ps = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + ps.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(ps,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/Box.pde new file mode 100644 index 000000000..344e1f108 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/Box.pde @@ -0,0 +1,87 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x, float y) { + w = random(4, 16); + h = random(4, 16); + // Add the box to the box2d world + makeBody(new Vec2(x, y), w, h); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+w*h) { + killBody(); + return true; + } + return false; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(127); + stroke(0); + strokeWeight(2); + rect(0, 0, w, h); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + + body = box2d.createBody(bd); + body.createFixture(fd); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde new file mode 100644 index 000000000..3e80aade3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde @@ -0,0 +1,71 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of falling rectangles + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; +// A list for all of our rectangles +ArrayList boxes; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -10); + + // Create ArrayLists + boxes = new ArrayList(); + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(width/4,height-5,width/2-50,10)); + boundaries.add(new Boundary(3*width/4,height-50,width/2-50,10)); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // Boxes fall from the top every so often + if (random(1) < 0.2) { + Box p = new Box(width/2,30); + boxes.add(p); + } + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } + + // Display all the boxes + for (Box b: boxes) { + b.display(); + } + + // Boxes that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = boxes.size()-1; i >= 0; i--) { + Box b = boxes.get(i); + if (b.done()) { + boxes.remove(i); + } + } +} + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde new file mode 100644 index 000000000..a9f07c166 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde @@ -0,0 +1,70 @@ +// The Nature of Code +// +// Spring 2011 +// PBox2D example + +// An uneven surface + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +// An object to store information about the uneven surface +Surface surface; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -10); + + // Create the empty list + particles = new ArrayList(); + // Create the surface + surface = new Surface(); +} + +void draw() { + // If the mouse is pressed, we make new particles + if (random(1) < 0.5) { + float sz = random(4,8); + particles.add(new Particle(width/2,10,sz)); + } + + // We must always step through time! + box2d.step(); + + background(255); + + // Draw the surface + surface.display(); + + // Draw all particles + for (Particle p: particles) { + p.display(); + } + + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + if (p.done()) { + particles.remove(i); + } + } +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Particle.pde new file mode 100644 index 000000000..a7d390361 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Particle.pde @@ -0,0 +1,89 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x,y,r); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(-a); + fill(127); + stroke(0); + strokeWeight(2); + ellipse(0,0,r*2,r*2); + // Let's add a line so we can see the rotation + line(0,0,r,0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + bd.type = BodyType.DYNAMIC; + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + // Give it a random initial velocity (and angular velocity) + body.setLinearVelocity(new Vec2(random(-10f,10f),random(5f,10f))); + body.setAngularVelocity(random(-10,10)); + } + + + + + + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde new file mode 100644 index 000000000..d11a18410 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An uneven surface boundary + +class Surface { + // We'll keep track of all of the surface points + ArrayList surface; + + + Surface() { + surface = new ArrayList(); + // Here we keep track of the screen coordinates of the chain + surface.add(new Vec2(0, height/2)); + //surface.add(new Vec2(width/2, height/2+50)); + surface.add(new Vec2(width, height/2)); + + // This is what box2d uses to put the surface in its world + ChainShape chain = new ChainShape(); + + // We can add 3 vertices by making an array of 3 Vec2 objects + Vec2[] vertices = new Vec2[surface.size()]; + for (int i = 0; i < vertices.length; i++) { + vertices[i] = box2d.coordPixelsToWorld(surface.get(i)); + } + + chain.createChain(vertices, vertices.length); + + // The edge chain is now a body! + BodyDef bd = new BodyDef(); + Body body = box2d.world.createBody(bd); + // Shortcut, we could define a fixture if we + // want to specify frictions, restitution, etc. + body.createFixture(chain, 1); + } + + // A simple function to just draw the edge chain as a series of vertex points + void display() { + strokeWeight(1); + stroke(0); + fill(0); + beginShape(); + for (Vec2 v: surface) { + vertex(v.x, v.y); + } + vertex(width, height); + vertex(0, height); + endShape(CLOSE); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/Boundary.pde new file mode 100644 index 000000000..ebf6b04bf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/Boundary.pde @@ -0,0 +1,59 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class (now incorporates angle) + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_, float a) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.angle = a; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, it doesn't move so we don't have to ask the Body for location + void display() { + fill(0); + stroke(0); + strokeWeight(1); + rectMode(CENTER); + float a = b.getAngle(); + pushMatrix(); + translate(x,y); + rotate(-a); + rect(0,0,w,h); + popMatrix(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/CustomShape.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/CustomShape.pde new file mode 100644 index 000000000..9e0180a59 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/CustomShape.pde @@ -0,0 +1,90 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class CustomShape { + + // We need to keep track of a Body and a width and height + Body body; + + // Constructor + CustomShape(float x, float y) { + // Add the box to the box2d world + makeBody(new Vec2(x, y)); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height) { + killBody(); + return true; + } + return false; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + Fixture f = body.getFixtureList(); + PolygonShape ps = (PolygonShape) f.getShape(); + + + rectMode(CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(127); + stroke(0); + strokeWeight(2); + beginShape(); + //println(vertices.length); + // For every vertex, convert to pixel vector + for (int i = 0; i < ps.getVertexCount(); i++) { + Vec2 v = box2d.vectorWorldToPixels(ps.getVertex(i)); + vertex(v.x, v.y); + } + endShape(CLOSE); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center) { + + Vec2[] vertices = new Vec2[4]; + vertices[0] = box2d.vectorPixelsToWorld(new Vec2(-15, 25)); + vertices[1] = box2d.vectorPixelsToWorld(new Vec2(15, 0)); + vertices[2] = box2d.vectorPixelsToWorld(new Vec2(20, -15)); + vertices[3] = box2d.vectorPixelsToWorld(new Vec2(-10, -10)); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape ps = new PolygonShape(); + ps.set(vertices, vertices.length); + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + body.createFixture(ps, 1.0); + + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde new file mode 100644 index 000000000..145012993 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde @@ -0,0 +1,71 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of falling rectangles + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; +// A list for all of our rectangles +ArrayList polygons; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -20); + + // Create ArrayLists + polygons = new ArrayList(); + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(width/4,height-5,width/2-50,10,0)); + boundaries.add(new Boundary(3*width/4,height-50,width/2-50,10,0)); + boundaries.add(new Boundary(width-5,height/2,10,height,0)); + boundaries.add(new Boundary(5,height/2,10,height,0)); +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } + + // Display all the people + for (CustomShape cs: polygons) { + cs.display(); + } + + // people that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = polygons.size()-1; i >= 0; i--) { + CustomShape cs = polygons.get(i); + if (cs.done()) { + polygons.remove(i); + } + } +} + +void mousePressed() { + CustomShape cs = new CustomShape(mouseX,mouseY); + polygons.add(cs); +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/Boundary.pde new file mode 100644 index 000000000..afe2ab2f5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/Boundary.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class (now incorporates angle) + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_, float a) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.angle = a; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + strokeWeight(1); + rectMode(CENTER); + + float a = b.getAngle(); + + pushMatrix(); + translate(x,y); + rotate(-a); + rect(0,0,w,h); + popMatrix(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/Lollipop.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/Lollipop.pde new file mode 100644 index 000000000..65805e008 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/Lollipop.pde @@ -0,0 +1,88 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box +class Lollipop { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + float r; + + // Constructor + Lollipop(float x, float y) { + w = 8; + h = 24; + r = 8; + // Add the box to the box2d world + makeBody(new Vec2(x, y)); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+w*h) { + killBody(); + return true; + } + return false; + } + + // Drawing the lollipop + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(CENTER); + pushMatrix(); + translate(pos.x, pos.y); + rotate(-a); + fill(127); + stroke(0); + strokeWeight(2); + + rect(0,0,w,h); + ellipse(0, -h/2, r*2, r*2); + popMatrix(); + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center) { + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + CircleShape circle = new CircleShape(); + circle.m_radius = box2d.scalarPixelsToWorld(r); + Vec2 offset = new Vec2(0,-h/2); + offset = box2d.vectorPixelsToWorld(offset); + circle.m_p.set(offset.x,offset.y); + + PolygonShape ps = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + ps.setAsBox(box2dW, box2dH); + + body.createFixture(ps,1.0); + body.createFixture(circle, 1.0); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde new file mode 100644 index 000000000..4ec682f7e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde @@ -0,0 +1,71 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of falling rectangles + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; +// A list for all of our rectangles +ArrayList pops; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this,20); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0, -20); + + // Create ArrayLists + pops = new ArrayList(); + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(width/4,height-5,width/2-50,10,0)); + boundaries.add(new Boundary(3*width/4,height-50,width/2-50,10,0)); + boundaries.add(new Boundary(width-5,height/2,10,height,0)); + boundaries.add(new Boundary(5,height/2,10,height,0)); +} + +void draw() { + background(255); + + // We must always step through time! + if (mousePressed) box2d.step(); + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } + + // Display all the people + for (Lollipop p: pops) { + p.display(); + } + + // people that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + for (int i = pops.size()-1; i >= 0; i--) { + Lollipop p = pops.get(i); + if (p.done()) { + pops.remove(i); + } + } +} + +void mousePressed() { + Lollipop p = new Lollipop(mouseX,mouseY); + pops.add(p); +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Boundary.pde new file mode 100644 index 000000000..9a17026a1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Boundary.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde new file mode 100644 index 000000000..298cf690d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example demonstrating distance joints +// A bridge is formed by connected a series of particles with joints + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; + + +// A list for all of our rectangles +ArrayList pairs; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Create ArrayLists + pairs = new ArrayList(); + + boundaries = new ArrayList(); + + // Add a bunch of fixed boundaries + boundaries.add(new Boundary(width/4,height-5,width/2-50,10)); + boundaries.add(new Boundary(3*width/4,height-50,width/2-50,10)); + +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // When the mouse is clicked, add a new Box object + + // Display all the boxes + for (Pair p: pairs) { + p.display(); + } + + // Display all the boundaries + for (Boundary wall: boundaries) { + wall.display(); + } + + fill(0); + text("Click mouse to add connected particles.",10,20); +} + +void mousePressed() { + Pair p = new Pair(mouseX,mouseY); + pairs.add(p); +} + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Pair.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Pair.pde new file mode 100644 index 000000000..780a8e316 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Pair.pde @@ -0,0 +1,47 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Series of Particles connected with distance joints + +class Pair { + + Particle p1; + Particle p2; + + float len; + // Chain constructor + Pair(float x, float y) { + len = 32; + + p1 = new Particle(x,y); + p2 = new Particle(x+random(-1,1),y+random(-1,1)); + + DistanceJointDef djd = new DistanceJointDef(); + // Connection between previous particle and this one + djd.bodyA = p1.body; + djd.bodyB = p2.body; + // Equilibrium length + djd.length = box2d.scalarPixelsToWorld(len); + + // These properties affect how springy the joint is + djd.frequencyHz = 3; // Try a value less than 5 (0 for no elasticity) + djd.dampingRatio = 0.1; // Ranges between 0 and 1 (1 for no springiness) + + // Make the joint. Note we aren't storing a reference to the joint ourselves anywhere! + // We might need to someday, but for now it's ok + DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd); + } + + void display() { + Vec2 pos1 = box2d.getBodyPixelCoord(p1.body); + Vec2 pos2 = box2d.getBodyPixelCoord(p2.body); + stroke(0); + strokeWeight(2); + line(pos1.x,pos1.y,pos2.x,pos2.y); + + p1.display(); + p2.display(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Particle.pde new file mode 100644 index 000000000..ed3d34199 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/Particle.pde @@ -0,0 +1,76 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Particle(float x, float y) { + r = 8; + + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x,y); + bd.type = BodyType.DYNAMIC; + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + fill(127); + stroke(0); + strokeWeight(2); + ellipse(0,0,r*2,r*2); + // Let's add a line so we can see the rotation + line(0,0,r,0); + popMatrix(); + } + + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Box.pde new file mode 100644 index 000000000..acf4abdec --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Box.pde @@ -0,0 +1,72 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x, float y, float w_, float h_, boolean lock) { + w = w_; + h = h_; + + // Define and create the body + BodyDef bd = new BodyDef(); + bd.position.set(box2d.coordPixelsToWorld(new Vec2(x,y))); + if (lock) bd.type = BodyType.STATIC; + else bd.type = BodyType.DYNAMIC; + + body = box2d.createBody(bd); + + // Define the shape -- a (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5,5),random(2,5))); + body.setAngularVelocity(random(-5,5)); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x,pos.y); + rotate(-a); + fill(127); + stroke(0); + strokeWeight(2); + rect(0,0,w,h); + popMatrix(); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde new file mode 100644 index 000000000..676df2896 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde @@ -0,0 +1,87 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Example demonstrating revolute joint + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// An object to describe a Windmill (two bodies and one joint) +Windmill windmill; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Make the windmill at an x,y location + windmill = new Windmill(width/2,175); + + // Create the empty list + particles = new ArrayList(); + +} + +// Click the mouse to turn on or off the motor +void mousePressed() { + windmill.toggleMotor(); +} + +void draw() { + background(255); + + if (random(1) < 0.1) { + float sz = random(4,8); + particles.add(new Particle(random(width/2-100,width/2+100),-20,sz)); + } + + + // We must always step through time! + box2d.step(); + + // Look at all particles + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.display(); + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + if (p.done()) { + particles.remove(i); + } + } + + // Draw the windmill + windmill.display(); + + String status = "OFF"; + if (windmill.motorOn()) status = "ON"; + + fill(0); + text("Click mouse to toggle motor.\nMotor: " + status,10,height-30); + + +} + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Particle.pde new file mode 100644 index 000000000..89fb8b443 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Particle.pde @@ -0,0 +1,84 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x, y, r); + body.setUserData(this); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + + rotate(-a); + fill(127); + stroke(0); + strokeWeight(2); + ellipse(0, 0, r*2, r*2); + // Let's add a line so we can see the rotation + line(0, 0, r, 0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x, y); + bd.type = BodyType.DYNAMIC; + + body = box2d.world.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + + fd.density = 2.0; + fd.friction = 0.01; + fd.restitution = 0.3; // Restitution is bounciness + + body.createFixture(fd); + + // Give it a random initial velocity (and angular velocity) + //body.setLinearVelocity(new Vec2(random(-10f,10f),random(5f,10f))); + body.setAngularVelocity(random(-10, 10)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Windmill.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Windmill.pde new file mode 100644 index 000000000..5a819a81e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/Windmill.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Class to describe a fixed spinning object + +class Windmill { + + // Our object is two boxes and one joint + // Consider making the fixed box much smaller and not drawing it + RevoluteJoint joint; + Box box1; + Box box2; + + Windmill(float x, float y) { + + // Initialize locations of two boxes + box1 = new Box(x, y-20, 120, 10, false); + box2 = new Box(x, y, 10, 40, true); + + // Define joint as between two bodies + RevoluteJointDef rjd = new RevoluteJointDef(); + + rjd.initialize(box1.body, box2.body, box1.body.getWorldCenter()); + + // Turning on a motor (optional) + rjd.motorSpeed = PI*2; // how fast? + rjd.maxMotorTorque = 1000.0; // how powerful? + rjd.enableMotor = false; // is it on? + + // There are many other properties you can set for a Revolute joint + // For example, you can limit its angle between a minimum and a maximum + // See box2d manual for more + + + // Create the joint + joint = (RevoluteJoint) box2d.world.createJoint(rjd); + } + + // Turn the motor on or off + void toggleMotor() { + joint.enableMotor(!joint.isMotorEnabled()); + } + + boolean motorOn() { + return joint.isMotorEnabled(); + } + + + void display() { + box2.display(); + box1.display(); + + // Draw anchor just for debug + Vec2 anchor = box2d.coordWorldToPixels(box1.body.getWorldCenter()); + fill(0); + noStroke(); + ellipse(anchor.x, anchor.y, 8, 8); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Boundary.pde new file mode 100644 index 000000000..61491af26 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Boundary.pde @@ -0,0 +1,62 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class (now incorporates angle) + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_, float a) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.angle = a; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + noFill(); + stroke(127); + fill(127); + strokeWeight(1); + rectMode(CENTER); + + float a = b.getAngle(); + + pushMatrix(); + translate(x,y); + rotate(-a); + rect(0,0,w,h); + popMatrix(); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Box.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Box.pde new file mode 100644 index 000000000..db935b7a4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Box.pde @@ -0,0 +1,88 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A rectangular box + +class Box { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + // Constructor + Box(float x_, float y_) { + float x = x_; + float y = y_; + w = 24; + h = 24; + // Add the box to the box2d world + makeBody(new Vec2(x,y),w,h); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + boolean contains(float x, float y) { + Vec2 worldPoint = box2d.coordPixelsToWorld(x, y); + Fixture f = body.getFixtureList(); + boolean inside = f.testPoint(worldPoint); + return inside; + } + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(PConstants.CENTER); + pushMatrix(); + translate(pos.x,pos.y); + rotate(a); + fill(127); + stroke(0); + strokeWeight(2); + rect(0,0,w,h); + popMatrix(); + } + + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_) { + // Define and create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + body = box2d.createBody(bd); + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + body.createFixture(fd); + //body.setMassFromShapes(); + + // Give it some initial random velocity + body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); + body.setAngularVelocity(random(-5, 5)); + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde new file mode 100644 index 000000000..b9fe8f72c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde @@ -0,0 +1,83 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with the mouse (by attaching a spring) + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +// A list we'll use to track fixed objects +ArrayList boundaries; + +// Just a single box this time +Box box; + +// The Spring that will attach to the box from the mouse +Spring spring; + +void setup() { + size(800,200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Make the box + box = new Box(width/2,height/2); + + // Make the spring (it doesn't really get initialized until the mouse is clicked) + spring = new Spring(); + + // Add a bunch of fixed boundaries + boundaries = new ArrayList(); + boundaries.add(new Boundary(width/2,height-5,width,10,0)); + boundaries.add(new Boundary(width/2,5,width,10,0)); + boundaries.add(new Boundary(width-5,height/2,10,height,0)); + boundaries.add(new Boundary(5,height/2,10,height,0)); +} + +// When the mouse is released we're done with the spring +void mouseReleased() { + spring.destroy(); +} + +// When the mouse is pressed we. . . +void mousePressed() { + // Check to see if the mouse was clicked on the box + if (box.contains(mouseX, mouseY)) { + // And if so, bind the mouse location to the box with a spring + spring.bind(mouseX,mouseY,box); + } +} + +void draw() { + background(255); + + // We must always step through time! + box2d.step(); + + // Always alert the spring to the new mouse location + spring.update(mouseX,mouseY); + + // Draw the boundaries + for (int i = 0; i < boundaries.size(); i++) { + Boundary wall = (Boundary) boundaries.get(i); + wall.display(); + } + + // Draw the box + box.display(); + // Draw the spring (it only appears when active) + spring.display(); +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Spring.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Spring.pde new file mode 100644 index 000000000..4daa97765 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/Spring.pde @@ -0,0 +1,77 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Class to describe the spring joint (displayed as a line) + +class Spring { + + // This is the box2d object we need to create + MouseJoint mouseJoint; + + Spring() { + // At first it doesn't exist + mouseJoint = null; + } + + // If it exists we set its target to the mouse location + void update(float x, float y) { + if (mouseJoint != null) { + // Always convert to world coordinates! + Vec2 mouseWorld = box2d.coordPixelsToWorld(x,y); + mouseJoint.setTarget(mouseWorld); + } + } + + void display() { + if (mouseJoint != null) { + // We can get the two anchor points + Vec2 v1 = new Vec2(0,0); + mouseJoint.getAnchorA(v1); + Vec2 v2 = new Vec2(0,0); + mouseJoint.getAnchorB(v2); + // Convert them to screen coordinates + v1 = box2d.coordWorldToPixels(v1); + v2 = box2d.coordWorldToPixels(v2); + // And just draw a line + stroke(0); + strokeWeight(1); + line(v1.x,v1.y,v2.x,v2.y); + } + } + + + // This is the key function where + // we attach the spring to an x,y location + // and the Box object's location + void bind(float x, float y, Box box) { + // Define the joint + MouseJointDef md = new MouseJointDef(); + // Body A is just a fake ground body for simplicity (there isn't anything at the mouse) + md.bodyA = box2d.getGroundBody(); + // Body 2 is the box's boxy + md.bodyB = box.body; + // Get the mouse location in world coordinates + Vec2 mp = box2d.coordPixelsToWorld(x,y); + // And that's the target + md.target.set(mp); + // Some stuff about how strong and bouncy the spring should be + md.maxForce = 1000.0 * box.body.m_mass; + md.frequencyHz = 5.0; + md.dampingRatio = 0.9; + + // Make the joint! + mouseJoint = (MouseJoint) box2d.world.createJoint(md); + } + + void destroy() { + // We can get rid of the joint when the mouse is released + if (mouseJoint != null) { + box2d.world.destroyJoint(mouseJoint); + mouseJoint = null; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/Boundary.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/Boundary.pde new file mode 100644 index 000000000..ff6226252 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/Boundary.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A fixed boundary class + +class Boundary { + + // A boundary is a simple rectangle with x,y,width,and height + float x; + float y; + float w; + float h; + + // But we also have to make a body for box2d to know about it + Body b; + + Boundary(float x_,float y_, float w_, float h_) { + x = x_; + y = y_; + w = w_; + h = h_; + + // Define the polygon + PolygonShape sd = new PolygonShape(); + // Figure out the box2d coordinates + float box2dW = box2d.scalarPixelsToWorld(w/2); + float box2dH = box2d.scalarPixelsToWorld(h/2); + // We're just a box + sd.setAsBox(box2dW, box2dH); + + + // Create the body + BodyDef bd = new BodyDef(); + bd.type = BodyType.STATIC; + bd.position.set(box2d.coordPixelsToWorld(x,y)); + b = box2d.createBody(bd); + + // Attached the shape to the body using a Fixture + b.createFixture(sd,1); + + b.setUserData(this); + } + + // Draw the boundary, if it were at an angle we'd have to do something fancier + void display() { + fill(0); + stroke(0); + rectMode(CENTER); + rect(x,y,w,h); + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde new file mode 100644 index 000000000..18132585c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde @@ -0,0 +1,108 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Basic example of controlling an object with our own motion (by attaching a MouseJoint) +// Also demonstrates how to know which object was hit + +import pbox2d.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.joints.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.collision.shapes.Shape; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; +import org.jbox2d.dynamics.contacts.*; + +// A reference to our box2d world +PBox2D box2d; + +// An ArrayList of particles that will fall on the surface +ArrayList particles; + +Boundary wall; + +void setup() { + size(800, 200); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + + // Turn on collision listening! + box2d.listenForCollisions(); + + // Create the empty list + particles = new ArrayList(); + + wall = new Boundary(width/2, height-5, width, 10); +} + +void draw() { + background(255); + + if (random(1) < 0.1) { + float sz = random(4, 8); + particles.add(new Particle(random(width), 20, sz)); + } + + + // We must always step through time! + box2d.step(); + + // Look at all particles + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.display(); + // Particles that leave the screen, we delete them + // (note they have to be deleted from both the box2d world and our list + if (p.done()) { + particles.remove(i); + } + } + + wall.display(); +} + + +// Collision event functions! +void beginContact(Contact cp) { + // Get both fixtures + Fixture f1 = cp.getFixtureA(); + Fixture f2 = cp.getFixtureB(); + // Get both bodies + Body b1 = f1.getBody(); + Body b2 = f2.getBody(); + + // Get our objects that reference these bodies + Object o1 = b1.getUserData(); + Object o2 = b2.getUserData(); + + if (o1.getClass() == Particle.class && o2.getClass() == Particle.class) { + Particle p1 = (Particle) o1; + p1.change(); + Particle p2 = (Particle) o2; + p2.change(); + } + +} + +// Objects stop touching each other +void endContact(Contact cp) { +} + + + + + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/Particle.pde new file mode 100644 index 000000000..6d3bf38d5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/Particle.pde @@ -0,0 +1,90 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A circular particle + +class Particle { + + // We need to keep track of a Body and a radius + Body body; + float r; + + color col; + + Particle(float x, float y, float r_) { + r = r_; + // This function puts the particle in the Box2d world + makeBody(x, y, r); + body.setUserData(this); + col = color(127); + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + // Change color when hit + void change() { + col = color(255, 0, 0); + } + + // Is the particle ready for deletion? + boolean done() { + // Let's find the screen position of the particle + Vec2 pos = box2d.getBodyPixelCoord(body); + // Is it off the bottom of the screen? + if (pos.y > height+r*2) { + killBody(); + return true; + } + return false; + } + + + // + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + // Get its angle of rotation + float a = body.getAngle(); + pushMatrix(); + translate(pos.x, pos.y); + rotate(a); + fill(col); + stroke(0); + strokeWeight(2); + ellipse(0, 0, r*2, r*2); + // Let's add a line so we can see the rotation + line(0, 0, r, 0); + popMatrix(); + } + + // Here's our function that adds the particle to the Box2D world + void makeBody(float x, float y, float r) { + // Define a body + BodyDef bd = new BodyDef(); + // Set its position + bd.position = box2d.coordPixelsToWorld(x, y); + bd.type = BodyType.DYNAMIC; + body = box2d.createBody(bd); + + // Make the body's shape a circle + CircleShape cs = new CircleShape(); + cs.m_radius = box2d.scalarPixelsToWorld(r); + + FixtureDef fd = new FixtureDef(); + fd.shape = cs; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.01; + fd.restitution = 0.3; + + // Attach fixture to body + body.createFixture(fd); + + body.setAngularVelocity(random(-10, 10)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/VectorStuff/VectorStuff.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/VectorStuff/VectorStuff.pde new file mode 100644 index 000000000..49345575d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/VectorStuff/VectorStuff.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Just demo-ing the basics of Vec2 vs. PVector + +import org.jbox2d.common.*; + +void setup() { + size(400,300); +// PVector a = new PVector(1,-1); +// PVector b = new PVector(3,4); +// a.add(b); +// +// PVector a = new PVector(1,-1); +// PVector b = new PVector(3,4); +// PVector c = PVector.add(a,b); +// +// Vec2 a = new Vec2(1,-1); +// Vec2 b = new Vec2(3,4); +// a.addLocal(b); +// +// Vec2 a = new Vec2(1,-1); +// Vec2 b = new Vec2(3,4); +// Vec2 c = a.add(b); +// +// PVector a = new PVector(1,-1); +// float n = 5; +// a.mult(n); +// +// PVector a = new PVector(1,-1); +// float n = 5; +// PVector c = PVector.mult(a,n); +// +// Vec2 a = new Vec2(1,-1); +// float n = 5; +// a.mulLocal(n); +// +// Vec2 a = new Vec2(1,-1); +// float n = 5; +// Vec2 c = a.mul(n); +// +// PVector a = new PVector(1,-1); +// float m = a.mag(); +// a.normalize(); + + Vec2 a = new Vec2(1,-1); + float m = a.length(); + a.normalize(); + println(a.x + "," + a.y); +} + +void draw() { + noLoop(); +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/readme.txt b/java/examples/Books/Nature of Code/chp5_physicslibraries/readme.txt new file mode 100644 index 000000000..99d3a27ad --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/readme.txt @@ -0,0 +1,3 @@ +For the box2d examples you will need PBox2D! + +https://github.com/shiffman/PBox2D \ No newline at end of file diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Blanket.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Blanket.pde new file mode 100644 index 000000000..1efcdb2ef --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Blanket.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Blanket { + ArrayList particles; + ArrayList springs; + + Blanket() { + particles = new ArrayList(); + springs = new ArrayList(); + + int w = 20; + int h = 20; + + float len = 10; + float strength = 0.125; + + for(int y=0; y< h; y++) { + for(int x=0; x < w; x++) { + + Particle p = new Particle(new Vec2D(width/2+x*len-w*len/2,y*len)); + physics.addParticle(p); + particles.add(p); + + if (x > 0) { + Particle previous = particles.get(particles.size()-2); + Connection c = new Connection(p,previous,len,strength); + physics.addSpring(c); + springs.add(c); + } + + if (y > 0) { + Particle above = particles.get(particles.size()-w-1); + Connection c=new Connection(p,above,len,strength); + physics.addSpring(c); + springs.add(c); + } + } + } + + Particle topleft= particles.get(0); + topleft.lock(); + + Particle topright = particles.get(w-1); + topright.lock(); + } + + void display() { + for (Connection c : springs) { + c.display(); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Connection.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Connection.pde new file mode 100644 index 000000000..bbbe2655c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Connection.pde @@ -0,0 +1,15 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Connection extends VerletSpring2D { + Connection(Particle p1, Particle p2, float len, float strength) { + super(p1,p2,len,strength); + } + + void display() { + stroke(0); + line(a.x,a.y,b.x,b.y); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde new file mode 100644 index 000000000..c41ee1126 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +/** + * This example is adapted from Karsten Schmidt's SoftBodySquare example + */ + +/*

Softbody square demo is showing how to create a 2D square mesh out of + * verlet particles and make it stable enough to avoid total structural + * deformation by including an inner skeleton.

+ * + *

Usage: move mouse to drag/deform the square

+ */ + +/* + * Copyright (c) 2008-2009 Karsten Schmidt + * + * This demo & library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * http://creativecommons.org/licenses/LGPL/2.1/ + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +import toxi.physics2d.behaviors.*; +import toxi.physics2d.*; + +import toxi.geom.*; +import toxi.math.*; + +VerletPhysics2D physics; + +Blanket b; + + +void setup() { + size(800,240); + physics=new VerletPhysics2D(); + physics.addBehavior(new GravityBehavior(new Vec2D(0,0.1))); + + b = new Blanket(); +} + +void draw() { + + background(255); + + physics.update(); + + b.display(); +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Particle.pde new file mode 100644 index 000000000..c4fef5474 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Particle.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Notice how we are using inheritance here! +// We could have just stored a reference to a VerletParticle object +// inside the Particle class, but inheritance is a nice alternative + +class Particle extends VerletParticle2D { + + Particle(Vec2D loc) { + super(loc); + } + + // All we're doing really is adding a display() function to a VerletParticle + void display() { + fill(175); + stroke(0); + ellipse(x,y,16,16); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Cluster.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Cluster.pde new file mode 100644 index 000000000..db0cfe2c2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Cluster.pde @@ -0,0 +1,98 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Force directed graph +// Heavily based on: http://code.google.com/p/fidgen/ + +class Cluster { + + // A cluster is a grouping of nodes + ArrayList nodes; + + float diameter; + + // We initialize a Cluster with a number of nodes, a diameter, and centerpoint + Cluster(int n, float d, Vec2D center) { + + // Initialize the ArrayList + nodes = new ArrayList(); + + // Set the diameter + diameter = d; + + // Create the nodes + for (int i = 0; i < n; i++) { + // We can't put them right on top of each other + nodes.add(new Node(center.add(Vec2D.randomVector()))); + } + + // Connect all the nodes with a Spring + for (int i = 1; i < nodes.size(); i++) { + VerletParticle2D pi = (VerletParticle2D) nodes.get(i); + for (int j = 0; j < i; j++) { + VerletParticle2D pj = (VerletParticle2D) nodes.get(j); + // A Spring needs two particles, a resting length, and a strength + physics.addSpring(new VerletSpring2D(pi,pj,diameter,0.01)); + } + } + } + + void display() { + // Show all the nodes + for (int i = 0; i < nodes.size(); i++) { + Node n = (Node) nodes.get(i); + n.display(); + } + } + + // This functons connects one cluster to another + // Each point of one cluster connects to each point of the other cluster + // The connection is a "VerletMinDistanceSpring" + // A VerletMinDistanceSpring is a string which only enforces its rest length if the + // current distance is less than its rest length. This is handy if you just want to + // ensure objects are at least a certain distance from each other, but don't + // care if it's bigger than the enforced minimum. + void connect(Cluster other) { + ArrayList otherNodes = other.getNodes(); + for (int i = 0; i < nodes.size(); i++) { + VerletParticle2D pi = (VerletParticle2D) nodes.get(i); + for (int j = 0; j < otherNodes.size(); j++) { + VerletParticle2D pj = (VerletParticle2D) otherNodes.get(j); + // Create the spring + physics.addSpring(new VerletMinDistanceSpring2D(pi,pj,(diameter+other.diameter)*0.5,0.05)); + } + } + } + + + // Draw all the internal connections + void showConnections() { + stroke(0,150); + for (int i = 0; i < nodes.size(); i++) { + VerletParticle2D pi = (VerletParticle2D) nodes.get(i); + for (int j = i+1; j < nodes.size(); j++) { + VerletParticle2D pj = (VerletParticle2D) nodes.get(j); + line(pi.x,pi.y,pj.x,pj.y); + } + } + } + + // Draw all the connections between this Cluster and another Cluster + void showConnections(Cluster other) { + stroke(0,50); + strokeWeight(2); + ArrayList otherNodes = other.getNodes(); + for (int i = 0; i < nodes.size(); i++) { + VerletParticle2D pi = (VerletParticle2D) nodes.get(i); + for (int j = 0; j < otherNodes.size(); j++) { + VerletParticle2D pj = (VerletParticle2D) otherNodes.get(j); + line(pi.x,pi.y,pj.x,pj.y); + } + } + } + + ArrayList getNodes() { + return nodes; + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde new file mode 100644 index 000000000..3cde75511 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde @@ -0,0 +1,133 @@ +/** + *

Force directed graph, + * heavily based on: fid.gen
+ * The Nature of Code
+ * Spring 2010

+ */ + +/* + * Copyright (c) 2010 Daniel Schiffmann + * + * This demo & library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * http://creativecommons.org/licenses/LGPL/2.1/ + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import toxi.geom.*; +import toxi.physics2d.*; +import toxi.physics2d.behaviors.*; + +// Reference to physics world +VerletPhysics2D physics; + +// A list of cluster objects +ArrayList clusters; + +// Boolean that indicates whether we draw connections or not +boolean showPhysics = true; +boolean showParticles = true; + +// Font +PFont f; + +void setup() { + size(800,300); + f = createFont("Georgia",12,true); + + // Initialize the physics + physics=new VerletPhysics2D(); + physics.setWorldBounds(new Rect(10,10,width-20,height-20)); + + // Spawn a new random graph + newGraph(); + +} + +// Spawn a new random graph +void newGraph() { + + // Clear physics + physics.clear(); + + // Create new ArrayList (clears old one) + clusters = new ArrayList(); + + // Create 8 random clusters + for (int i = 0; i < 8; i++) { + Vec2D center = new Vec2D(width/2,height/2); + clusters.add(new Cluster((int) random(3,8),random(20,100),center)); + } + + // All clusters connect to all clusters + for (int i = 0; i < clusters.size(); i++) { + for (int j = i+1; j < clusters.size(); j++) { + Cluster ci = (Cluster) clusters.get(i); + Cluster cj = (Cluster) clusters.get(j); + ci.connect(cj); + } + } + +} + +void draw() { + + // Update the physics world + physics.update(); + + background(255); + + // Display all points + if (showParticles) { + for (int i = 0; i < clusters.size(); i++) { + Cluster c = (Cluster) clusters.get(i); + c.display(); + } + } + + // If we want to see the physics + if (showPhysics) { + for (int i = 0; i < clusters.size(); i++) { + // Cluster internal connections + Cluster ci = (Cluster) clusters.get(i); + ci.showConnections(); + + // Cluster connections to other clusters + for (int j = i+1; j < clusters.size(); j++) { + Cluster cj = (Cluster) clusters.get(j); + ci.showConnections(cj); + } + } + } + + // Instructions + fill(0); + textFont(f); + text("'p' to display or hide particles\n'c' to display or hide connections\n'n' for new graph",10,20); +} + +// Key press commands +void keyPressed() { + if (key == 'c') { + showPhysics = !showPhysics; + if (!showPhysics) showParticles = true; + } + else if (key == 'p') { + showParticles = !showParticles; + if (!showParticles) showPhysics = true; + } + else if (key == 'n') { + newGraph(); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Node.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Node.pde new file mode 100644 index 000000000..54dc835b4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Node.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Force directed graph +// Heavily based on: http://code.google.com/p/fidgen/ + +// Notice how we are using inheritance here! +// We could have just stored a reference to a VerletParticle object +// inside the Node class, but inheritance is a nice alternative + +class Node extends VerletParticle2D { + + Node(Vec2D pos) { + super(pos); + } + + // All we're doing really is adding a display() function to a VerletParticle + void display() { + fill(0,150); + stroke(0); + strokeWeight(2); + ellipse(x,y,16,16); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde new file mode 100644 index 000000000..14ab4dd7b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Toxiclibs Spring + +import toxi.physics2d.*; +import toxi.physics2d.behaviors.*; +import toxi.geom.*; + +// Reference to physics world +VerletPhysics2D physics; + +Particle p1; +Particle p2; + +void setup() { + size(800,200); + frameRate(30); + + // Initialize the physics + physics=new VerletPhysics2D(); + physics.addBehavior(new GravityBehavior(new Vec2D(0,0.5))); + + // Set the world's bounding box + physics.setWorldBounds(new Rect(0,0,width,height)); + + // Make two particles + p1 = new Particle(new Vec2D(width/2,20)); + p2 = new Particle(new Vec2D(width,180)); + // Lock one in place + p1.lock(); + + // Make a spring connecting both Particles + VerletSpring2D spring=new VerletSpring2D(p1,p2,80,0.01); + + // Anything we make, we have to add into the physics world + physics.addParticle(p1); + physics.addParticle(p2); + physics.addSpring(spring); +} + +void draw() { + + // Update the physics world + physics.update(); + + background(255); + + // Draw a line between the particles + stroke(0); + strokeWeight(2); + line(p1.x,p1.y,p2.x,p2.y); + + // Display the particles + p1.display(); + p2.display(); + + // Move the second one according to the mouse + if (mousePressed) { + p2.lock(); + p2.x = mouseX; + p2.y = mouseY; + p2.unlock(); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/Particle.pde new file mode 100644 index 000000000..06bb533dc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/Particle.pde @@ -0,0 +1,22 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Notice how we are using inheritance here! + +// We could have just stored a reference to a VerletParticle object +// inside the Particle class, but inheritance is a nice alternative + +class Particle extends VerletParticle2D { + + Particle(Vec2D loc) { + super(loc); + } + + // All we're doing really is adding a display() function to a VerletParticle + void display() { + fill(127); + stroke(0); + strokeWeight(2); + ellipse(x,y,32,32); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/Chain.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/Chain.pde new file mode 100644 index 000000000..91b68c9b6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/Chain.pde @@ -0,0 +1,103 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A soft pendulum (series of connected springs) + +class Chain { + + // Chain properties + float totalLength; // How long + int numPoints; // How many points + float strength; // Strength of springs + float radius; // Radius of ball at tail + + // This list is redundant since we can ask for physics.particles, but in case we have many of these + // it's a convenient to keep track of our own list + ArrayList particles; + + // Let's keep an extra reference to the tail particle + // This is just the last particle in the ArrayList + Particle tail; + + // Some variables for mouse dragging + PVector offset = new PVector(); + boolean dragged = false; + + // Chain constructor + Chain(float l, int n, float r, float s) { + particles = new ArrayList(); + + totalLength = l; + numPoints = n; + radius = r; + strength = s; + + float len = totalLength / numPoints; + + // Here is the real work, go through and add particles to the chain itself + for(int i=0; i < numPoints; i++) { + // Make a new particle with an initial starting location + Particle particle=new Particle(width/2,i*len); + + // Redundancy, we put the particles both in physics and in our own ArrayList + physics.addParticle(particle); + particles.add(particle); + + // Connect the particles with a Spring (except for the head) + if (i != 0) { + Particle previous = particles.get(i-1); + VerletSpring2D spring = new VerletSpring2D(particle,previous,len,strength); + // Add the spring to the physics world + physics.addSpring(spring); + } + } + + // Keep the top fixed + Particle head=particles.get(0); + head.lock(); + + // Store reference to the tail + tail = particles.get(numPoints-1); + tail.radius = radius; + } + + // Check if a point is within the ball at the end of the chain + // If so, set dragged = true; + void contains(int x, int y) { + float d = dist(x,y,tail.x,tail.y); + if (d < radius) { + offset.x = tail.x - x; + offset.y = tail.y - y; + tail.lock(); + dragged = true; + } + } + + // Release the ball + void release() { + tail.unlock(); + dragged = false; + } + + // Update tail location if being dragged + void updateTail(int x, int y) { + if (dragged) { + tail.set(x+offset.x,y+offset.y); + } + } + + // Draw the chain + void display() { + // Draw line connecting all points + beginShape(); + stroke(0); + strokeWeight(2); + noFill(); + for (Particle p : particles) { + vertex(p.x,p.y); + } + endShape(); + tail.display(); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde new file mode 100644 index 000000000..cab6ace9d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde @@ -0,0 +1,68 @@ +/** + *

A soft pendulum (series of connected springs)
+ * The Nature of Code
+ * Spring 2010

+ */ + +/* + * Copyright (c) 2010 Daniel Shiffmann + * + * This demo & library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * http://creativecommons.org/licenses/LGPL/2.1/ + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import toxi.physics2d.*; +import toxi.physics2d.behaviors.*; +import toxi.geom.*; + +// Reference to physics "world" (2D) +VerletPhysics2D physics; + +// Our "Chain" object +Chain chain; + +void setup() { + size(800, 200); + // Initialize the physics world + physics=new VerletPhysics2D(); + physics.addBehavior(new GravityBehavior(new Vec2D(0, 0.1))); + physics.setWorldBounds(new Rect(0, 0, width, height)); + + // Initialize the chain + chain = new Chain(180, 20, 16, 0.2); +} + +void draw() { + background(255); + + // Update physics + physics.update(); + // Update chain's tail according to mouse location + chain.updateTail(mouseX, mouseY); + // Display chain + chain.display(); +} + +void mousePressed() { + // Check to see if we're grabbing the chain + chain.contains(mouseX, mouseY); +} + +void mouseReleased() { + // Release the chain + chain.release(); +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/Particle.pde new file mode 100644 index 000000000..99ca7dac3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/Particle.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Notice how we are using inheritance here! +// We could have just stored a reference to a VerletParticle object +// inside the Particle class, but inheritance is a nice alternative + +class Particle extends VerletParticle2D { + + float radius = 4; // Adding a radius for each particle + + Particle(float x, float y) { + super(x,y); + } + + // All we're doing really is adding a display() function to a VerletParticle + void display() { + fill(127); + stroke(0); + strokeWeight(2); + ellipse(x,y,radius*2,radius*2); + } +} diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/Cluster.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/Cluster.pde new file mode 100644 index 000000000..241520f2b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/Cluster.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// +// Spring 2010 +// Toxiclibs example: http://toxiclibs.org/ + +// Force directed graph +// Heavily based on: http://code.google.com/p/fidgen/ + +class Cluster { + + // A cluster is a grouping of nodes + ArrayList nodes; + + float diameter; + + // We initialize a Cluster with a number of nodes, a diameter, and centerpoint + Cluster(int n, float d, Vec2D center) { + + // Initialize the ArrayList + nodes = new ArrayList(); + + // Set the diameter + diameter = d; + + // Create the nodes + for (int i = 0; i < n; i++) { + // We can't put them right on top of each other + nodes.add(new Node(center.add(Vec2D.randomVector()))); + } + + // Connect all the nodes with a Spring + for (int i = 0; i < nodes.size()-1; i++) { + VerletParticle2D ni = nodes.get(i); + for (int j = i+1; j < nodes.size(); j++) { + VerletParticle2D nj = nodes.get(j); + // A Spring needs two particles, a resting length, and a strength + physics.addSpring(new VerletSpring2D(ni, nj, diameter, 0.01)); + } + } + } + + void display() { + // Show all the nodes + for (Node n : nodes) { + n.display(); + } + } + + + // Draw all the internal connections + void showConnections() { + stroke(0, 150); + strokeWeight(2); + for (int i = 0; i < nodes.size()-1; i++) { + VerletParticle2D pi = (VerletParticle2D) nodes.get(i); + for (int j = i+1; j < nodes.size(); j++) { + VerletParticle2D pj = (VerletParticle2D) nodes.get(j); + + line(pi.x, pi.y, pj.x, pj.y); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde new file mode 100644 index 000000000..46cb7eddc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde @@ -0,0 +1,75 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Force directed graph, +// heavily based on: http://code.google.com/p/fidgen/ + +import toxi.geom.*; +import toxi.physics2d.*; + +// Reference to physics world +VerletPhysics2D physics; + +// A list of cluster objects +Cluster cluster; + +// Boolean that indicates whether we draw connections or not +boolean showPhysics = true; +boolean showParticles = true; + +// Font +PFont f; + +void setup() { + size(800, 200); + frameRate(30); + f = createFont("Georgia", 12, true); + + // Initialize the physics + physics=new VerletPhysics2D(); + physics.setWorldBounds(new Rect(10, 10, width-20, height-20)); + + // Spawn a new random graph + cluster = new Cluster(8, 100, new Vec2D(width/2, height/2)); +} + +void draw() { + + // Update the physics world + physics.update(); + + background(255); + + // Display all points + if (showParticles) { + cluster.display(); + } + + // If we want to see the physics + if (showPhysics) { + cluster.showConnections(); + } + + // Instructions + fill(0); + textFont(f); + text("'p' to display or hide particles\n'c' to display or hide connections\n'n' for new graph",10,20); +} + +// Key press commands +void keyPressed() { + if (key == 'c') { + showPhysics = !showPhysics; + if (!showPhysics) showParticles = true; + } + else if (key == 'p') { + showParticles = !showParticles; + if (!showParticles) showPhysics = true; + } + else if (key == 'n') { + physics.clear(); + cluster = new Cluster(int(random(2, 20)), random(10, width/2), new Vec2D(width/2, height/2)); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/Node.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/Node.pde new file mode 100644 index 000000000..6fe3b5144 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/Node.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// +// Spring 2010 +// Toxiclibs example: http://toxiclibs.org/ + +// Force directed graph +// Heavily based on: http://code.google.com/p/fidgen/ + +// Notice how we are using inheritance here! +// We could have just stored a reference to a VerletParticle object +// inside the Node class, but inheritance is a nice alternative + +class Node extends VerletParticle2D { + + Node(Vec2D pos) { + super(pos); + } + + // All we're doing really is adding a display() function to a VerletParticle + void display() { + fill(0,150); + stroke(0); + strokeWeight(2); + ellipse(x,y,16,16); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/Attractor.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/Attractor.pde new file mode 100644 index 000000000..69e7ecb1d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/Attractor.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Attractor extends VerletParticle2D { + + float r; + + Attractor (Vec2D loc) { + super (loc); + r = 24; + physics.addParticle(this); + physics.addBehavior(new AttractionBehavior(this, width, 0.1)); + } + + void display () { + fill(0); + ellipse (x, y, r*2, r*2); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde new file mode 100644 index 000000000..79691843b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde @@ -0,0 +1,40 @@ +import toxi.geom.*; +import toxi.physics2d.*; +import toxi.physics2d.behaviors.*; + +ArrayList particles; +Attractor attractor; + +VerletPhysics2D physics; + +void setup () { + size (800, 200); + physics = new VerletPhysics2D (); + physics.setDrag (0.01); + + particles = new ArrayList(); + for (int i = 0; i < 50; i++) { + particles.add(new Particle(new Vec2D(random(width),random(height)))); + } + + attractor = new Attractor(new Vec2D(width/2,height/2)); +} + + +void draw () { + background (255); + physics.update (); + + attractor.display(); + for (Particle p: particles) { + p.display(); + } + + if (mousePressed) { + attractor.lock(); + attractor.set(mouseX,mouseY); + } else { + attractor.unlock(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/Particle.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/Particle.pde new file mode 100644 index 000000000..8096405d4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/Particle.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// class Spore extends the class "VerletParticle2D" +class Particle extends VerletParticle2D { + + float r; + + Particle (Vec2D loc) { + super(loc); + r = 8; + physics.addParticle(this); + physics.addBehavior(new AttractionBehavior(this, r*4, -1)); + } + + void display () { + fill (127); + stroke (0); + strokeWeight(2); + ellipse (x, y, r*2, r*2); + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Cohesion/Cohesion.pde b/java/examples/Books/Nature of Code/chp6_agents/Cohesion/Cohesion.pde new file mode 100644 index 000000000..b1244cbe1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Cohesion/Cohesion.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Separation + +// Via Reynolds: http://www.red3d.com/cwr/steer/ + +// A list of vehicles +ArrayList vehicles; + +void setup() { + size(640,360); + // We are now making random vehicles and storing them in an ArrayList + vehicles = new ArrayList(); + for (int i = 0; i < 100; i++) { + vehicles.add(new Vehicle(random(width),random(height))); + } +} + +void draw() { + background(255); + + for (Vehicle v : vehicles) { + // Path following and separation are worked on in this function + v.cohesion(vehicles); + // Call the generic run method (update, borders, display, etc.) + v.update(); + v.borders(); + v.display(); + } + + // Instructions + fill(0); + text("Drag the mouse to generate new vehicles.",10,height-16); +} + + +void mouseDragged() { + vehicles.add(new Vehicle(mouseX,mouseY)); + + if (vehicles.size() > 200) { + vehicles.remove(0); + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Cohesion/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/Cohesion/Vehicle.pde new file mode 100644 index 000000000..e0c072416 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Cohesion/Vehicle.pde @@ -0,0 +1,101 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Separation + +// Vehicle class + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle(float x, float y) { + location = new PVector(x, y); + r = 12; + maxspeed = 3; + maxforce = 0.2; + acceleration = new PVector(0, 0); + velocity = new PVector(0, 0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // Cohesion + // Method checks for nearby vehicles and steers away + void cohesion (ArrayList vehicles) { + float desiredseparation = r*2; + PVector sum = new PVector(); + int count = 0; + // For every boid in the system, check if it's too close + for (Vehicle other : vehicles) { + float d = PVector.dist(location, other.location); + // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) + if (d > desiredseparation) { + // Calculate vector pointing away from neighbor + PVector diff = PVector.sub(location, other.location); + diff.normalize(); + diff.mult(-d); // Weight by distance + sum.add(diff); + count++; // Keep track of how many + } + } + // Average -- divide by how many + if (count > 0) { + sum.div(count); + // Our desired vector is the average scaled to maximum speed + sum.normalize(); + sum.mult(maxspeed); + // Implement Reynolds: Steering = Desired - Velocity + PVector steer = PVector.sub(sum, velocity); + steer.limit(maxforce); + applyForce(steer); + } + } + + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void display() { + fill(175); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + ellipse(0, 0, r, r); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } +} + + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/CrowdPathFollowing.pde b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/CrowdPathFollowing.pde new file mode 100644 index 000000000..201905f78 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/CrowdPathFollowing.pde @@ -0,0 +1,76 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Crowd Path Following +// Via Reynolds: http://www.red3d.com/cwr/steer/CrowdPath.html + +// Using this variable to decide whether to draw all the stuff +boolean debug = false; + + +// A path object (series of connected points) +Path path; + +// Two vehicles +ArrayList vehicles; + +void setup() { + size(640,360); + // Call a function to generate new Path object + newPath(); + + // We are now making random vehicles and storing them in an ArrayList + vehicles = new ArrayList(); + for (int i = 0; i < 120; i++) { + newVehicle(random(width),random(height)); + } +} + +void draw() { + background(255); + // Display the path + path.display(); + + for (Vehicle v : vehicles) { + // Path following and separation are worked on in this function + v.applyBehaviors(vehicles,path); + // Call the generic run method (update, borders, display, etc.) + v.run(); + } + + // Instructions + fill(0); + text("Hit 'd' to toggle debugging lines. Click the mouse to generate new vehicles.",10,height-16); +} + +void newPath() { + // A path is a series of connected points + // A more sophisticated path might be a curve + path = new Path(); + float offset = 60; + path.addPoint(offset,offset); + path.addPoint(width-offset,offset); + path.addPoint(width-offset,height-offset); + path.addPoint(width/2,height-offset*3); + path.addPoint(offset,height-offset); +} + +void newVehicle(float x, float y) { + float maxspeed = random(2,4); + float maxforce = 0.3; + vehicles.add(new Vehicle(new PVector(x,y),maxspeed,maxforce)); +} + +void keyPressed() { + if (key == 'd') { + debug = !debug; + } +} + +void mousePressed() { + newVehicle(mouseX,mouseY); +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/Path.pde b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/Path.pde new file mode 100644 index 000000000..755be5b1f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/Path.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following + +class Path { + + // A Path is an arraylist of points (PVector objects) + ArrayList points; + // A path has a radius, i.e how far is it ok for the boid to wander off + float radius; + + Path() { + // Arbitrary radius of 20 + radius = 20; + points = new ArrayList(); + } + + // Add a point to the path + void addPoint(float x, float y) { + PVector point = new PVector(x, y); + points.add(point); + } + + // Draw the path + void display() { + strokeJoin(ROUND); + + // Draw thick line for radius + stroke(175); + strokeWeight(radius*2); + noFill(); + beginShape(); + for (PVector v : points) { + vertex(v.x, v.y); + } + endShape(CLOSE); + // Draw thin line for center of path + stroke(0); + strokeWeight(1); + noFill(); + beginShape(); + for (PVector v : points) { + vertex(v.x, v.y); + } + endShape(CLOSE); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/Vehicle.pde new file mode 100644 index 000000000..74030e95d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/Vehicle.pde @@ -0,0 +1,241 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following + +// Vehicle class + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle( PVector l, float ms, float mf) { + location = l.get(); + r = 12; + maxspeed = ms; + maxforce = mf; + acceleration = new PVector(0, 0); + velocity = new PVector(maxspeed, 0); + } + + // A function to deal with path following and separation + void applyBehaviors(ArrayList vehicles, Path path) { + // Follow path force + PVector f = follow(path); + // Separate from other boids force + PVector s = separate(vehicles); + // Arbitrary weighting + f.mult(3); + s.mult(1); + // Accumulate in acceleration + applyForce(f); + applyForce(s); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + + // Main "run" function + public void run() { + update(); + borders(); + render(); + } + + + // This function implements Craig Reynolds' path following algorithm + // http://www.red3d.com/cwr/steer/PathFollow.html + PVector follow(Path p) { + + // Predict location 25 (arbitrary choice) frames ahead + PVector predict = velocity.get(); + predict.normalize(); + predict.mult(25); + PVector predictLoc = PVector.add(location, predict); + + // Now we must find the normal to the path from the predicted location + // We look at the normal for each line segment and pick out the closest one + PVector normal = null; + PVector target = null; + float worldRecord = 1000000; // Start with a very high worldRecord distance that can easily be beaten + + // Loop through all points of the path + for (int i = 0; i < p.points.size(); i++) { + + // Look at a line segment + PVector a = p.points.get(i); + PVector b = p.points.get((i+1)%p.points.size()); // Note Path has to wraparound + + // Get the normal point to that line + PVector normalPoint = getNormalPoint(predictLoc, a, b); + + // Check if normal is on line segment + PVector dir = PVector.sub(b, a); + // If it's not within the line segment, consider the normal to just be the end of the line segment (point b) + //if (da + db > line.mag()+1) { + if (normalPoint.x < min(a.x,b.x) || normalPoint.x > max(a.x,b.x) || normalPoint.y < min(a.y,b.y) || normalPoint.y > max(a.y,b.y)) { + normalPoint = b.get(); + // If we're at the end we really want the next line segment for looking ahead + a = p.points.get((i+1)%p.points.size()); + b = p.points.get((i+2)%p.points.size()); // Path wraps around + dir = PVector.sub(b, a); + } + + // How far away are we from the path? + float d = PVector.dist(predictLoc, normalPoint); + // Did we beat the worldRecord and find the closest line segment? + if (d < worldRecord) { + worldRecord = d; + normal = normalPoint; + + // Look at the direction of the line segment so we can seek a little bit ahead of the normal + dir.normalize(); + // This is an oversimplification + // Should be based on distance to path & velocity + dir.mult(25); + target = normal.get(); + target.add(dir); + + } + } + + // Draw the debugging stuff + if (debug) { + // Draw predicted future location + stroke(0); + fill(0); + line(location.x, location.y, predictLoc.x, predictLoc.y); + ellipse(predictLoc.x, predictLoc.y, 4, 4); + + // Draw normal location + stroke(0); + fill(0); + ellipse(normal.x, normal.y, 4, 4); + // Draw actual target (red if steering towards it) + line(predictLoc.x, predictLoc.y, target.x, target.y); + if (worldRecord > p.radius) fill(255, 0, 0); + noStroke(); + ellipse(target.x, target.y, 8, 8); + } + + // Only if the distance is greater than the path's radius do we bother to steer + if (worldRecord > p.radius) { + return seek(target); + } + else { + return new PVector(0, 0); + } + } + + + // A function to get the normal point from a point (p) to a line segment (a-b) + // This function could be optimized to make fewer new Vector objects + PVector getNormalPoint(PVector p, PVector a, PVector b) { + // Vector from a to p + PVector ap = PVector.sub(p, a); + // Vector from a to b + PVector ab = PVector.sub(b, a); + ab.normalize(); // Normalize the line + // Project vector "diff" onto line by using the dot product + ab.mult(ap.dot(ab)); + PVector normalPoint = PVector.add(a, ab); + return normalPoint; + } + + // Separation + // Method checks for nearby boids and steers away + PVector separate (ArrayList boids) { + float desiredseparation = r*2; + PVector steer = new PVector(0, 0, 0); + int count = 0; + // For every boid in the system, check if it's too close + for (int i = 0 ; i < boids.size(); i++) { + Vehicle other = (Vehicle) boids.get(i); + float d = PVector.dist(location, other.location); + // 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(location, other.location); + 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) { + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mult(maxspeed); + steer.sub(velocity); + steer.limit(maxforce); + } + return steer; + } + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.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, location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus Velocationity + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); // Limit to maximum steering force + + return steer; + } + + + void render() { + // Simpler boid is just a circle + fill(75); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + ellipse(0, 0, r, r); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + //if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + //if (location.y > height+r) location.y = -r; + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Exercise_6_04_Wander.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Exercise_6_04_Wander.pde new file mode 100644 index 000000000..abbcec856 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Exercise_6_04_Wander.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Demonstration of Craig Reynolds' "Wandering" behavior +// See: http://www.red3d.com/cwr/ + +// Click mouse to turn on and off rendering of the wander circle + +Vehicle wanderer; +boolean debug = true; + +void setup() { + size(740,200); + wanderer = new Vehicle(width/2,height/2); + smooth(); +} + +void draw() { + background(255); + wanderer.wander(); + wanderer.run(); +} + +void mousePressed() { + debug = !debug; +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde new file mode 100644 index 000000000..fb979e8c5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde @@ -0,0 +1,123 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// The "Vehicle" class (for wandering) + +class Vehicle { + + PVector location; + PVector velocity; + PVector acceleration; + float r; + float wandertheta; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(float x, float y) { + acceleration = new PVector(0,0); + velocity = new PVector(0,0); + location = new PVector(x,y); + r = 6; + wandertheta = 0; + maxspeed = 2; + maxforce = 0.05; + } + + void run() { + update(); + borders(); + display(); + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void wander() { + float wanderR = 25; // Radius for our "wander circle" + float wanderD = 80; // Distance for our "wander circle" + float change = 0.3; + wandertheta += random(-change,change); // Randomly change wander theta + + // Now we have to calculate the new location to steer towards on the wander circle + PVector circleloc = velocity.get(); // Start with velocity + circleloc.normalize(); // Normalize to get heading + circleloc.mult(wanderD); // Multiply by distance + circleloc.add(location); // Make it relative to boid's location + + float h = velocity.heading2D(); // We need to know the heading to offset wandertheta + + PVector circleOffSet = new PVector(wanderR*cos(wandertheta+h),wanderR*sin(wandertheta+h)); + PVector target = PVector.add(circleloc,circleOffSet); + seek(target); + + // Render wandering circle, etc. + if (debug) drawWanderStuff(location,circleloc,target,wanderR); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + // A method that calculates and applies a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + void seek(PVector target) { + PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus Velocity + PVector steer = PVector.sub(desired,velocity); + steer.limit(maxforce); // Limit to maximum steering force + + applyForce(steer); + } + + void display() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(127); + stroke(0); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } +} + + +// A method just to draw the circle associated with wandering +void drawWanderStuff(PVector location, PVector circle, PVector target, float rad) { + stroke(0); + noFill(); + ellipseMode(CENTER); + ellipse(circle.x,circle.y,rad*2,rad*2); + ellipse(target.x,target.y,4,4); + line(location.x,location.y,circle.x,circle.y); + line(circle.x,circle.y,target.x,target.y); +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde new file mode 100644 index 000000000..aec7e814f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Angle Between Two Vectors +// Using the dot product to compute the angle between two vectors + +void setup() { + size(383, 200); + smooth(); +} + +void draw() { + background(255); + + // A "vector" (really a point) to store the mouse location and screen center location + PVector mouseLoc = new PVector(mouseX, mouseY); + PVector centerLoc = new PVector(width/2, height/2); + + // Aha, a vector to store the displacement between the mouse and center + PVector v = PVector.sub(mouseLoc, centerLoc); + v.normalize(); + v.mult(75); + + PVector xaxis = new PVector(75, 0); + // Render the vector + drawVector(v, centerLoc, 1.0); + drawVector(xaxis, centerLoc, 1.0); + + + float theta = PVector.angleBetween(v, xaxis); + + fill(0); + text(int(degrees(theta)) + " degrees\n" + theta + " radians", 10, 160); +} + +// Renders a vector object 'v' as an arrow and a location 'loc' +void drawVector(PVector v, PVector loc, float scayl) { + pushMatrix(); + float arrowsize = 6; + // Translate to location to render vector + translate(loc.x, loc.y); + stroke(0); + strokeWeight(2); + // Call vector heading function to get direction (pointing up is a heading of 0) + rotate(v.heading2D()); + // 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 + line(0, 0, len, 0); + line(len, 0, len-arrowsize, +arrowsize/2); + line(len, 0, len-arrowsize, -arrowsize/2); + popMatrix(); +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Exercise_6_13_CrowdPathFollowing.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Exercise_6_13_CrowdPathFollowing.pde new file mode 100644 index 000000000..bb66799ca --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Exercise_6_13_CrowdPathFollowing.pde @@ -0,0 +1,77 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Crowd Path Following +// Via Reynolds: http://www.red3d.com/cwr/steer/CrowdPath.html + +// Using this variable to decide whether to draw all the stuff +boolean debug = false; + + +// A path object (series of connected points) +Path path; + +// Two vehicles +ArrayList vehicles; + +void setup() { + size(720,200); + // Call a function to generate new Path object + newPath(); + + // We are now making random vehicles and storing them in an ArrayList + vehicles = new ArrayList(); + for (int i = 0; i < 120; i++) { + newVehicle(random(width),random(height)); + } +} + +void draw() { + background(255); + // Display the path + path.display(); + + for (Vehicle v : vehicles) { + // Path following and separation are worked on in this function + v.applyBehaviors(vehicles,path); + // Call the generic run method (update, borders, display, etc.) + v.run(); + } + + // Instructions + fill(0); + textAlign(CENTER); + text("Hit 'd' to toggle debugging lines.\nClick the mouse to generate new vehicles.",width/2,height-20); +} + +void newPath() { + // A path is a series of connected points + // A more sophisticated path might be a curve + path = new Path(); + float offset = 30; + path.addPoint(offset,offset); + path.addPoint(width-offset,offset); + path.addPoint(width-offset,height-offset); + path.addPoint(width/2,height-offset*3); + path.addPoint(offset,height-offset); +} + +void newVehicle(float x, float y) { + float maxspeed = random(2,4); + float maxforce = 0.3; + vehicles.add(new Vehicle(new PVector(x,y),maxspeed,maxforce)); +} + +void keyPressed() { + if (key == 'd') { + debug = !debug; + } +} + +void mousePressed() { + newVehicle(mouseX,mouseY); +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Path.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Path.pde new file mode 100644 index 000000000..755be5b1f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Path.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following + +class Path { + + // A Path is an arraylist of points (PVector objects) + ArrayList points; + // A path has a radius, i.e how far is it ok for the boid to wander off + float radius; + + Path() { + // Arbitrary radius of 20 + radius = 20; + points = new ArrayList(); + } + + // Add a point to the path + void addPoint(float x, float y) { + PVector point = new PVector(x, y); + points.add(point); + } + + // Draw the path + void display() { + strokeJoin(ROUND); + + // Draw thick line for radius + stroke(175); + strokeWeight(radius*2); + noFill(); + beginShape(); + for (PVector v : points) { + vertex(v.x, v.y); + } + endShape(CLOSE); + // Draw thin line for center of path + stroke(0); + strokeWeight(1); + noFill(); + beginShape(); + for (PVector v : points) { + vertex(v.x, v.y); + } + endShape(CLOSE); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Vehicle.pde new file mode 100644 index 000000000..14a2947e7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_13_CrowdPathFollowing/Vehicle.pde @@ -0,0 +1,240 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following +// Vehicle class + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle( PVector l, float ms, float mf) { + location = l.get(); + r = 12; + maxspeed = ms; + maxforce = mf; + acceleration = new PVector(0, 0); + velocity = new PVector(maxspeed, 0); + } + + // A function to deal with path following and separation + void applyBehaviors(ArrayList vehicles, Path path) { + // Follow path force + PVector f = follow(path); + // Separate from other boids force + PVector s = separate(vehicles); + // Arbitrary weighting + f.mult(3); + s.mult(1); + // Accumulate in acceleration + applyForce(f); + applyForce(s); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + + // Main "run" function + public void run() { + update(); + borders(); + render(); + } + + + // This function implements Craig Reynolds' path following algorithm + // http://www.red3d.com/cwr/steer/PathFollow.html + PVector follow(Path p) { + + // Predict location 25 (arbitrary choice) frames ahead + PVector predict = velocity.get(); + predict.normalize(); + predict.mult(25); + PVector predictLoc = PVector.add(location, predict); + + // Now we must find the normal to the path from the predicted location + // We look at the normal for each line segment and pick out the closest one + PVector normal = null; + PVector target = null; + float worldRecord = 1000000; // Start with a very high worldRecord distance that can easily be beaten + + // Loop through all points of the path + for (int i = 0; i < p.points.size(); i++) { + + // Look at a line segment + PVector a = p.points.get(i); + PVector b = p.points.get((i+1)%p.points.size()); // Note Path has to wraparound + + // Get the normal point to that line + PVector normalPoint = getNormalPoint(predictLoc, a, b); + + // Check if normal is on line segment + PVector dir = PVector.sub(b, a); + // If it's not within the line segment, consider the normal to just be the end of the line segment (point b) + //if (da + db > line.mag()+1) { + if (normalPoint.x < min(a.x,b.x) || normalPoint.x > max(a.x,b.x) || normalPoint.y < min(a.y,b.y) || normalPoint.y > max(a.y,b.y)) { + normalPoint = b.get(); + // If we're at the end we really want the next line segment for looking ahead + a = p.points.get((i+1)%p.points.size()); + b = p.points.get((i+2)%p.points.size()); // Path wraps around + dir = PVector.sub(b, a); + } + + // How far away are we from the path? + float d = PVector.dist(predictLoc, normalPoint); + // Did we beat the worldRecord and find the closest line segment? + if (d < worldRecord) { + worldRecord = d; + normal = normalPoint; + + // Look at the direction of the line segment so we can seek a little bit ahead of the normal + dir.normalize(); + // This is an oversimplification + // Should be based on distance to path & velocity + dir.mult(25); + target = normal.get(); + target.add(dir); + + } + } + + // Draw the debugging stuff + if (debug) { + // Draw predicted future location + stroke(0); + fill(0); + line(location.x, location.y, predictLoc.x, predictLoc.y); + ellipse(predictLoc.x, predictLoc.y, 4, 4); + + // Draw normal location + stroke(0); + fill(0); + ellipse(normal.x, normal.y, 4, 4); + // Draw actual target (red if steering towards it) + line(predictLoc.x, predictLoc.y, target.x, target.y); + if (worldRecord > p.radius) fill(255, 0, 0); + noStroke(); + ellipse(target.x, target.y, 8, 8); + } + + // Only if the distance is greater than the path's radius do we bother to steer + if (worldRecord > p.radius) { + return seek(target); + } + else { + return new PVector(0, 0); + } + } + + + // A function to get the normal point from a point (p) to a line segment (a-b) + // This function could be optimized to make fewer new Vector objects + PVector getNormalPoint(PVector p, PVector a, PVector b) { + // Vector from a to p + PVector ap = PVector.sub(p, a); + // Vector from a to b + PVector ab = PVector.sub(b, a); + ab.normalize(); // Normalize the line + // Project vector "diff" onto line by using the dot product + ab.mult(ap.dot(ab)); + PVector normalPoint = PVector.add(a, ab); + return normalPoint; + } + + // Separation + // Method checks for nearby boids and steers away + PVector separate (ArrayList boids) { + float desiredseparation = r*2; + PVector steer = new PVector(0, 0, 0); + int count = 0; + // For every boid in the system, check if it's too close + for (int i = 0 ; i < boids.size(); i++) { + Vehicle other = (Vehicle) boids.get(i); + float d = PVector.dist(location, other.location); + // 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(location, other.location); + 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) { + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mult(maxspeed); + steer.sub(velocity); + steer.limit(maxforce); + } + return steer; + } + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.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, location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus Velocationity + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); // Limit to maximum steering force + + return steer; + } + + + void render() { + // Simpler boid is just a circle + fill(75); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + ellipse(0, 0, r, r); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + //if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + //if (location.y > height+r) location.y = -r; + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde new file mode 100644 index 000000000..1f3350be5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde @@ -0,0 +1,36 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Two "vehicles" follow the mouse position + +// Implements Craig Reynold's autonomous steering behaviors +// One vehicle "seeks" +// One vehicle "arrives" +// See: http://www.red3d.com/cwr/ + +Vehicle v; + +void setup() { + size(800, 200); + v = new Vehicle(width/2, height/2); + smooth(); +} + +void draw() { + background(255); + + PVector mouse = new PVector(mouseX, mouseY); + + // Draw an ellipse at the mouse location + fill(200); + stroke(0); + strokeWeight(2); + ellipse(mouse.x, mouse.y, 48, 48); + + // Call the appropriate steering behaviors for our agents + v.seek(mouse); + v.update(); + v.display(); +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde new file mode 100644 index 000000000..dfb311c92 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde @@ -0,0 +1,77 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Seek_Arrive + +// The "Vehicle" class + +class Vehicle { + + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(float x, float y) { + acceleration = new PVector(0,0); + velocity = new PVector(0,-2); + location = new PVector(x,y); + r = 6; + maxspeed = 4; + maxforce = 0.1; + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelerationelertion to 0 each cycle + acceleration.mult(0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // A method that calculates a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + void seek(PVector target) { + PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus velocity + PVector steer = PVector.sub(desired,velocity); + steer.limit(maxforce); // Limit to maximum steering force + + applyForce(steer); + } + + void display() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + PI/2; + fill(127); + stroke(0); + strokeWeight(1); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(CLOSE); + popMatrix(); + + + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/NOC_6_01_Seek_trail.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/NOC_6_01_Seek_trail.pde new file mode 100644 index 000000000..0c68b26e6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/NOC_6_01_Seek_trail.pde @@ -0,0 +1,36 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Implements Craig Reynold's autonomous steering behaviors +// One vehicle "seeks" +// See: http://www.red3d.com/cwr/ + +Vehicle v; + +void setup() { + size(800, 200); + v = new Vehicle(width/2, height/2); + smooth(); +} + +void draw() { + if (mousePressed) { + + background(255); + + PVector mouse = new PVector(mouseX, mouseY); + + // Draw an ellipse at the mouse location + fill(200); + stroke(0); + strokeWeight(2); + ellipse(mouse.x, mouse.y, 48, 48); + + // Call the appropriate steering behaviors for our agents + v.seek(mouse); + v.update(); + v.display(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde new file mode 100644 index 000000000..d0b33d652 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde @@ -0,0 +1,91 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// The "Vehicle" class + +class Vehicle { + ArrayList history = new ArrayList(); + + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(float x, float y) { + acceleration = new PVector(0,0); + velocity = new PVector(0,-2); + location = new PVector(x,y); + r = 6; + maxspeed = 4; + maxforce = 0.1; + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelerationelertion to 0 each cycle + acceleration.mult(0); + + history.add(location.get()); + if (history.size() > 100) { + history.remove(0); + } + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // A method that calculates a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + void seek(PVector target) { + PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus velocity + PVector steer = PVector.sub(desired,velocity); + steer.limit(maxforce); // Limit to maximum steering force + + applyForce(steer); + } + + void display() { + beginShape(); + stroke(0); + strokeWeight(1); + noFill(); + for(PVector v: history) { + vertex(v.x,v.y); + } + endShape(); + + + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + PI/2; + fill(127); + stroke(0); + strokeWeight(1); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(CLOSE); + popMatrix(); + + + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde new file mode 100644 index 000000000..1267fb8ec --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// One vehicle "arrives" +// See: http://www.red3d.com/cwr/ + +Vehicle v; + +void setup() { + size(800, 200); + v = new Vehicle(width/2, height/2); + smooth(); +} + +void draw() { + background(255); + + PVector mouse = new PVector(mouseX, mouseY); + + // Draw an ellipse at the mouse location + fill(200); + stroke(0); + strokeWeight(2); + ellipse(mouse.x, mouse.y, 48, 48); + + // Call the appropriate steering behaviors for our agents + v.arrive(mouse); + v.update(); + v.display(); +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde new file mode 100644 index 000000000..72fe089b8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde @@ -0,0 +1,81 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// The "Vehicle" class + +class Vehicle { + + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(float x, float y) { + acceleration = new PVector(0,0); + velocity = new PVector(0,0); + location = new PVector(x,y); + r = 6; + maxspeed = 4; + maxforce = 0.1; + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelerationelertion to 0 each cycle + acceleration.mult(0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // A method that calculates a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + void arrive(PVector target) { + PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target + float d = desired.mag(); + // Normalize desired and scale with arbitrary damping within 100 pixels + desired.normalize(); + if (d < 100) { + float m = map(d,0,100,0,maxspeed); + desired.mult(m); + } else { + desired.mult(maxspeed); + } + + // Steering = Desired minus Velocity + PVector steer = PVector.sub(desired,velocity); + steer.limit(maxforce); // Limit to maximum steering force + applyForce(steer); + } + + void display() { + + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + PI/2; + fill(127); + stroke(0); + strokeWeight(1); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(CLOSE); + popMatrix(); + + + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/NOC_6_03_StayWithinWalls.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/NOC_6_03_StayWithinWalls.pde new file mode 100644 index 000000000..edbd19635 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/NOC_6_03_StayWithinWalls.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stay Within Walls +// "Made-up" Steering behavior to stay within walls + + +Vehicle v; +boolean debug = true; + +float d = 25; + + +void setup() { + size(800, 200); + v = new Vehicle(width/2, height/2); + smooth(); +} + +void draw() { + background(255); + + if (debug) { + stroke(175); + noFill(); + rectMode(CENTER); + rect(width/2, height/2, width-d*2, height-d*2); + } + + v.boundaries(); + v.run(); +} + +void mousePressed() { + debug = !debug; +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde new file mode 100644 index 000000000..9a507181c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde @@ -0,0 +1,92 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// The "Vehicle" class + +class Vehicle { + + PVector location; + PVector velocity; + PVector acceleration; + float r; + + float maxspeed; + float maxforce; + + Vehicle(float x, float y) { + acceleration = new PVector(0, 0); + velocity = new PVector(3, -2); + velocity.mult(5); + location = new PVector(x, y); + r = 6; + maxspeed = 3; + maxforce = 0.15; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void boundaries() { + + PVector desired = null; + + if (location.x < d) { + desired = new PVector(maxspeed, velocity.y); + } + else if (location.x > width -d) { + desired = new PVector(-maxspeed, velocity.y); + } + + if (location.y < d) { + desired = new PVector(velocity.x, maxspeed); + } + else if (location.y > height-d) { + desired = new PVector(velocity.x, -maxspeed); + } + + if (desired != null) { + desired.normalize(); + desired.mult(maxspeed); + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); + applyForce(steer); + } + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + void display() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(127); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/NOC_6_03_StayWithinWalls_trail.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/NOC_6_03_StayWithinWalls_trail.pde new file mode 100644 index 000000000..edbd19635 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/NOC_6_03_StayWithinWalls_trail.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stay Within Walls +// "Made-up" Steering behavior to stay within walls + + +Vehicle v; +boolean debug = true; + +float d = 25; + + +void setup() { + size(800, 200); + v = new Vehicle(width/2, height/2); + smooth(); +} + +void draw() { + background(255); + + if (debug) { + stroke(175); + noFill(); + rectMode(CENTER); + rect(width/2, height/2, width-d*2, height-d*2); + } + + v.boundaries(); + v.run(); +} + +void mousePressed() { + debug = !debug; +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde new file mode 100644 index 000000000..0d94054a4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde @@ -0,0 +1,108 @@ +// Wander +// Daniel Shiffman +// The Nature of Code + +// The "Vehicle" class + +class Vehicle { + ArrayList history = new ArrayList(); + + PVector location; + PVector velocity; + PVector acceleration; + float r; + + float maxspeed; + float maxforce; + + Vehicle(float x, float y) { + acceleration = new PVector(0, 0); + velocity = new PVector(3, -2); + velocity.mult(5); + location = new PVector(x, y); + r = 6; + maxspeed = 3; + maxforce = 0.15; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + + history.add(location.get()); + if (history.size() > 500) { + history.remove(0); + } + } + + void boundaries() { + + PVector desired = null; + + if (location.x < d) { + desired = new PVector(maxspeed, velocity.y); + } + else if (location.x > width -d) { + desired = new PVector(-maxspeed, velocity.y); + } + + if (location.y < d) { + desired = new PVector(velocity.x, maxspeed); + } + else if (location.y > height-d) { + desired = new PVector(velocity.x, -maxspeed); + } + + if (desired != null) { + desired.normalize(); + desired.mult(maxspeed); + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); + applyForce(steer); + } + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + void display() { + beginShape(); + stroke(0); + strokeWeight(1); + noFill(); + for(PVector v: history) { + vertex(v.x,v.y); + } + endShape(); + + + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(127); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde new file mode 100644 index 000000000..75b471b29 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde @@ -0,0 +1,94 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flow Field Following + +class FlowField { + + // A flow field is a two dimensional array of PVectors + PVector[][] field; + int cols, rows; // Columns and Rows + int resolution; // How large is each "cell" of the flow field + + FlowField(int r) { + resolution = r; + // Determine the number of columns and rows based on sketch's width and height + cols = width/resolution; + rows = height/resolution; + field = new PVector[cols][rows]; + init(); + } + + void init() { + // Reseed noise so we get a new flow field every time + noiseSeed((int)random(10000)); + float xoff = 0; + for (int i = 0; i < cols; i++) { + float yoff = 0; + for (int j = 0; j < rows; j++) { + //float theta = random(TWO_PI); + //float theta = map(noise(xoff,yoff),0,1,0,TWO_PI); + float x = i*resolution; + float y = j*resolution; + PVector v = new PVector(width/2-x,-y); + v.normalize(); + // Polar to cartesian coordinate transformation to get x and y components of the vector + field[i][j] = v;// new PVector(cos(theta),sin(theta)); + yoff += 0.1; + } + xoff += 0.1; + } + } + + // Draw every vector + void display() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + //drawVector(field[i][j],i*resolution,j*resolution,resolution-2); + pushMatrix(); + //translate(i*resolution+arrow.width/2,j*resolution+arrow.height/2); + translate(i*resolution,j*resolution); + rotate(field[i][j].heading2D()); + imageMode(CENTER); + //scale(0.2); + image(a,0,0); + //shape(arrow,-arrow.width/2,-arrow.height/2); + //ellipse(0,0,8,8); + popMatrix(); + } + } + + } + + // Renders a vector object 'v' as an arrow and a location 'x,y' + void drawVector(PVector v, float x, float y, float scayl) { + pushMatrix(); + float arrowsize = 4; + // Translate to location to render vector + translate(x,y); + stroke(0,100); + // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate + rotate(v.heading2D()); + // 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(); + } + + PVector lookup(PVector lookup) { + int column = int(constrain(lookup.x/resolution,0,cols-1)); + int row = int(constrain(lookup.y/resolution,0,rows-1)); + return field[column][row].get(); + } + + +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/NOC_6_04_Flow_Figures.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/NOC_6_04_Flow_Figures.pde new file mode 100644 index 000000000..beb0642c9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/NOC_6_04_Flow_Figures.pde @@ -0,0 +1,35 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flow Field Following + +// Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html + +// Flowfield object +FlowField flowfield; +PShape arrow; +PImage a; + +void setup() { + size(1800, 60*9); + // Make a new flow field with "resolution" of 16 + flowfield = new FlowField(60); + arrow = loadShape("arrow.svg"); + a = loadImage("arrow60.png"); +} + +void draw() { + background(255); + // Display the flowfield in "debug" mode + translate(30,30); + flowfield.display(); + saveFrame("ch6_exc6.png"); + noLoop(); +} +// Make a new flowfield +void mousePressed() { + flowfield.init(); +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde new file mode 100644 index 000000000..2326a1e7c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde @@ -0,0 +1,87 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flow Field Following + +class Vehicle { + + // The usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(PVector l, float ms, float mf) { + location = l.get(); + r = 3.0; + maxspeed = ms; + maxforce = mf; + acceleration = new PVector(0,0); + velocity = new PVector(0,0); + } + + public void run() { + update(); + borders(); + display(); + } + + + // Implementing Reynolds' flow field following algorithm + // http://www.red3d.com/cwr/steer/FlowFollow.html + void follow(FlowField flow) { + // What is the vector at that spot in the flow field? + PVector desired = flow.lookup(location); + // Scale it up by maxspeed + desired.mult(maxspeed); + // Steering is desired minus velocity + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); // Limit to maximum steering force + applyForce(steer); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void display() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(175); + stroke(0); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/data/arrow.svg b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/data/arrow.svg new file mode 100644 index 000000000..0f34115e7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/data/arrow.svg @@ -0,0 +1,5149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde new file mode 100644 index 000000000..08bf7eb23 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde @@ -0,0 +1,79 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flow Field Following + +class FlowField { + + // A flow field is a two dimensional array of PVectors + PVector[][] field; + int cols, rows; // Columns and Rows + int resolution; // How large is each "cell" of the flow field + + FlowField(int r) { + resolution = r; + // Determine the number of columns and rows based on sketch's width and height + cols = width/resolution; + rows = height/resolution; + field = new PVector[cols][rows]; + init(); + } + + void init() { + // Reseed noise so we get a new flow field every time + noiseSeed((int)random(10000)); + float xoff = 0; + for (int i = 0; i < cols; i++) { + float yoff = 0; + for (int j = 0; j < rows; j++) { + float theta = map(noise(xoff,yoff),0,1,0,TWO_PI); + // Polar to cartesian coordinate transformation to get x and y components of the vector + field[i][j] = new PVector(cos(theta),sin(theta)); + yoff += 0.1; + } + xoff += 0.1; + } + } + + // Draw every vector + void display() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + drawVector(field[i][j],i*resolution,j*resolution,resolution-2); + } + } + + } + + // Renders a vector object 'v' as an arrow and a location 'x,y' + void drawVector(PVector v, float x, float y, float scayl) { + pushMatrix(); + float arrowsize = 4; + // Translate to location to render vector + translate(x,y); + stroke(0,100); + // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate + rotate(v.heading2D()); + // 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(); + } + + PVector lookup(PVector lookup) { + int column = int(constrain(lookup.x/resolution,0,cols-1)); + int row = int(constrain(lookup.y/resolution,0,rows-1)); + return field[column][row].get(); + } + + +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde new file mode 100644 index 000000000..47ce095df --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flow Field Following +// Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html + +// Using this variable to decide whether to draw all the stuff +boolean debug = true; + +// Flowfield object +FlowField flowfield; +// An ArrayList of vehicles +ArrayList vehicles; + +void setup() { + size(800, 200); + // Make a new flow field with "resolution" of 16 + flowfield = new FlowField(20); + vehicles = new ArrayList(); + // Make a whole bunch of vehicles with random maxspeed and maxforce values + for (int i = 0; i < 120; i++) { + vehicles.add(new Vehicle(new PVector(random(width), random(height)), random(2, 5), random(0.1, 0.5))); + } +} + +void draw() { + background(255); + // Display the flowfield in "debug" mode + if (debug) flowfield.display(); + // Tell all the vehicles to follow the flow field + for (Vehicle v : vehicles) { + v.follow(flowfield); + v.run(); + } + + // Instructions + fill(0); + text("Hit space bar to toggle debugging lines.\nClick the mouse to generate a new flow field.",10,height-20); +} + + +void keyPressed() { + if (key == ' ') { + debug = !debug; + } +} + +// Make a new flowfield +void mousePressed() { + flowfield.init(); +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde new file mode 100644 index 000000000..2326a1e7c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde @@ -0,0 +1,87 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flow Field Following + +class Vehicle { + + // The usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Vehicle(PVector l, float ms, float mf) { + location = l.get(); + r = 3.0; + maxspeed = ms; + maxforce = mf; + acceleration = new PVector(0,0); + velocity = new PVector(0,0); + } + + public void run() { + update(); + borders(); + display(); + } + + + // Implementing Reynolds' flow field following algorithm + // http://www.red3d.com/cwr/steer/FlowFollow.html + void follow(FlowField flow) { + // What is the vector at that spot in the flow field? + PVector desired = flow.lookup(location); + // Scale it up by maxspeed + desired.mult(maxspeed); + // Steering is desired minus velocity + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); // Limit to maximum steering force + applyForce(steer); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void display() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(175); + stroke(0); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/sketch.properties new file mode 100644 index 000000000..e69de29bb diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde new file mode 100644 index 000000000..7b6387c31 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde @@ -0,0 +1,51 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following +// Path is a just a straight line in this example +// Via Reynolds: // http://www.red3d.com/cwr/steer/PathFollow.html + +// Using this variable to decide whether to draw all the stuff +boolean debug = true; + +// A path object (series of connected points) +Path path; + +// Two vehicles +Vehicle car1; +Vehicle car2; + +void setup() { + size(800, 200); + path = new Path(); + + // Each vehicle has different maxspeed and maxforce for demo purposes + car1 = new Vehicle(new PVector(0, height/2), 3, 0.05); + car2 = new Vehicle(new PVector(0, height/2), 5, 0.1); +} + +void draw() { + background(255); + // Display the path + path.display(); + // The boids follow the path + car1.follow(path); + car2.follow(path); + // Call the generic run method (update, borders, display, etc.) + car1.run(); + car2.run(); + + // Instructions + fill(0); + text("Hit space bar to toggle debugging lines.", 10, height-30); +} + +public void keyPressed() { + if (key == ' ') { + debug = !debug; + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Path.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Path.pde new file mode 100644 index 000000000..3d222214d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Path.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following + +class Path { + + // A Path is line between two points (PVector objects) + PVector start; + PVector end; + // A path has a radius, i.e how far is it ok for the boid to wander off + float radius; + + Path() { + // Arbitrary radius of 20 + radius = 20; + start = new PVector(0,height/3); + end = new PVector(width,2*height/3); + } + + // Draw the path + void display() { + + strokeWeight(radius*2); + stroke(0,100); + line(start.x,start.y,end.x,end.y); + + strokeWeight(1); + stroke(0); + line(start.x,start.y,end.x,end.y); + } +} + + + + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde new file mode 100644 index 000000000..109d7d658 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde @@ -0,0 +1,161 @@ +// Path Following +// Daniel Shiffman +// The Nature of Code, Spring 2009 + +// Vehicle class + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle( PVector l, float ms, float mf) { + location = l.get(); + r = 4.0; + maxspeed = ms; + maxforce = mf; + acceleration = new PVector(0, 0); + velocity = new PVector(maxspeed, 0); + } + + // Main "run" function + void run() { + update(); + borders(); + render(); + } + + + // This function implements Craig Reynolds' path following algorithm + // http://www.red3d.com/cwr/steer/PathFollow.html + void follow(Path p) { + + // Predict location 25 (arbitrary choice) frames ahead + PVector predict = velocity.get(); + predict.normalize(); + predict.mult(25); + PVector predictLoc = PVector.add(location, predict); + + // Look at the line segment + PVector a = p.start; + PVector b = p.end; + + // Get the normal point to that line + PVector normalPoint = getNormalPoint(predictLoc, a, b); + + // Find target point a little further ahead of normal + PVector dir = PVector.sub(b, a); + dir.normalize(); + dir.mult(10); // This could be based on velocity instead of just an arbitrary 10 pixels + PVector target = PVector.add(normalPoint, dir); + + // How far away are we from the path? + float distance = PVector.dist(predictLoc, normalPoint); + // Only if the distance is greater than the path's radius do we bother to steer + if (distance > p.radius) { + seek(target); + } + + + // Draw the debugging stuff + if (debug) { + fill(0); + stroke(0); + line(location.x, location.y, predictLoc.x, predictLoc.y); + ellipse(predictLoc.x, predictLoc.y, 4, 4); + + // Draw normal location + fill(0); + stroke(0); + line(predictLoc.x, predictLoc.y, normalPoint.x, normalPoint.y); + ellipse(normalPoint.x, normalPoint.y, 4, 4); + stroke(0); + if (distance > p.radius) fill(255, 0, 0); + noStroke(); + ellipse(target.x+dir.x, target.y+dir.y, 8, 8); + } + } + + + // A function to get the normal point from a point (p) to a line segment (a-b) + // This function could be optimized to make fewer new Vector objects + PVector getNormalPoint(PVector p, PVector a, PVector b) { + // Vector from a to p + PVector ap = PVector.sub(p, a); + // Vector from a to b + PVector ab = PVector.sub(b, a); + ab.normalize(); // Normalize the line + // Project vector "diff" onto line by using the dot product + ab.mult(ap.dot(ab)); + PVector normalPoint = PVector.add(a, ab); + return normalPoint; + } + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + // A method that calculates and applies a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + void seek(PVector target) { + PVector desired = PVector.sub(target, location); // A vector pointing from the location to the target + + // If the magnitude of desired equals 0, skip out of here + // (We could optimize this to check if x and y are 0 to avoid mag() square root + if (desired.mag() == 0) return; + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus Velocity + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); // Limit to maximum steering force + + applyForce(steer); + } + + void render() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(175); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + beginShape(PConstants.TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + //if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + //if (location.y > height+r) location.y = -r; + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties new file mode 100644 index 000000000..6d28cd598 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties @@ -0,0 +1 @@ +mode=JavaScript diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde new file mode 100644 index 000000000..2990a9045 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following +// Via Reynolds: // http://www.red3d.com/cwr/steer/PathFollow.html + +// Using this variable to decide whether to draw all the stuff +boolean debug = true; + +// A path object (series of connected points) +Path path; + +// Two vehicles +Vehicle car1; +Vehicle car2; + +void setup() { + size(800, 200); + // Call a function to generate new Path object + newPath(); + + // Each vehicle has different maxspeed and maxforce for demo purposes + car1 = new Vehicle(new PVector(0, height/2), 3, 0.1); + car2 = new Vehicle(new PVector(0, height/2), 5, 0.2); +} + +void draw() { + background(255); + // Display the path + path.display(); + // The boids follow the path + car1.follow(path); + car2.follow(path); + // Call the generic run method (update, borders, display, etc.) + car1.run(); + car2.run(); + + // Instructions + fill(0); + text("Hit space bar to toggle debugging lines.\nClick the mouse to generate a new path.", 10, height-30); +} + +void newPath() { + // A path is a series of connected points + // A more sophisticated path might be a curve + path = new Path(); + path.addPoint(0, height/2); + path.addPoint(random(0, width/2), random(0, height)); + path.addPoint(random(width/2, width), random(0, height)); + path.addPoint(width, height/2); +} + +public void keyPressed() { + if (key == ' ') { + debug = !debug; + } +} + +public void mousePressed() { + newPath(); +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Path.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Path.pde new file mode 100644 index 000000000..feb679588 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Path.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following + +class Path { + + // A Path is an arraylist of points (PVector objects) + ArrayList points; + // A path has a radius, i.e how far is it ok for the boid to wander off + float radius; + + Path() { + // Arbitrary radius of 20 + radius = 20; + points = new ArrayList(); + } + + // Add a point to the path + void addPoint(float x, float y) { + PVector point = new PVector(x, y); + points.add(point); + } + + // Draw the path + void display() { + // Draw thick line for radius + stroke(175); + strokeWeight(radius*2); + noFill(); + beginShape(); + for (PVector v : points) { + vertex(v.x, v.y); + } + endShape(); + // Draw thin line for center of path + stroke(0); + strokeWeight(1); + noFill(); + beginShape(); + for (PVector v : points) { + vertex(v.x, v.y); + } + endShape(); + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde new file mode 100644 index 000000000..b705abaf2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde @@ -0,0 +1,192 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Path Following + +// Vehicle class + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle( PVector l, float ms, float mf) { + location = l.get(); + r = 4.0; + maxspeed = ms; + maxforce = mf; + acceleration = new PVector(0, 0); + velocity = new PVector(maxspeed, 0); + } + + // Main "run" function + public void run() { + update(); + borders(); + render(); + } + + + // This function implements Craig Reynolds' path following algorithm + // http://www.red3d.com/cwr/steer/PathFollow.html + void follow(Path p) { + + // Predict location 25 (arbitrary choice) frames ahead + PVector predict = velocity.get(); + predict.normalize(); + predict.mult(25); + PVector predictLoc = PVector.add(location, predict); + + // Now we must find the normal to the path from the predicted location + // We look at the normal for each line segment and pick out the closest one + + PVector normal = null; + PVector target = null; + float worldRecord = 1000000; // Start with a very high record distance that can easily be beaten + + // Loop through all points of the path + for (int i = 0; i < p.points.size()-1; i++) { + + // Look at a line segment + PVector a = p.points.get(i); + PVector b = p.points.get(i+1); + + // Get the normal point to that line + PVector normalPoint = getNormalPoint(predictLoc, a, b); + // This only works because we know our path goes from left to right + // We could have a more sophisticated test to tell if the point is in the line segment or not + if (normalPoint.x < a.x || normalPoint.x > b.x) { + // This is something of a hacky solution, but if it's not within the line segment + // consider the normal to just be the end of the line segment (point b) + normalPoint = b.get(); + } + + // How far away are we from the path? + float distance = PVector.dist(predictLoc, normalPoint); + // Did we beat the record and find the closest line segment? + if (distance < worldRecord) { + worldRecord = distance; + // If so the target we want to steer towards is the normal + normal = normalPoint; + + // Look at the direction of the line segment so we can seek a little bit ahead of the normal + PVector dir = PVector.sub(b, a); + dir.normalize(); + // This is an oversimplification + // Should be based on distance to path & velocity + dir.mult(10); + target = normalPoint.get(); + target.add(dir); + } + } + + // Only if the distance is greater than the path's radius do we bother to steer + if (worldRecord > p.radius) { + seek(target); + } + + + // Draw the debugging stuff + if (debug) { + // Draw predicted future location + stroke(0); + fill(0); + line(location.x, location.y, predictLoc.x, predictLoc.y); + ellipse(predictLoc.x, predictLoc.y, 4, 4); + + // Draw normal location + stroke(0); + fill(0); + ellipse(normal.x, normal.y, 4, 4); + // Draw actual target (red if steering towards it) + line(predictLoc.x, predictLoc.y, normal.x, normal.y); + if (worldRecord > p.radius) fill(255, 0, 0); + noStroke(); + ellipse(target.x, target.y, 8, 8); + } + } + + + // A function to get the normal point from a point (p) to a line segment (a-b) + // This function could be optimized to make fewer new Vector objects + PVector getNormalPoint(PVector p, PVector a, PVector b) { + // Vector from a to p + PVector ap = PVector.sub(p, a); + // Vector from a to b + PVector ab = PVector.sub(b, a); + ab.normalize(); // Normalize the line + // Project vector "diff" onto line by using the dot product + ab.mult(ap.dot(ab)); + PVector normalPoint = PVector.add(a, ab); + return normalPoint; + } + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + // A method that calculates and applies a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + void seek(PVector target) { + PVector desired = PVector.sub(target, location); // A vector pointing from the location to the target + + // If the magnitude of desired equals 0, skip out of here + // (We could optimize this to check if x and y are 0 to avoid mag() square root + if (desired.mag() == 0) return; + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus Velocity + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); // Limit to maximum steering force + + applyForce(steer); + } + + void render() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(175); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + beginShape(PConstants.TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + //if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + //if (location.y > height+r) location.y = -r; + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde new file mode 100644 index 000000000..8f92a4921 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Separation +// Via Reynolds: http://www.red3d.com/cwr/steer/ + +// A list of vehicles +ArrayList vehicles; + +void setup() { + size(800,200); + // We are now making random vehicles and storing them in an ArrayList + vehicles = new ArrayList(); + for (int i = 0; i < 100; i++) { + vehicles.add(new Vehicle(random(width),random(height))); + } +} + +void draw() { + background(255); + + for (Vehicle v : vehicles) { + // Path following and separation are worked on in this function + v.separate(vehicles); + // Call the generic run method (update, borders, display, etc.) + v.update(); + v.borders(); + v.display(); + } + + // Instructions + fill(0); + text("Drag the mouse to generate new vehicles.",10,height-16); +} + + +void mouseDragged() { + vehicles.add(new Vehicle(mouseX,mouseY)); +} + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/Vehicle.pde new file mode 100644 index 000000000..f0a5ddb96 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/Vehicle.pde @@ -0,0 +1,99 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Vehicle class + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle(float x, float y) { + location = new PVector(x, y); + r = 12; + maxspeed = 3; + maxforce = 0.2; + acceleration = new PVector(0, 0); + velocity = new PVector(0, 0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + // Separation + // Method checks for nearby vehicles and steers away + void separate (ArrayList vehicles) { + float desiredseparation = r*2; + PVector sum = new PVector(); + int count = 0; + // For every boid in the system, check if it's too close + for (Vehicle other : vehicles) { + float d = PVector.dist(location, other.location); + // 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(location, other.location); + diff.normalize(); + diff.div(d); // Weight by distance + sum.add(diff); + count++; // Keep track of how many + } + } + // Average -- divide by how many + if (count > 0) { + sum.div(count); + // Our desired vector is the average scaled to maximum speed + sum.normalize(); + sum.mult(maxspeed); + // Implement Reynolds: Steering = Desired - Velocity + PVector steer = PVector.sub(sum, velocity); + steer.limit(maxforce); + applyForce(steer); + } + } + + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void display() { + fill(175); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + ellipse(0, 0, r, r); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } +} + + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde new file mode 100644 index 000000000..afdf7f6b4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A list of vehicles +ArrayList vehicles; + +void setup() { + size(800,200); + // We are now making random vehicles and storing them in an ArrayList + vehicles = new ArrayList(); + for (int i = 0; i < 100; i++) { + vehicles.add(new Vehicle(random(width),random(height))); + } +} + +void draw() { + background(255); + + for (Vehicle v : vehicles) { + // Path following and separation are worked on in this function + v.applyBehaviors(vehicles); + // Call the generic run method (update, borders, display, etc.) + v.update(); + v.display(); + } + + // Instructions + fill(0); + text("Drag the mouse to generate new vehicles.",10,height-16); +} + + +void mouseDragged() { + vehicles.add(new Vehicle(mouseX,mouseY)); +} + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde new file mode 100644 index 000000000..b4270972e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde @@ -0,0 +1,113 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Vehicle { + + // All the usual stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + // Constructor initialize all values + Vehicle(float x, float y) { + location = new PVector(x, y); + r = 12; + maxspeed = 3; + maxforce = 0.2; + acceleration = new PVector(0, 0); + velocity = new PVector(0, 0); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + void applyBehaviors(ArrayList vehicles) { + PVector separateForce = separate(vehicles); + PVector seekForce = seek(new PVector(mouseX,mouseY)); + separateForce.mult(2); + seekForce.mult(1); + applyForce(separateForce); + applyForce(seekForce); + } + + // A method that calculates a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + PVector seek(PVector target) { + PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus velocity + PVector steer = PVector.sub(desired,velocity); + steer.limit(maxforce); // Limit to maximum steering force + + return steer; + } + + // Separation + // Method checks for nearby vehicles and steers away + PVector separate (ArrayList vehicles) { + float desiredseparation = r*2; + PVector sum = new PVector(); + int count = 0; + // For every boid in the system, check if it's too close + for (Vehicle other : vehicles) { + float d = PVector.dist(location, other.location); + // 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(location, other.location); + diff.normalize(); + diff.div(d); // Weight by distance + sum.add(diff); + count++; // Keep track of how many + } + } + // Average -- divide by how many + if (count > 0) { + sum.div(count); + // Our desired vector is the average scaled to maximum speed + sum.normalize(); + sum.mult(maxspeed); + // Implement Reynolds: Steering = Desired - Velocity + sum.sub(velocity); + sum.limit(maxforce); + } + return sum; + } + + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void display() { + fill(175); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + ellipse(0, 0, r, r); + popMatrix(); + } + +} + + + + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties new file mode 100644 index 000000000..6d28cd598 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties @@ -0,0 +1 @@ +mode=JavaScript diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde new file mode 100644 index 000000000..194dfc362 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde @@ -0,0 +1,182 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Boid class +// Methods for Separation, Cohesion, Alignment added + +class Boid { + + PVector location; + 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); + velocity = new PVector(random(-1,1),random(-1,1)); + location = new PVector(x,y); + r = 3.0; + maxspeed = 3; + maxforce = 0.05; + } + + void run(ArrayList 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 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 location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.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,location); // A vector pointing from the location to the target + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(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); + fill(175); + stroke(0); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } + + // Separation + // Method checks for nearby boids and steers away + PVector separate (ArrayList 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(location,other.location); + // 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(location,other.location); + 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) { + // 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 boids) { + float neighbordist = 50; + PVector sum = new PVector(0,0); + int count = 0; + for (Boid other : boids) { + float d = PVector.dist(location,other.location); + if ((d > 0) && (d < neighbordist)) { + sum.add(other.velocity); + count++; + } + } + if (count > 0) { + sum.div((float)count); + 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 location (i.e. center) of all nearby boids, calculate steering vector towards that location + PVector cohesion (ArrayList boids) { + float neighbordist = 50; + PVector sum = new PVector(0,0); // Start with empty vector to accumulate all locations + int count = 0; + for (Boid other : boids) { + float d = PVector.dist(location,other.location); + if ((d > 0) && (d < neighbordist)) { + sum.add(other.location); // Add location + count++; + } + } + if (count > 0) { + sum.div(count); + return seek(sum); // Steer towards the location + } else { + return new PVector(0,0); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Flock.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Flock.pde new file mode 100644 index 000000000..b548b2469 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Flock.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flock class +// Does very little, simply manages the ArrayList of all the boids + +class Flock { + ArrayList boids; // An ArrayList for all the boids + + Flock() { + boids = new ArrayList(); // 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); + } + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde new file mode 100644 index 000000000..f7d8cf42f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Demonstration of Craig Reynolds' "Flocking" behavior +// See: http://www.red3d.com/cwr/ +// Rules: Cohesion, Separation, Alignment + +// Click mouse to add boids into the system + +Flock flock; + +void setup() { + size(800,200); + flock = new Flock(); + // Add an initial set of boids into the system + for (int i = 0; i < 200; i++) { + Boid b = new Boid(width/2,height/2); + flock.addBoid(b); + } + smooth(); +} + +void draw() { + background(255); + flock.run(); + + // Instructions + fill(0); + //text("Drag the mouse to generate new boids.",10,height-16); +} + +// Add a new boid into the System +void mouseDragged() { + flock.addBoid(new Boid(mouseX,mouseY)); +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/StayWithinCircle.pde b/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/StayWithinCircle.pde new file mode 100644 index 000000000..83c90eb27 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/StayWithinCircle.pde @@ -0,0 +1,43 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stay Within Circle +// "Made-up" Steering behavior to stay within walls + +Vehicle v; +boolean debug = true; + + +PVector circleLocation; +float circleRadius; + + + +void setup() { + size(640, 360); + v = new Vehicle(width/2, height/4); + + circleLocation = new PVector(width/2,height/2); + circleRadius = height/2-25; + + smooth(); +} + +void draw() { + background(255); + + if (debug) { + stroke(175); + noFill(); + ellipse(circleLocation.x,circleLocation.y, circleRadius*2,circleRadius*2); + } + + v.boundaries(); + v.run(); +} + +void mousePressed() { + debug = !debug; +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde new file mode 100644 index 000000000..7bc96d2fa --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde @@ -0,0 +1,93 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Vehicle { + + PVector location; + PVector velocity; + PVector acceleration; + float r; + + float maxspeed; + float maxforce; + + Vehicle(float x, float y) { + acceleration = new PVector(0, 0); + velocity = new PVector(1,0); + velocity.mult(5); + location = new PVector(x, y); + r = 3; + maxspeed = 3; + maxforce = 0.15; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + // Update velocity + velocity.add(acceleration); + // Limit speed + velocity.limit(maxspeed); + location.add(velocity); + // Reset accelertion to 0 each cycle + acceleration.mult(0); + } + + void boundaries() { + + PVector desired = null; + + // Predict location 25 (arbitrary choice) frames ahead + PVector predict = velocity.get(); + predict.mult(25); + PVector futureLocation = PVector.add(location, predict); + float distance = PVector.dist(futureLocation,circleLocation); + + if (distance > circleRadius) { + PVector toCenter = PVector.sub(circleLocation,location); + toCenter.normalize(); + toCenter.mult(velocity.mag()); + desired = PVector.add(velocity,toCenter); + desired.normalize(); + desired.mult(maxspeed); + } + + if (desired != null) { + PVector steer = PVector.sub(desired, velocity); + steer.limit(maxforce); + applyForce(steer); + } + + fill(255,0,0); + ellipse(futureLocation.x,futureLocation.y,4,4); + + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acceleration.add(force); + } + + + void display() { + // Draw a triangle rotated in the direction of velocity + float theta = velocity.heading2D() + radians(90); + fill(175); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection/Thing.pde b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection/Thing.pde new file mode 100644 index 000000000..7a739186b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection/Thing.pde @@ -0,0 +1,33 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Daniel Shiffman + +// Simple class describing an ellipse living on our screen + +class Thing { + + float x,y; + boolean highlight; + float r; + + Thing (float x_, float y_) { + x = x_; + y = y_; + highlight = false; + r = random(8) + 1; + } + + void move() { + x += random(-1,1); + y += random(-1,1); + } + + void render() { + noStroke(); + if (highlight) fill(255); + else fill(100); + ellipse(x,y,r,r); + } + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection/intersection.pde b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection/intersection.pde new file mode 100644 index 000000000..a8474b9c3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection/intersection.pde @@ -0,0 +1,105 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Bin-Lattice Spatial Subdivision +// http://www.red3d.com/cwr/papers/2000/pip.pdf + +// Example demonstrating optimized intersection test for large # of objects +// Each object registers its location in a virtual grid +// Only the objects in neighboring cells on the grid are tested against each other + +int totalThings = 2000; + +ArrayList a; // ArrayList for all "things" +ArrayList[][] grid; // Grid of ArrayLists for intersection test +int scl = 4; // Size of each grid cell +int cols, rows; // Total coluns and rows + +void setup() { + size(640,360); + a = new ArrayList(); // Create the list + cols = width/scl; // Calculate cols & rows + rows = height/scl; + + // Initialize grid as 2D array of empty ArrayLists + grid = new ArrayList[cols][rows]; + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + grid[i][j] = new ArrayList(); + } + } + + // Put 2000 Things in the system + for (int i = 0; i < totalThings; i++) { + a.add(new Thing(random(width),random(height))); + } + +} + +void draw() { + background(0); + + // Every time through draw clear all the lists + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + grid[i][j].clear(); + } + } + + // Register every Thing object in the grid according to it's location + for (Thing t : a) { + t.highlight = false; + int x = int(t.x) / scl; + int y = int (t.y) /scl; + // It goes in 9 cells, i.e. every Thing is tested against other Things in its cell + // as well as its 8 neighbors + for (int n = -1; n <= 1; n++) { + for (int m = -1; m <= 1; m++) { + if (x+n >= 0 && x+n < cols && y+m >= 0 && y+m< rows) grid[x+n][y+m].add(t); + } + } + } + + // Run through the Grid + stroke(255); + for (int i = 0; i < cols; i++) { + //line(i*scl,0,i*scl,height); + for (int j = 0; j < rows; j++) { + //line(0,j*scl,width,j*scl); + + // For every list in the grid + ArrayList temp = grid[i][j]; + // Check every Thing + for (Thing t : temp) { + // Against every other Thing + for (Thing other : temp) { + // As long as its not the same one + if (other != t) { + // Check to see if they are touching + // (We could do many other things here besides just intersection tests, such + // as apply forces, etc.) + float d = dist(t.x,t.y,other.x,other.y); + if (d < t.r/2 + other.r/2) { + t.highlight = true; + } + } + } + } + } + } + + // Display and move all Things + for (Thing t : a) { + t.render(); + t.move(); + } + + fill(0); + rect(0,height-20,width,20); + fill(255); + text("Framerate: " + int(frameRate),10,height-6); + + + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection_slow/Thing.pde b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection_slow/Thing.pde new file mode 100644 index 000000000..7a739186b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection_slow/Thing.pde @@ -0,0 +1,33 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Daniel Shiffman + +// Simple class describing an ellipse living on our screen + +class Thing { + + float x,y; + boolean highlight; + float r; + + Thing (float x_, float y_) { + x = x_; + y = y_; + highlight = false; + r = random(8) + 1; + } + + void move() { + x += random(-1,1); + y += random(-1,1); + } + + void render() { + noStroke(); + if (highlight) fill(255); + else fill(100); + ellipse(x,y,r,r); + } + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection_slow/intersection_slow.pde b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection_slow/intersection_slow.pde new file mode 100644 index 000000000..f8303c06e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/binlatticespatialsubdivision/intersection/intersection_slow/intersection_slow.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// The old way to do intersection tests, look how slow!! + +int totalThings = 2000; + +ArrayList a; // ArrayList for all "things" + +void setup() { + size(640,360); + a = new ArrayList(); // Create the list + + // Put 2000 Things in the system + for (int i = 0; i < totalThings; i++) { + a.add(new Thing(random(width),random(height))); + } + +} + +void draw() { + background(0); + fill(255); + noStroke(); + // Run through the Grid + stroke(255); + for (Thing t : a) { + t.highlight = false; + for (Thing other : a) { + // As long as its not the same one + if (t != other) { + // Check to see if they are touching + // (We could do many other things here besides just intersection tests, such + // as apply forces, etc.) + float d = dist(t.x,t.y,other.x,other.y); + if (d < t.r/2 + other.r/2) { + t.highlight = true; + } + } + } + } + + // Display and move all Things + for (Thing t : a) { + t.render(); + t.move(); + } + + fill(0); + rect(0,height-20,width,20); + fill(255); + text("Framerate: " + int(frameRate),10,height-6); + + + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Boid.pde b/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Boid.pde new file mode 100644 index 000000000..85150e404 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Boid.pde @@ -0,0 +1,257 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flocking + +// Boid class +// Methods for Separation, Cohesion, Alignment added + +class Boid { + + // We need to keep track of a Body and a width and height + Body body; + float w; + float h; + + float maxforce; // Maximum steering force + float maxspeed; // Maximum speed + + Boid(PVector loc) { + w = 12; + h = 12; + // Add the box to the box2d world + makeBody(new Vec2(loc.x,loc.y),w,h,new Vec2(0,0),0); + maxspeed = 20; + maxforce = 10; + } + + // This function removes the particle from the box2d world + void killBody() { + box2d.destroyBody(body); + } + + void run(ArrayList boids) { + flock(boids); + borders(); + display(); + } + + // We accumulate a new acceleration each time based on three rules + void flock(ArrayList boids) { + Vec2 sep = separate(boids); // Separation + Vec2 ali = align(boids); // Alignment + Vec2 coh = cohesion(boids); // Cohesion + // Arbitrarily weight these forces + sep.mulLocal(1.5); + ali.mulLocal(1); + coh.mulLocal(1); + // Add the force vectors to acceleration + Vec2 loc = body.getWorldCenter(); + body.applyForce(sep,loc); + body.applyForce(ali,loc); + body.applyForce(coh,loc); + } + + // A method that calculates and applies a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + Vec2 seek(Vec2 target) { + Vec2 loc = body.getWorldCenter(); + Vec2 desired = target.sub(loc); // A vector pointing from the location to the target + + // If the magnitude of desired equals 0, skip out of here + // (We could optimize this to check if x and y are 0 to avoid mag() square root + if (desired.length() == 0) return new Vec2(0,0); + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mulLocal(maxspeed); + // Steering = Desired minus Velocity + + Vec2 vel = body.getLinearVelocity(); + Vec2 steer = desired.sub(vel); + + float len = steer.length(); + if (len > maxforce) { + steer.normalize(); + steer.mulLocal(maxforce); + } + return steer; + } + + + + // Drawing the box + void display() { + // We look at each body and get its screen position + Vec2 pos = box2d.getBodyPixelCoord(body); + + // Get its angle of rotation + float a = body.getAngle(); + + rectMode(CENTER); + pushMatrix(); + translate(pos.x,pos.y); + rotate(-a); + fill(175); + strokeWeight(2); + stroke(0); + rect(0,0,w,h); + popMatrix(); + } + + // Wraparound + void borders() { + Vec2 loc = box2d.getBodyPixelCoord(body); + Vec2 vel = body.getLinearVelocity(); + float a = body.getAngularVelocity(); + if (loc.x < -w) { + killBody(); + makeBody(new Vec2(width+w,loc.y),w,h,vel,a); + } else if (loc.y < -w) { + killBody(); + makeBody(new Vec2(loc.x,height+w),w,h,vel,a); + } else if (loc.x > width+w) { + killBody(); + makeBody(new Vec2(-w,loc.y),w,h,vel,a); + } else if (loc.y > height+w) { + killBody(); + makeBody(new Vec2(loc.x,-w),w,h,vel,a); + } + } + + // Separation + // Method checks for nearby boids and steers away + Vec2 separate (ArrayList boids) { + float desiredseparation = box2d.scalarPixelsToWorld(30); + + Vec2 steer = new Vec2(0,0); + int count = 0; + // For every boid in the system, check if it's too close + Vec2 locA = body.getWorldCenter(); + for (Boid other : boids) { + Vec2 locB = other.body.getWorldCenter(); + float d = dist(locA.x,locA.y,locB.x,locB.y); + // 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 + Vec2 diff = locA.sub(locB); + diff.normalize(); + diff.mulLocal(1.0/d); // Weight by distance + steer.addLocal(diff); + count++; // Keep track of how many + } + } + // Average -- divide by how many + if (count > 0) { + steer.mulLocal(1.0/count); + } + + // As long as the vector is greater than 0 + if (steer.length() > 0) { + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mulLocal(maxspeed); + Vec2 vel = body.getLinearVelocity(); + steer.subLocal(vel); + float len = steer.length(); + if (len > maxforce) { + steer.normalize(); + steer.mulLocal(maxforce); + } + } + return steer; + } + + // Alignment + // For every nearby boid in the system, calculate the average velocity + Vec2 align (ArrayList boids) { + float neighbordist = box2d.scalarPixelsToWorld(50); + Vec2 steer = new Vec2(0,0); + int count = 0; + Vec2 locA = body.getWorldCenter(); + for (Boid other : boids) { + Vec2 locB = other.body.getWorldCenter(); + float d = dist(locA.x,locA.y,locB.x,locB.y); + if ((d > 0) && (d < neighbordist)) { + Vec2 vel = other.body.getLinearVelocity(); + steer.addLocal(vel); + count++; + } + } + if (count > 0) { + steer.mulLocal(1.0/count); + } + + // As long as the vector is greater than 0 + if (steer.length() > 0) { + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mulLocal(maxspeed); + Vec2 vel = body.getLinearVelocity(); + steer.subLocal(vel); + float len = steer.length(); + if (len > maxforce) { + steer.normalize(); + steer.mulLocal(maxforce); + } + } + return steer; + } + + // Cohesion + // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location + Vec2 cohesion (ArrayList boids) { + float neighbordist = box2d.scalarPixelsToWorld(50); + Vec2 sum = new Vec2(0,0); // Start with empty vector to accumulate all locations + int count = 0; + Vec2 locA = body.getWorldCenter(); + for (Boid other : boids) { + Vec2 locB = other.body.getWorldCenter(); + + float d = dist(locA.x,locA.y,locB.x,locB.y); + if ((d > 0) && (d < neighbordist)) { + sum.addLocal(locB); // Add location + count++; + } + } + if (count > 0) { + sum.mulLocal(1.0/count); + return seek(sum); // Steer towards the location + } + return sum; + } + + // This function adds the rectangle to the box2d world + void makeBody(Vec2 center, float w_, float h_, Vec2 vel, float avel) { + + // Define a polygon (this is what we use for a rectangle) + PolygonShape sd = new PolygonShape(); + float box2dW = box2d.scalarPixelsToWorld(w_/2); + float box2dH = box2d.scalarPixelsToWorld(h_/2); + sd.setAsBox(box2dW, box2dH); + + // Define a fixture + FixtureDef fd = new FixtureDef(); + fd.shape = sd; + // Parameters that affect physics + fd.density = 1; + fd.friction = 0.3; + fd.restitution = 0.5; + + // Define the body and make it from the shape + BodyDef bd = new BodyDef(); + bd.type = BodyType.DYNAMIC; + bd.position.set(box2d.coordPixelsToWorld(center)); + + body = box2d.createBody(bd); + body.createFixture(fd); + + body.setLinearVelocity(vel); + body.setAngularVelocity(avel); + + } + + +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Flock.pde b/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Flock.pde new file mode 100644 index 000000000..47b0e7b16 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Flock.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flocking + +// Flock class +// Does very little, simply manages the ArrayList of all the boids + +class Flock { + ArrayList boids; // An arraylist for all the boids + + Flock() { + boids = new ArrayList(); // 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); + } + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Flocking_box2d.pde b/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Flocking_box2d.pde new file mode 100644 index 000000000..39595fbd9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/box2d/Flocking_box2d/Flocking_box2d.pde @@ -0,0 +1,58 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flocking + +// Demonstration of Craig Reynolds' "Flocking" behavior +// See: http://www.red3d.com/cwr/ +// Rules: Cohesion, Separation, Alignment + +// Click mouse to add boids into the system + +import pbox2d.*; +import org.jbox2d.collision.shapes.*; +import org.jbox2d.common.*; +import org.jbox2d.dynamics.*; + +// A reference to our box2d world +PBox2D box2d; + +Flock flock; + +void setup() { + size(640,360); + // Initialize box2d physics and create the world + box2d = new PBox2D(this); + box2d.createWorld(); + // We are setting a custom gravity + box2d.setGravity(0,0); + + flock = new Flock(); + // Add an initial set of boids into the system + for (int i = 0; i < 50; i++) { + flock.addBoid(new Boid(new PVector(random(width),random(height)))); + } + smooth(); +} + +void draw() { + + + // We must always step through time! + box2d.step(); + + background(255); + flock.run(); + +} + +void mousePressed() { + flock.addBoid(new Boid(new PVector(mouseX,mouseY))); +} + +void mouseDragged() { + flock.addBoid(new Boid(new PVector(mouseX,mouseY))); +} + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde new file mode 100644 index 000000000..808b7c6d5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde @@ -0,0 +1,185 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float swt = 25.0; //sep.mult(25.0f); +float awt = 4.0; //ali.mult(4.0f); +float cwt = 5.0; //coh.mult(5.0f); +float maxspeed = 1; +float maxforce = 0.025; + + +// Flocking +// Daniel Shiffman +// The Nature of Code, Spring 2009 + +// Boid class +// Methods for Separation, Cohesion, Alignment added + +class Boid { + + PVector loc; + PVector vel; + PVector acc; + float r; + + Boid(float x, float y) { + acc = new PVector(0,0); + vel = new PVector(random(-1,1),random(-1,1)); + loc = new PVector(x,y); + r = 2.0; + } + + void run(ArrayList boids) { + flock(boids); + update(); + borders(); + render(); + } + + void applyForce(PVector force) { + // We could add mass here if we want A = F / M + acc.add(force); + } + + // We accumulate a new acceleration each time based on three rules + void flock(ArrayList boids) { + PVector sep = separate(boids); // Separation + PVector ali = align(boids); // Alignment + PVector coh = cohesion(boids); // Cohesion + // Arbitrarily weight these forces + sep.mult(swt); + ali.mult(awt); + coh.mult(cwt); + // Add the force vectors to acceleration + applyForce(sep); + applyForce(ali); + applyForce(coh); + } + + // Method to update location + void update() { + // Update velocity + vel.add(acc); + // Limit speed + vel.limit(maxspeed); + loc.add(vel); + // Reset accelertion to 0 each cycle + acc.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,loc); // A vector pointing from the location to the target + + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(maxspeed); + // Steering = Desired minus Velocity + PVector steer = PVector.sub(desired,vel); + steer.limit(maxforce); // Limit to maximum steering force + + return steer; + } + + void render() { + // Draw a triangle rotated in the direction of velocity + float theta = vel.heading2D() + radians(90); + fill(175); + stroke(0); + pushMatrix(); + translate(loc.x,loc.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + } + + // Wraparound + void borders() { + if (loc.x < -r) loc.x = width+r; + if (loc.y < -r) loc.y = height+r; + if (loc.x > width+r) loc.x = -r; + if (loc.y > height+r) loc.y = -r; + } + + // Separation + // Method checks for nearby boids and steers away + PVector separate (ArrayList boids) { + float desiredseparation = 25.0; + PVector steer = new PVector(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(loc,other.loc); + // 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(loc,other.loc); + 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); + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mult(maxspeed); + steer.sub(vel); + steer.limit(maxforce); + } + return steer; + } + + // Alignment + // For every nearby boid in the system, calculate the average velocity + PVector align (ArrayList boids) { + float neighbordist = 50.0; + PVector steer = new PVector(); + int count = 0; + for (Boid other : boids) { + float d = PVector.dist(loc,other.loc); + if ((d > 0) && (d < neighbordist)) { + steer.add(other.vel); + count++; + } + } + if (count > 0) { + steer.div((float)count); + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mult(maxspeed); + steer.sub(vel); + steer.limit(maxforce); + } + return steer; + } + + // Cohesion + // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location + PVector cohesion (ArrayList boids) { + float neighbordist = 50.0; + PVector sum = new PVector(0,0); // Start with empty vector to accumulate all locations + int count = 0; + for (Boid other : boids) { + float d = PVector.dist(loc,other.loc); + if ((d > 0) && (d < neighbordist)) { + sum.add(other.loc); // Add location + count++; + } + } + if (count > 0) { + sum.div((float)count); + return seek(sum); // Steer towards the location + } + return sum; + } +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Flock.pde b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Flock.pde new file mode 100644 index 000000000..b548b2469 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Flock.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flock class +// Does very little, simply manages the ArrayList of all the boids + +class Flock { + ArrayList boids; // An ArrayList for all the boids + + Flock() { + boids = new ArrayList(); // 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); + } + +} diff --git a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/flocking_sliders.pde b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/flocking_sliders.pde new file mode 100644 index 000000000..006e0f43d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/flocking_sliders.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + + +// Flocking +// Demonstration of Craig Reynolds' "Flocking" behavior +// See: http://www.red3d.com/cwr/ +// Rules: Cohesion, Separation, Alignment + +// Click mouse to add boids into the system + +import processing.opengl.*; + + +Flock flock; +PVector center; + +boolean showvalues = true; +boolean scrollbar = false; + + +void setup() { + size(1024,768,OPENGL); + setupScrollbars(); + center = new PVector(width/2,height/2); + colorMode(RGB,255,255,255,100); + flock = new Flock(); + // Add an initial set of boids into the system + for (int i = 0; i < 120; i++) { + flock.addBoid(new Boid(width/2,height/2)); + } + smooth(); +} + + +void draw() { + + background(255); + flock.run(); + drawScrollbars(); + + if (mousePressed && !scrollbar) { + flock.addBoid(new Boid(mouseX,mouseY)); + } + + + if (showvalues) { + fill(0); + textAlign(LEFT); + text("Total boids: " + flock.boids.size() + "\n" + "Framerate: " + round(frameRate) + "\nPress any key to show/hide sliders and text\nClick mouse to add more boids",5,100); + } +} + +void keyPressed() { + showvalues = !showvalues; +} + +void mousePressed() { +} + diff --git a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/keyPressed.pde b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/keyPressed.pde new file mode 100644 index 000000000..b28b04f64 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/keyPressed.pde @@ -0,0 +1,3 @@ + + + diff --git a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/scrollbar.pde b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/scrollbar.pde new file mode 100644 index 000000000..3a6bc39be --- /dev/null +++ b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/scrollbar.pde @@ -0,0 +1,137 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Code based on "Scrollbar" by Casey Reas + +HScrollbar[] hs = new HScrollbar[5];// +String[] labels = {"separation", "alignment","cohesion","maxspeed","maxforce"}; + +int x = 5; +int y = 20; +int w = 50; +int h = 8; +int l = 2; +int spacing = 4; + +void setupScrollbars() { + for (int i = 0; i < hs.length; i++) { + hs[i] = new HScrollbar(x, y + i*(h+spacing), w, h, l); + } + + hs[0].setPos(0.5); + hs[1].setPos(0.5); + hs[2].setPos(0.5); + hs[3].setPos(0.5); + hs[4].setPos(0.05); + +} + +void drawScrollbars() { + //if (showvalues) { + swt = hs[0].getPos()*10.0f; //sep.mult(25.0f); + awt = hs[1].getPos()*2.0f; //sep.mult(25.0f); + cwt = hs[2].getPos()*2.0f; //sep.mult(25.0f); + maxspeed = hs[3].getPos()*10.0f; + maxforce = hs[4].getPos()*0.5; + + + if (showvalues) { + for (int i = 0; i < hs.length; i++) { + hs[i].update(); + hs[i].draw(); + fill(0); + textAlign(LEFT); + text(labels[i],x+w+spacing,y+i*(h+spacing)+spacing); + //text(hs[i].getPos(),x+w+spacing+75,y+i*(h+spacing)+spacing); + } + } +} + + +class HScrollbar +{ + int swidth, sheight; // width and height of bar + int xpos, ypos; // x and y position of bar + float spos, newspos; // x position of slider + int sposMin, sposMax; // max and min values of slider + int loose; // how loose/heavy + boolean over; // is the mouse over the slider? + boolean locked; + float ratio; + + HScrollbar (int xp, int yp, int sw, int sh, int l) { + swidth = sw; + sheight = sh; + int widthtoheight = sw - sh; + ratio = (float)sw / (float)widthtoheight; + xpos = xp; + ypos = yp-sheight/2; + spos = xpos; + newspos = spos; + sposMin = xpos; + sposMax = xpos + swidth - sheight; + loose = l; + } + + void update() { + if(over()) { + over = true; + } + else { + over = false; + } + if(mousePressed && over) { + scrollbar = true; + locked = true; + } + if(!mousePressed) { + locked = false; + scrollbar = false; + } + if(locked) { + newspos = constrain(mouseX-sheight/2, sposMin, sposMax); + } + if(abs(newspos - spos) > 0) { + spos = spos + (newspos-spos)/loose; + } + } + + int constrain(int val, int minv, int maxv) { + return min(max(val, minv), maxv); + } + + boolean over() { + if(mouseX > xpos && mouseX < xpos+swidth && + mouseY > ypos && mouseY < ypos+sheight) { + return true; + } + else { + return false; + } + } + + void draw() { + fill(255); + rectMode(CORNER); + rect(xpos, ypos, swidth, sheight); + if(over || locked) { + fill(153, 102, 0); + } + else { + fill(102, 102, 102); + } + rect(spos, ypos, sheight, sheight); + } + + void setPos(float s) { + spos = xpos + s*(sposMax-sposMin); + newspos = spos; + } + + float getPos() { + // convert spos to be values between + // 0 and the total width of the scrollbar + return ((spos-xpos))/(sposMax-sposMin);// * ratio; + } +} diff --git a/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/Cell.pde b/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/Cell.pde new file mode 100644 index 000000000..13acf5b88 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/Cell.pde @@ -0,0 +1,42 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Cell { + + float x, y; + float w; + float xoff; + float yoff; + + int state; + + Cell(float x_, float y_, float w_) { + x = x_; + y = y_; + w = w_; + xoff = w/2; + yoff = sin(radians(60))*w; + state = int(random(2)); + } + + + void display() { + + fill(state*255); + stroke(0); + pushMatrix(); + translate(x,y); + beginShape(); + vertex(0, yoff); + vertex(xoff, 0); + vertex(xoff+w, 0); + vertex(2*w, yoff); + vertex(xoff+w, 2*yoff); + vertex(xoff, 2*yoff); + vertex(0, yoff); + endShape(); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/Ex7_09_HexagonCells.pde b/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/Ex7_09_HexagonCells.pde new file mode 100644 index 000000000..62e049fe7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/Ex7_09_HexagonCells.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Outline for game of life +// This is just a grid of hexagons right now + +GOL gol; + +void setup() { + size(800, 200); + gol = new GOL(); +} + +void draw() { + background(255); + gol.display(); +} + +// reset board when mouse is pressed +void mousePressed() { + gol.init(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/GOL.pde new file mode 100644 index 000000000..1f1491abe --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Ex7_09_HexagonCells/GOL.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class GOL { + + float w = 20; + float h = sin(radians(60))*w; + int columns, rows; + + // Game of life board + Cell[][] board; + + + GOL() { + // Initialize rows, columns and set-up arrays + columns = width/int(w*3); + rows = height/int(h); + board = new Cell[columns][rows]; + init(); + } + + void init() { + float h = sin(radians(60))*w; + for (int i = 0; i < columns; i++) { + for (int j = 0; j < rows; j++) { + if (j % 2 == 0) board[i][j] = new Cell(i*w*3, j*h,w); + else board[i][j] = new Cell(i*w*3+w+h/2, j*h, w); + } + } + } + + + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + board[i][j].display(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_01_WolframCA_randomizedrules/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_01_WolframCA_randomizedrules/CA.pde new file mode 100644 index 000000000..57f208c2c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_01_WolframCA_randomizedrules/CA.pde @@ -0,0 +1,98 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int[] cells; // An array of 0s and 1s + int generation; // How many generations? + + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + + int w = 5; + + CA(int[] r) { + ruleset = r; + cells = new int[width/w]; + restart(); + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cells.length; i++) { + cells[i] = 0; + } + cells[cells.length/2] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + + // The process of creating the new generation + void generate() { + // First we create an empty array for the new values + int[] nextgen = new int[cells.length]; + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 1; i < cells.length-1; i++) { + int left = cells[i-1]; // Left neighbor state + int me = cells[i]; // Current state + int right = cells[i+1]; // Right neighbor state + nextgen[i] = rules(left, me, right); // Compute next generation state based on ruleset + } + // The current generation is the new generation + cells = nextgen; + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for (int i = 0; i < cells.length; i++) { + if (cells[i] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, generation*w, w, w); + } + } + + // Implementing the Wolfram rules + // This is the concise conversion to binary way + /*int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s, 2); + return ruleset[index]; + }*/ + // For JavaScript Mode + int rules (int a, int b, int c) { + if (a == 1 && b == 1 && c == 1) return ruleset[0]; + if (a == 1 && b == 1 && c == 0) return ruleset[1]; + if (a == 1 && b == 0 && c == 1) return ruleset[2]; + if (a == 1 && b == 0 && c == 0) return ruleset[3]; + if (a == 0 && b == 1 && c == 1) return ruleset[4]; + if (a == 0 && b == 1 && c == 0) return ruleset[5]; + if (a == 0 && b == 0 && c == 1) return ruleset[6]; + if (a == 0 && b == 0 && c == 0) return ruleset[7]; + return 0; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/w) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_01_WolframCA_randomizedrules/Exercise_7_01_WolframCA_randomizedrules.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_01_WolframCA_randomizedrules/Exercise_7_01_WolframCA_randomizedrules.pde new file mode 100644 index 000000000..f39ae6b7f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_01_WolframCA_randomizedrules/Exercise_7_01_WolframCA_randomizedrules.pde @@ -0,0 +1,45 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// When the system reaches bottom of the window, it restarts with a new ruleset +// Mouse click restarts as well + +CA ca; // An object to describe a Wolfram elementary Cellular Automata + +int delay = 0; + +void setup() { + size(800, 200); + background(255); + int[] ruleset = { + 0, 1, 0, 1, 1, 0, 1, 0 + }; // An initial rule system + ca = new CA(ruleset); // Initialize CA + frameRate(30); +} + +void draw() { + ca.display(); // Draw the CA + ca.generate(); + + if (ca.finished()) { // If we're done, clear the screen, pick a new ruleset and restart + delay++; + if (delay > 30) { + background(255); + ca.randomize(); + ca.restart(); + delay = 0; + } + } +} + +void mousePressed() { + background(255); + ca.randomize(); + ca.restart(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling/CA.pde new file mode 100644 index 000000000..085fac824 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling/CA.pde @@ -0,0 +1,95 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int generation; // How many generations? + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + int w = 5; + int[][] matrix; // Store a history of generations in 2D array, not just one + + int cols; + int rows; + + + CA(int[] r) { + ruleset = r; + cols = width/w; + rows = height/w; + matrix = new int[cols][rows]; + restart(); + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + matrix[i][j] = 0; + } + } + matrix[cols/2][0] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + + // The process of creating the new generation + void generate() { + + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 0; i < cols; i++) { + int left = matrix[(i+cols-1)%cols][generation%rows]; // Left neighbor state + int me = matrix[i][generation%rows]; // Current state + int right = matrix[(i+1)%cols][generation%rows]; // Right neighbor state + matrix[i][(generation+1)%rows] = rules(left, me, right); // Compute next generation state based on ruleset + } + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + int offset = generation%rows; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int y = j - offset; + if (y <= 0) y = rows + y; + if (matrix[i][j] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, (y-1)*w, w, w); + } + } + } + + // Implementing the Wolfram rules + // This is the concise conversion to binary way + int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s, 2); + return ruleset[index]; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/w) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling/Exercise_7_04_WolframCA_scrolling.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling/Exercise_7_04_WolframCA_scrolling.pde new file mode 100644 index 000000000..48e551df0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling/Exercise_7_04_WolframCA_scrolling.pde @@ -0,0 +1,37 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// with the system scrolling by +// Also implements wrap around + +CA ca; // An object to describe a Wolfram elementary Cellular Automata + + +void setup() { + size(800, 200); + frameRate(30); + background(255); + int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222 + //int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190 + //int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30 + //int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110 + + ca = new CA(ruleset); // Initialize CA +} + +void draw() { + ca.display(); // Draw the CA + ca.generate(); +} + +void mousePressed() { + saveFrame("222-####.png"); + //background(255); + //ca.randomize(); + //ca.restart(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_110/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_110/CA.pde new file mode 100644 index 000000000..fa62c817f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_110/CA.pde @@ -0,0 +1,107 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int generation; // How many generations? + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + int w = 5; + int[][] matrix; // Store a history of generations in 2D array, not just one + + int cols; + int rows; + + + CA(int[] r) { + ruleset = r; + cols = width/w; + rows = height/w; + matrix = new int[cols][rows]; + restart(); + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + matrix[i][j] = 0; + } + } + matrix[cols/2][0] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + + // The process of creating the new generation + void generate() { + + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 0; i < cols; i++) { + int left = matrix[(i+cols-1)%cols][generation%rows]; // Left neighbor state + int me = matrix[i][generation%rows]; // Current state + int right = matrix[(i+1)%cols][generation%rows]; // Right neighbor state + matrix[i][(generation+1)%rows] = rules(left, me, right); // Compute next generation state based on ruleset + } + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + int offset = generation%rows; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int y = j - offset; + if (y <= 0) y = rows + y; + if (matrix[i][j] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, (y-1)*w, w, w); + } + } + } + + // Implementing the Wolfram rules + // This is the concise conversion to binary way + /*int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s, 2); + return ruleset[index]; + }*/ + // For JavaScript Mode + int rules (int a, int b, int c) { + if (a == 1 && b == 1 && c == 1) return ruleset[7]; + if (a == 1 && b == 1 && c == 0) return ruleset[6]; + if (a == 1 && b == 0 && c == 1) return ruleset[5]; + if (a == 1 && b == 0 && c == 0) return ruleset[4]; + if (a == 0 && b == 1 && c == 1) return ruleset[3]; + if (a == 0 && b == 1 && c == 0) return ruleset[2]; + if (a == 0 && b == 0 && c == 1) return ruleset[1]; + if (a == 0 && b == 0 && c == 0) return ruleset[0]; + return 0; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/w) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_110/Exercise_7_04_WolframCA_scrolling_110.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_110/Exercise_7_04_WolframCA_scrolling_110.pde new file mode 100644 index 000000000..fbf426702 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_110/Exercise_7_04_WolframCA_scrolling_110.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// with the system scrolling by +// Also implements wrap around + +CA ca; // An object to describe a Wolfram elementary Cellular Automata + + +void setup() { + size(800, 100); + frameRate(30); + background(255); + //int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222 + //int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190 + //int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30 + int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110 + + ca = new CA(ruleset); // Initialize CA +} + +void draw() { + ca.display(); // Draw the CA + ca.generate(); +} diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_190/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_190/CA.pde new file mode 100644 index 000000000..fa62c817f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_190/CA.pde @@ -0,0 +1,107 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int generation; // How many generations? + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + int w = 5; + int[][] matrix; // Store a history of generations in 2D array, not just one + + int cols; + int rows; + + + CA(int[] r) { + ruleset = r; + cols = width/w; + rows = height/w; + matrix = new int[cols][rows]; + restart(); + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + matrix[i][j] = 0; + } + } + matrix[cols/2][0] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + + // The process of creating the new generation + void generate() { + + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 0; i < cols; i++) { + int left = matrix[(i+cols-1)%cols][generation%rows]; // Left neighbor state + int me = matrix[i][generation%rows]; // Current state + int right = matrix[(i+1)%cols][generation%rows]; // Right neighbor state + matrix[i][(generation+1)%rows] = rules(left, me, right); // Compute next generation state based on ruleset + } + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + int offset = generation%rows; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int y = j - offset; + if (y <= 0) y = rows + y; + if (matrix[i][j] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, (y-1)*w, w, w); + } + } + } + + // Implementing the Wolfram rules + // This is the concise conversion to binary way + /*int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s, 2); + return ruleset[index]; + }*/ + // For JavaScript Mode + int rules (int a, int b, int c) { + if (a == 1 && b == 1 && c == 1) return ruleset[7]; + if (a == 1 && b == 1 && c == 0) return ruleset[6]; + if (a == 1 && b == 0 && c == 1) return ruleset[5]; + if (a == 1 && b == 0 && c == 0) return ruleset[4]; + if (a == 0 && b == 1 && c == 1) return ruleset[3]; + if (a == 0 && b == 1 && c == 0) return ruleset[2]; + if (a == 0 && b == 0 && c == 1) return ruleset[1]; + if (a == 0 && b == 0 && c == 0) return ruleset[0]; + return 0; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/w) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_190/Exercise_7_04_WolframCA_scrolling_190.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_190/Exercise_7_04_WolframCA_scrolling_190.pde new file mode 100644 index 000000000..bf9542216 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_190/Exercise_7_04_WolframCA_scrolling_190.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// with the system scrolling by +// Also implements wrap around + +CA ca; // An object to describe a Wolfram elementary Cellular Automata + + +void setup() { + size(800, 100); + frameRate(30); + background(255); + //int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222 + int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190 + //int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30 + //int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110 + + ca = new CA(ruleset); // Initialize CA +} + +void draw() { + ca.display(); // Draw the CA + ca.generate(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_222/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_222/CA.pde new file mode 100644 index 000000000..fa62c817f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_222/CA.pde @@ -0,0 +1,107 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int generation; // How many generations? + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + int w = 5; + int[][] matrix; // Store a history of generations in 2D array, not just one + + int cols; + int rows; + + + CA(int[] r) { + ruleset = r; + cols = width/w; + rows = height/w; + matrix = new int[cols][rows]; + restart(); + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + matrix[i][j] = 0; + } + } + matrix[cols/2][0] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + + // The process of creating the new generation + void generate() { + + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 0; i < cols; i++) { + int left = matrix[(i+cols-1)%cols][generation%rows]; // Left neighbor state + int me = matrix[i][generation%rows]; // Current state + int right = matrix[(i+1)%cols][generation%rows]; // Right neighbor state + matrix[i][(generation+1)%rows] = rules(left, me, right); // Compute next generation state based on ruleset + } + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + int offset = generation%rows; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int y = j - offset; + if (y <= 0) y = rows + y; + if (matrix[i][j] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, (y-1)*w, w, w); + } + } + } + + // Implementing the Wolfram rules + // This is the concise conversion to binary way + /*int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s, 2); + return ruleset[index]; + }*/ + // For JavaScript Mode + int rules (int a, int b, int c) { + if (a == 1 && b == 1 && c == 1) return ruleset[7]; + if (a == 1 && b == 1 && c == 0) return ruleset[6]; + if (a == 1 && b == 0 && c == 1) return ruleset[5]; + if (a == 1 && b == 0 && c == 0) return ruleset[4]; + if (a == 0 && b == 1 && c == 1) return ruleset[3]; + if (a == 0 && b == 1 && c == 0) return ruleset[2]; + if (a == 0 && b == 0 && c == 1) return ruleset[1]; + if (a == 0 && b == 0 && c == 0) return ruleset[0]; + return 0; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/w) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_222/Exercise_7_04_WolframCA_scrolling_222.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_222/Exercise_7_04_WolframCA_scrolling_222.pde new file mode 100644 index 000000000..24f356e7e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_222/Exercise_7_04_WolframCA_scrolling_222.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// with the system scrolling by +// Also implements wrap around + +CA ca; // An object to describe a Wolfram elementary Cellular Automata + + +void setup() { + size(800, 100); + frameRate(30); + background(255); + int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222 + //int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190 + //int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30 + //int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110 + + ca = new CA(ruleset); // Initialize CA +} + +void draw() { + ca.display(); // Draw the CA + ca.generate(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_30/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_30/CA.pde new file mode 100644 index 000000000..2353dcb9b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_30/CA.pde @@ -0,0 +1,106 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int generation; // How many generations? + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + int w = 5; + int[][] matrix; // Store a history of generations in 2D array, not just one + + int cols; + int rows; + + + CA(int[] r) { + ruleset = r; + cols = width/w; + rows = height/w; + matrix = new int[cols][rows]; + restart(); + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + matrix[i][j] = 0; + } + } + matrix[cols/2][0] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + + // The process of creating the new generation + void generate() { + + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 0; i < cols; i++) { + int left = matrix[(i+cols-1)%cols][generation%rows]; // Left neighbor state + int me = matrix[i][generation%rows]; // Current state + int right = matrix[(i+1)%cols][generation%rows]; // Right neighbor state + matrix[i][(generation+1)%rows] = rules(left, me, right); // Compute next generation state based on ruleset + } + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + int offset = generation%rows; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int y = j - offset; + if (y <= 0) y = rows + y; + if (matrix[i][j] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, (y-1)*w, w, w); + } + } + } + // Implementing the Wolfram rules + // This is the concise conversion to binary way + /*int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s, 2); + return ruleset[index]; + }*/ + // For JavaScript Mode + int rules (int a, int b, int c) { + if (a == 1 && b == 1 && c == 1) return ruleset[7]; + if (a == 1 && b == 1 && c == 0) return ruleset[6]; + if (a == 1 && b == 0 && c == 1) return ruleset[5]; + if (a == 1 && b == 0 && c == 0) return ruleset[4]; + if (a == 0 && b == 1 && c == 1) return ruleset[3]; + if (a == 0 && b == 1 && c == 0) return ruleset[2]; + if (a == 0 && b == 0 && c == 1) return ruleset[1]; + if (a == 0 && b == 0 && c == 0) return ruleset[0]; + return 0; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/w) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_30/Exercise_7_04_WolframCA_scrolling_30.pde b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_30/Exercise_7_04_WolframCA_scrolling_30.pde new file mode 100644 index 000000000..f77d59cb1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Exercise_7_04_WolframCA_scrolling_30/Exercise_7_04_WolframCA_scrolling_30.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// with the system scrolling by +// Also implements wrap around + +CA ca; // An object to describe a Wolfram elementary Cellular Automata + + +void setup() { + size(800, 100); + frameRate(30); + background(255); + //int[] ruleset = {0,1,1,1,1,0,1,1}; // Rule 222 + //int[] ruleset = {0,1,1,1,1,1,0,1}; // Rule 190 + int[] ruleset = {0,1,1,1,1,0,0,0}; // Rule 30 + //int[] ruleset = {0,1,1,1,0,1,1,0}; // Rule 110 + + ca = new CA(ruleset); // Initialize CA +} + +void draw() { + ca.display(); // Draw the CA + ca.generate(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Figure_7_17_cells/Figure_7_17_cells.pde b/java/examples/Books/Nature of Code/chp7_CA/Figure_7_17_cells/Figure_7_17_cells.pde new file mode 100644 index 000000000..ef16d1b06 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/Figure_7_17_cells/Figure_7_17_cells.pde @@ -0,0 +1,31 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +size(1800,90); + +int w = 90; + +int total = width/w; + +int[] cells = {1,0,1,0,0,0,0,1,0,1,1,1,0,0,0,1,1,1,0,0}; + + +print("int[] cells = {"); +for (int i = 0; i < cells.length; i++) { + if (cells[i] == 0) fill(255); + else fill(64); + stroke(0); + rect(i*w,0,w-1,w-1); + print(cells[i] +","); +} + +saveFrame("cells.png"); + + + + + + + + diff --git a/java/examples/Books/Nature of Code/chp7_CA/Figure_7_17_cells/cells.tif b/java/examples/Books/Nature of Code/chp7_CA/Figure_7_17_cells/cells.tif new file mode 100644 index 000000000..38ef13501 Binary files /dev/null and b/java/examples/Books/Nature of Code/chp7_CA/Figure_7_17_cells/cells.tif differ diff --git a/java/examples/Books/Nature of Code/chp7_CA/GameOfLifeWrapAround/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/GameOfLifeWrapAround/GOL.pde new file mode 100644 index 000000000..3fd3a82d5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/GameOfLifeWrapAround/GOL.pde @@ -0,0 +1,77 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class GOL { + + int w = 8; + int columns, rows; + + // Game of life board + int[][] board; + + + GOL() { + // Initialize rows, columns and set-up arrays + columns = width/w; + rows = height/w; + board = new int[columns][rows]; + //next = new int[columns][rows]; + // Call function to fill array with random values 0 or 1 + init(); + } + + void init() { + for (int i =1;i < columns-1;i++) { + for (int j =1;j < rows-1;j++) { + board[i][j] = int(random(2)); + } + } + } + + // The process of creating the new generation + void generate() { + + int[][] next = new int[columns][rows]; + + // Loop through every spot in our 2D array and check spots neighbors + for (int x = 0; x < columns; x++) { + for (int y = 0; y < rows; y++) { + + // Add up all the states in a 3x3 surrounding grid + int neighbors = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + neighbors += board[(x+i+columns)%columns][(y+j+rows)%rows]; + } + } + + // A little trick to subtract the current cell's state since + // we added it in the above loop + neighbors -= board[x][y]; + + // Rules of Life + if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0; // Loneliness + else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0; // Overpopulation + else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1; // Reproduction + else next[x][y] = board[x][y]; // Stasis + } + } + + // Next is now our board + board = next; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + if ((board[i][j] == 1)) fill(0); + else fill(255); + stroke(0); + rect(i*w, j*w, w, w); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/GameOfLifeWrapAround/GameOfLifeWrapAround.pde b/java/examples/Books/Nature of Code/chp7_CA/GameOfLifeWrapAround/GameOfLifeWrapAround.pde new file mode 100644 index 000000000..f807dbebc --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/GameOfLifeWrapAround/GameOfLifeWrapAround.pde @@ -0,0 +1,33 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Daniel Shiffman, Nature of Code + +// A basic implementation of John Conway's Game of Life CA +// how could this be improved to use object oriented programming? +// think of it as similar to our particle system, with a "cell" class +// to describe each individual cell and a "cellular automata" class +// to describe a collection of cells + +// Cells wrap around + +GOL gol; + +void setup() { + size(400, 400); + gol = new GOL(); +} + +void draw() { + background(255); + + gol.generate(); + gol.display(); +} + +// reset board when mouse is pressed +void mousePressed() { + gol.init(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/Cell.pde b/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/Cell.pde new file mode 100644 index 000000000..13acf5b88 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/Cell.pde @@ -0,0 +1,42 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Cell { + + float x, y; + float w; + float xoff; + float yoff; + + int state; + + Cell(float x_, float y_, float w_) { + x = x_; + y = y_; + w = w_; + xoff = w/2; + yoff = sin(radians(60))*w; + state = int(random(2)); + } + + + void display() { + + fill(state*255); + stroke(0); + pushMatrix(); + translate(x,y); + beginShape(); + vertex(0, yoff); + vertex(xoff, 0); + vertex(xoff+w, 0); + vertex(2*w, yoff); + vertex(xoff+w, 2*yoff); + vertex(xoff, 2*yoff); + vertex(0, yoff); + endShape(); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/GOL.pde new file mode 100644 index 000000000..1f1491abe --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/GOL.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class GOL { + + float w = 20; + float h = sin(radians(60))*w; + int columns, rows; + + // Game of life board + Cell[][] board; + + + GOL() { + // Initialize rows, columns and set-up arrays + columns = width/int(w*3); + rows = height/int(h); + board = new Cell[columns][rows]; + init(); + } + + void init() { + float h = sin(radians(60))*w; + for (int i = 0; i < columns; i++) { + for (int j = 0; j < rows; j++) { + if (j % 2 == 0) board[i][j] = new Cell(i*w*3, j*h,w); + else board[i][j] = new Cell(i*w*3+w+h/2, j*h, w); + } + } + } + + + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + board[i][j].display(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/HexagonCells.pde b/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/HexagonCells.pde new file mode 100644 index 000000000..6bd52053b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/HexagonCells/HexagonCells.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Outline for game of life +// This is just a grid of hexagons right now + +GOL gol; + +void setup() { + size(600, 600); + gol = new GOL(); +} + +void draw() { + background(255); + gol.display(); +} + +// reset board when mouse is pressed +void mousePressed() { + gol.init(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_figures/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_figures/CA.pde new file mode 100644 index 000000000..b0309e63b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_figures/CA.pde @@ -0,0 +1,95 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int[] cells; // An array of 0s and 1s + int generation; // How many generations? + + int[] ruleset; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + + CA(int[] r) { + ruleset = r; + cells = new int[width/scl]; + restart(); + } + + CA() { + scl = 1; + cells = new int[width/scl]; + randomize(); + restart(); + } + + // Set the rules of the CA + void setRules(int[] r) { + ruleset = r; + } + + // Make a random ruleset + void randomize() { + for (int i = 0; i < 8; i++) { + ruleset[i] = int(random(2)); + } + } + + // Reset to generation 0 + void restart() { + for (int i = 0; i < cells.length; i++) { + cells[i] = 0; + } + cells[cells.length/2] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + // The process of creating the new generation + void generate() { + // First we create an empty array for the new values + int[] nextgen = new int[cells.length]; + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 1; i < cells.length-1; i++) { + int left = cells[i-1]; // Left neighbor state + int me = cells[i]; // Current state + int right = cells[i+1]; // Right neighbor state + nextgen[i] = rules(left, me, right); // Compute next generation state based on ruleset + } + // The current generation is the new generation + cells = nextgen; + generation++; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void render() { + for (int i = 0; i < cells.length; i++) { + if (cells[i] == 1) fill(0); + else fill(255); + stroke(0); + rect(i*scl, generation*scl, scl, scl); + } + } + + // Implementing the Wolfram rules + // Could be improved and made more concise, but here we can explicitly see what is going on for each case + int rules (int a, int b, int c) { + String s = "" + a + b + c; + int index = Integer.parseInt(s,2); + return ruleset[index]; + } + + // The CA is done if it reaches the bottom of the screen + boolean finished() { + if (generation > height/scl) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_figures/NOC_7_01_WolframCA_figures.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_figures/NOC_7_01_WolframCA_figures.pde new file mode 100644 index 000000000..8e7ea3f4c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_figures/NOC_7_01_WolframCA_figures.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata +// When the system reaches bottom of the window, it restarts with a new ruleset +// Mouse click restarts as well + + +CA ca; // An instance object to describe the Wolfram basic Cellular Automata + +int scl = 20; + +void setup() { + size(1800,600); + background(255); + //int[] ruleset = {0,1,0,1,1,0,1,0}; // 90 + int[] ruleset = {0,1,1,1,1,0,1,1}; // An initial rule system + ca = new CA(ruleset); // Initialize CA +} + +void draw() { + ca.render(); // Draw the CA + ca.generate(); // Generate the next level + + if (ca.finished()) { // If we're done, clear the screen, pick a new ruleset and restart + saveFrame("rule222.png"); + noLoop(); + } +} + +void mousePressed() { + background(255); + ca.randomize(); + ca.restart(); +} diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_simple/CA.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_simple/CA.pde new file mode 100644 index 000000000..a6e158470 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_simple/CA.pde @@ -0,0 +1,70 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Wolfram Cellular Automata + +// A class to manage the CA + +class CA { + + int[] cells; // An array of 0s and 1s + int generation; // How many generations? + + int[] ruleset = {0, 1, 0, 1, 1, 0, 1, 0}; // An array to store the ruleset, for example {0,1,1,0,1,1,0,1} + + int w = 10; + + CA() { + cells = new int[width/w]; + for (int i = 0; i < cells.length; i++) { + cells[i] = 0; + } + cells[cells.length/2] = 1; // We arbitrarily start with just the middle cell having a state of "1" + generation = 0; + } + + // The process of creating the new generation + void generate() { + // First we create an empty array for the new values + int[] nextgen = new int[cells.length]; + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (int i = 1; i < cells.length-1; i++) { + int left = cells[i-1]; // Left neighbor state + int me = cells[i]; // Current state + int right = cells[i+1]; // Right neighbor state + nextgen[i] = rules(left, me, right); // Compute next generation state based on ruleset + } + // The current generation is the new generation + cells = nextgen; + generation++; + + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for (int i = 0; i < cells.length; i++) { + if (cells[i] == 1) fill(0); + else fill(255); + noStroke(); + rect(i*w, generation*w, w, w); + } + } + + + + // Implementing the Wolfram rules + // Could be improved and made more concise, but here we can explicitly see what is going on for each case + int rules (int a, int b, int c) { + if (a == 1 && b == 1 && c == 1) return ruleset[0]; + if (a == 1 && b == 1 && c == 0) return ruleset[1]; + if (a == 1 && b == 0 && c == 1) return ruleset[2]; + if (a == 1 && b == 0 && c == 0) return ruleset[3]; + if (a == 0 && b == 1 && c == 1) return ruleset[4]; + if (a == 0 && b == 1 && c == 0) return ruleset[5]; + if (a == 0 && b == 0 && c == 1) return ruleset[6]; + if (a == 0 && b == 0 && c == 0) return ruleset[7]; + return 0; + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_simple/NOC_7_01_WolframCA_simple.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_simple/NOC_7_01_WolframCA_simple.pde new file mode 100644 index 000000000..e26b35453 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_01_WolframCA_simple/NOC_7_01_WolframCA_simple.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Wolfram Cellular Automata + +// Simple demonstration of a Wolfram 1-dimensional cellular automata + +CA ca; // An instance object to describe the Wolfram basic Cellular Automata + + +void setup() { + size(800, 400); + background(255); + ca = new CA(); // Initialize CA +} + +void draw() { + ca.display(); // Draw the CA + if (ca.generation < height/ca.w) { + ca.generate(); + } + +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/Cell.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/Cell.pde new file mode 100644 index 000000000..d18e16933 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/Cell.pde @@ -0,0 +1,40 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Cell { + + float x, y; + float w; + + int state; + int previous; + + Cell(float x_, float y_, float w_) { + x = x_; + y = y_; + w = w_; + + state = int(random(2)); + previous = state; + } + + void savePrevious() { + previous = state; + } + + void newState(int s) { + state = s; + } + + void display() { + if (previous == 0 && state == 1) fill(0,0,255); + else if (state == 1) fill(0); + else if (previous == 1 && state == 0) fill(255,0,0); + else fill(255); + stroke(0); + rect(x, y, w, w); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/GOL.pde new file mode 100644 index 000000000..cdf3f3ad2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/GOL.pde @@ -0,0 +1,73 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class GOL { + + int w = 8; + int columns, rows; + + // Game of life board + Cell[][] board; + + + GOL() { + // Initialize rows, columns and set-up arrays + columns = width/w; + rows = height/w; + board = new Cell[columns][rows]; + init(); + } + + void init() { + for (int i = 0; i < columns; i++) { + for (int j = 0; j < rows; j++) { + board[i][j] = new Cell(i*w, j*w, w); + } + } + } + + // The process of creating the new generation + void generate() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + board[i][j].savePrevious(); + } + } + + + // Loop through every spot in our 2D array and check spots neighbors + for (int x = 0; x < columns; x++) { + for (int y = 0; y < rows; y++) { + + // Add up all the states in a 3x3 surrounding grid + int neighbors = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + neighbors += board[(x+i+columns)%columns][(y+j+rows)%rows].previous; + } + } + + // A little trick to subtract the current cell's state since + // we added it in the above loop + neighbors -= board[x][y].previous; + + // Rules of Life + if ((board[x][y].state == 1) && (neighbors < 2)) board[x][y].newState(0); // Loneliness + else if ((board[x][y].state == 1) && (neighbors > 3)) board[x][y].newState(0); // Overpopulation + else if ((board[x][y].state == 0) && (neighbors == 3)) board[x][y].newState(1); // Reproduction + // else do nothing! + } + } + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + board[i][j].display(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde new file mode 100644 index 000000000..a0d0ee3f2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A basic implementation of John Conway's Game of Life CA + +// Each cell is now an object! + +GOL gol; + +void setup() { + size(400, 400); + gol = new GOL(); +} + +void draw() { + background(255); + + gol.generate(); + gol.display(); +} + +// reset board when mouse is pressed +void mousePressed() { + gol.init(); +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/GOL.pde new file mode 100644 index 000000000..413318d9d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/GOL.pde @@ -0,0 +1,77 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class GOL { + + int w = 8; + int columns, rows; + + // Game of life board + int[][] board; + + + GOL() { + // Initialize rows, columns and set-up arrays + columns = width/w; + rows = height/w; + board = new int[columns][rows]; + //next = new int[columns][rows]; + // Call function to fill array with random values 0 or 1 + init(); + } + + void init() { + for (int i =1;i < columns-1;i++) { + for (int j =1;j < rows-1;j++) { + board[i][j] = int(random(2)); + } + } + } + + // The process of creating the new generation + void generate() { + + int[][] next = new int[columns][rows]; + + // Loop through every spot in our 2D array and check spots neighbors + for (int x = 1; x < columns-1; x++) { + for (int y = 1; y < rows-1; y++) { + + // Add up all the states in a 3x3 surrounding grid + int neighbors = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + neighbors += board[x+i][y+j]; + } + } + + // A little trick to subtract the current cell's state since + // we added it in the above loop + neighbors -= board[x][y]; + + // Rules of Life + if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0; // Loneliness + else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0; // Overpopulation + else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1; // Reproduction + else next[x][y] = board[x][y]; // Stasis + } + } + + // Next is now our board + board = next; + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + if ((board[i][j] == 1)) fill(0); + else fill(255); + stroke(0); + rect(i*w, j*w, w, w); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde new file mode 100644 index 000000000..29d9843c7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A basic implementation of John Conway's Game of Life CA +// how could this be improved to use object oriented programming? +// think of it as similar to our particle system, with a "cell" class +// to describe each individual cell and a "cellular automata" class +// to describe a collection of cells + +GOL gol; + +void setup() { + size(400, 400); + gol = new GOL(); +} + +void draw() { + background(255); + + gol.generate(); + gol.display(); +} + +// reset board when mouse is pressed +void mousePressed() { + gol.init(); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/CantorSetArrayList/CantorSetArrayList.pde b/java/examples/Books/Nature of Code/chp8_fractals/CantorSetArrayList/CantorSetArrayList.pde new file mode 100644 index 000000000..3c3d86023 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/CantorSetArrayList/CantorSetArrayList.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Cantor Set +// Renders a simple fractal, the Cantor Set +// Uses an ArrayList to store list of objects +// Generates when mouse is pressed + +float h = 30; + +// List of line objects +ArrayList cantor; + +void setup() { + size(729, 200); + + // Start with one line + cantor = new ArrayList(); + cantor.add(new CantorLine(0, 100, width)); +} + +// Click the mouse to advance the sequence +void mousePressed() { + generate(); +} + +void draw() { + background(255); + // Always show all the lines + for (CantorLine cl : cantor) { + cl.display(); + } + + fill(0); + text("Click mouse to generate",10,height-20); +} + +void generate() { + // Generate the next set of lines + ArrayList next = new ArrayList(); + for (CantorLine cl : cantor) { + next.add(new CantorLine(cl.x,cl.y,cl.len/3)); + next.add(new CantorLine(cl.x+cl.len*2/3,cl.y,cl.len/3)); + } + cantor = next; +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/CantorSetArrayList/Line.pde b/java/examples/Books/Nature of Code/chp8_fractals/CantorSetArrayList/Line.pde new file mode 100644 index 000000000..2677ac37b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/CantorSetArrayList/Line.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Cantor line is a simple horizontal line with a starting point +// and length + +class CantorLine { + float x,y; + float len; + + CantorLine(float x_, float y_, float len_) { + x = x_; + y = y_; + len = len_; + } + + void display() { + stroke(0); + line(x,y,x+len,y); + } + +} diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_01_RecursionLines/Exercise_8_01_RecursionLines.pde b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_01_RecursionLines/Exercise_8_01_RecursionLines.pde new file mode 100644 index 000000000..e90258a0b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_01_RecursionLines/Exercise_8_01_RecursionLines.pde @@ -0,0 +1,36 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Recursion + +void setup() { + size(800, 200); +} + +void draw() { + background(255); + drawLines(100,100,700,100); + noLoop(); +} + +void drawLines(float x1, float y1, float x2, float y2) { + + line(x1,y1,x2,y2); + + float dx = x2-x1; + float dy = y2-y1; + + //println(dx + " " + dy); + + if (dx == 0 && dy > 4) { + //println(dy); + drawLines(x1-dy/3,y1,x1+dy/3,y1); + drawLines(x1-dy/3,y2,x1+dy/3,y2); + } else if (dy == 0 && dx > 4) { + //println(dx); + drawLines(x1,y1-dx/3,x1,y1+dx/3); + drawLines(x2,y1-dx/3,x2,y1+dx/3); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_02_KochSnowFlake/Exercise_8_02_KochSnowFlake.pde b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_02_KochSnowFlake/Exercise_8_02_KochSnowFlake.pde new file mode 100644 index 000000000..c5e5f6b86 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_02_KochSnowFlake/Exercise_8_02_KochSnowFlake.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Snowflake + +// Renders a simple fractal, the Koch snowflake +// Each recursive level drawn in sequence + +ArrayList lines ; // A list to keep track of all the lines + +void setup() { + size(600, 692); + background(255); + lines = new ArrayList(); + PVector a = new PVector(0, 173); + PVector b = new PVector(width, 173); + PVector c = new PVector(width/2, 173+width*cos(radians(30))); + + // Starting with additional lines + lines.add(new KochLine(a, b)); + lines.add(new KochLine(b, c)); + lines.add(new KochLine(c, a)); + + for (int i = 0; i < 5; i++) { + generate(); + } +} + +void draw() { + background(255); + for (KochLine l : lines) { + l.display(); + } +} + +void generate() { + ArrayList next = new ArrayList(); // Create emtpy list + for (KochLine l : lines) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.kochA(); + PVector b = l.kochB(); + PVector c = l.kochC(); + PVector d = l.kochD(); + PVector e = l.kochE(); + // Make line segments between all the PVectors and add them + next.add(new KochLine(a, b)); + next.add(new KochLine(b, c)); + next.add(new KochLine(c, d)); + next.add(new KochLine(d, e)); + } + lines = next; +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_02_KochSnowFlake/KochLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_02_KochSnowFlake/KochLine.pde new file mode 100644 index 000000000..8b2b5aab9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_02_KochSnowFlake/KochLine.pde @@ -0,0 +1,75 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve + +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector start; + PVector end; + + KochLine(PVector a, PVector b) { + start = a.get(); + end = b.get(); + } + + void display() { + stroke(0); + strokeWeight(2); + line(start.x, start.y, end.x, end.y); + } + + PVector kochA() { + return start.get(); + } + + + // This is easy, just 1/3 of the way + PVector kochB() { + PVector v = PVector.sub(end, start); + v.div(3); + v.add(start); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochC() { + PVector a = start.get(); // Start at the beginning + + PVector v = PVector.sub(end, start); + v.div(3); + a.add(v); // Move to point B + + rotate(v, -radians(60)); // Rotate 60 degrees + a.add(v); // Move to point C + + return a; + } + + // Easy, just 2/3 of the way + PVector kochD() { + PVector v = PVector.sub(end, start); + v.mult(2/3.0); + v.add(start); + return v; + } + + PVector kochE() { + return end.get(); + } +} + +public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*PApplet.cos(theta) - v.y*PApplet.sin(theta); + v.y = xTemp*PApplet.sin(theta) + v.y*PApplet.cos(theta); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_06_Tree/Exercise_8_06_Tree.pde b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_06_Tree/Exercise_8_06_Tree.pde new file mode 100644 index 000000000..ced569b79 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_06_Tree/Exercise_8_06_Tree.pde @@ -0,0 +1,58 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree + +// Renders a simple tree-like structure via recursion +// Branching angle calculated as a function of horizontal mouse location + +float theta; + +void setup() { + size(1800, 500); + smooth(); +} + +void draw() { + background(255); + // Let's pick an angle 0 to 90 degrees based on the mouse position + theta = PI/6;//map(mouseX,0,width,0,PI/2); + + // Start the tree from the bottom of the screen + translate(width/2, height); + stroke(0); + branch(200,0); + save("chapter08_exc06.png"); + noLoop(); +} + +void branch(float len, int level) { + // Each branch will be 2/3rds the size of the previous one + + //float sw = map(len,2,120,1,10); + //strokeWeight(sw); + strokeWeight(2); + + line(0, 0, 0, -len); + // Move to the end of that line + translate(0, -len); + + len *= 0.66; + level++; + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (level < 5) { + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(len,level); // Ok, now call myself to draw two new branches!! + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + pushMatrix(); + rotate(-theta); + branch(len,level); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_07_Tree/Exercise_8_07_Tree.pde b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_07_Tree/Exercise_8_07_Tree.pde new file mode 100644 index 000000000..a626aa61d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Exercise_8_07_Tree/Exercise_8_07_Tree.pde @@ -0,0 +1,52 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree +// Renders a simple tree-like structure via recursion +// Branching angle calculated as a function of horizontal mouse location + +float theta; + +void setup() { + size(800, 200); + smooth(); +} + +void draw() { + background(255); + // Let's pick an angle 0 to 90 degrees based on the mouse position + theta = map(mouseX,0,width,0,PI/2); + + // Start the tree from the bottom of the screen + translate(width/2, height); + stroke(0); + branch(60); +} + +void branch(float len) { + // Each branch will be 2/3rds the size of the previous one + float sw = map(len,2,120,1,10); + strokeWeight(sw); + + line(0, 0, 0, -len); + // Move to the end of that line + translate(0, -len); + + len *= 0.66; + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (len > 2) { + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(len); // Ok, now call myself to draw two new branches!! + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + pushMatrix(); + rotate(-theta); + branch(len); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_02_Mandelbrot/Figure_8_02_Mandelbrot.pde b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_02_Mandelbrot/Figure_8_02_Mandelbrot.pde new file mode 100644 index 000000000..6883037b6 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_02_Mandelbrot/Figure_8_02_Mandelbrot.pde @@ -0,0 +1,80 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// The Mandelbrot Set + +// Simple rendering of the Mandelbrot set +// c = a + bi +// Iterate z = z^2 + c, i.e. +// z(0) = 0 +// z(1) = 0*0 + c +// z(2) = c*c + c +// z(3) = (c*c + c) * (c*c + c) + c +// etc. + +// c*c = (a+bi) * (a+bi) = a^2 - b^2 + 2abi + +// Establish a range of values on the complex plane +double xmin = -2.5; double ymin = -1; double w = 4; double h = 2; +// A different range will allow us to "zoom" in or out on the fractal +// double xmin = -1.5; double ymin = -.1; double wh = 0.15; + +void setup() { + size(863,863/2); +} + +void draw() { + + loadPixels(); + + // Maximum number of iterations for each point on the complex plane + int maxiterations = 200; + + // x goes from xmin to xmax + double xmax = xmin + w; + // y goes from ymin to ymax + double ymax = ymin + h; + + // Calculate amount we increment x,y for each pixel + double dx = (xmax - xmin) / (width); + double dy = (ymax - ymin) / (height); + + // Start y + double y = ymin; + for(int j = 0; j < height; j++) { + // Start x + double x = xmin; + for(int i = 0; i < width; i++) { + + // Now we test, as we iterate z = z^2 + cm does z tend towards infinity? + double a = x; + double b = y; + int n = 0; + while (n < maxiterations) { + double aa = a * a; + double bb = b * b; + double twoab = 2.0 * a * b; + a = aa - bb + x; + b = twoab + y; + // Infinty in our finite world is simple, let's just consider it 16 + if(aa + bb > 16.0f) { + break; // Bail + } + n++; + } + + // We color each pixel based on how long it takes to get to infinity + // If we never got there, let's pick the color black + if (n == maxiterations) pixels[i+j*width] = color(0); + else pixels[i+j*width] = color(n*16 % 255); // Gosh, we could make fancy colors here if we wanted + x += dx; + } + y += dy; + } + updatePixels(); + + save("chapter08_02.png"); + noLoop(); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_14_Koch/Figure_8_14_Koch.pde b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_14_Koch/Figure_8_14_Koch.pde new file mode 100644 index 000000000..d9d8b0bee --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_14_Koch/Figure_8_14_Koch.pde @@ -0,0 +1,67 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve + +// Renders a simple fractal, the Koch snowflake +// Each recursive level drawn in sequence + +ArrayList lines ; // A list to keep track of all the lines + +void setup() { + size(1820, 200); + + + smooth(); +} + + + +void draw() { + translate(10,0); + int spacing = 10; + int total = 5; + + background(255); + float w = (1800-spacing*(total-1))/5; + for (int n = 0; n < total; n++) { + lines = new ArrayList(); + PVector start = new PVector(0, height*2/3); + PVector end = new PVector(w, height*2/3); + lines.add(new KochLine(start, end)); + for (int i = 0; i < n; i++) { + generate(); + } + strokeWeight(2); + for (KochLine l : lines) { + l.display(); + } + noFill(); + strokeWeight(1); + stroke(127); + rect(0, 10, w,height-20); + translate(w+spacing, 0); + } + save("chapter08_14.png"); + noLoop(); +} + +void generate() { + ArrayList next = new ArrayList(); // Create emtpy list + for (KochLine l : lines) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.kochA(); + PVector b = l.kochB(); + PVector c = l.kochC(); + PVector d = l.kochD(); + PVector e = l.kochE(); + // Make line segments between all the PVectors and add them + next.add(new KochLine(a, b)); + next.add(new KochLine(b, c)); + next.add(new KochLine(c, d)); + next.add(new KochLine(d, e)); + } + lines = next; +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_14_Koch/KochLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_14_Koch/KochLine.pde new file mode 100644 index 000000000..54ed28120 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_14_Koch/KochLine.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve + +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector start; + PVector end; + + KochLine(PVector a, PVector b) { + start = a.get(); + end = b.get(); + } + + void display() { + stroke(0); + line(start.x, start.y, end.x, end.y); + } + + PVector kochA() { + return start.get(); + } + + + // This is easy, just 1/3 of the way + PVector kochB() { + PVector v = PVector.sub(end, start); + v.div(3); + v.add(start); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochC() { + PVector a = start.get(); // Start at the beginning + + PVector v = PVector.sub(end, start); + v.div(3); + a.add(v); // Move to point B + + rotate(v, -radians(60)); // Rotate 60 degrees + a.add(v); // Move to point C + + return a; + } + + // Easy, just 2/3 of the way + PVector kochD() { + PVector v = PVector.sub(end, start); + v.mult(2/3.0); + v.add(start); + return v; + } + + PVector kochE() { + return end.get(); + } +} + +public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*PApplet.cos(theta) - v.y*PApplet.sin(theta); + v.y = xTemp*PApplet.sin(theta) + v.y*PApplet.cos(theta); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_20_Tree/Figure_8_20_Tree.pde b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_20_Tree/Figure_8_20_Tree.pde new file mode 100644 index 000000000..a81bd3fe8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_20_Tree/Figure_8_20_Tree.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree + +// Renders a simple tree-like structure via recursion +// Branching angle calculated as a function of horizontal mouse location + +float theta; + +void setup() { + size(800, 200); + smooth(); +} + +void draw() { + background(255); + // Let's pick an angle 0 to 90 degrees based on the mouse position + theta = map(mouseX,0,width,0,PI/2); + + // Start the tree from the bottom of the screen + translate(width/2, height); + stroke(0); + branch(60); +} + +void branch(float len) { + // Each branch will be 2/3rds the size of the previous one + + //float sw = map(len,2,120,1,10); + //strokeWeight(sw); + strokeWeight(2); + + line(0, 0, 0, -len); + // Move to the end of that line + translate(0, -len); + + len *= 0.66; + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (len > 2) { + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(len); // Ok, now call myself to draw two new branches!! + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + pushMatrix(); + rotate(-theta); + branch(len); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_CantorLine/Figure_8_CantorLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_CantorLine/Figure_8_CantorLine.pde new file mode 100644 index 000000000..135d12ac9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Figure_8_CantorLine/Figure_8_CantorLine.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +void setup() { + size(800, 60); + background(255); +} + +void cantor(float x, float y, float len) { + line(x, y, x+len, y); + + y += 20; + line(x,y,x+len/3,y); //[bold] + line(x+len*2/3,y,x+len,y); //[bold] +} + +void draw() { + cantor(10, 20, width-20); + save("chapter08_12.png"); + noLoop(); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde new file mode 100644 index 000000000..9cfe2e706 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Recursion + +void setup() { + size(800,200); + smooth(); +} + +void draw() { + background(255); + drawCircle(width/2,height/2,width); + noLoop(); +} + +// Very simple function that draws one circle +// and recursively calls itself +void drawCircle(int x, int y, float r) { + ellipse(x, y, r, r); + // Exit condition, stop when radius is too small + if(r > 2) { + r *= 0.75f; + // Call the function inside the function! (recursion!) + drawCircle(x, y, r); + } +} diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde new file mode 100644 index 000000000..d6082e9a8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Recursion + +void setup() { + size(800,200); +} + +void draw() { + background(255); + drawCircle(width/2,height/2,400); + noLoop(); +} + +// Recursive function +void drawCircle(float x, float y, float r) { + stroke(0); + noFill(); + ellipse(x, y, r, r); + if(r > 2) { + // Now we draw two more circles, one to the left + // and one to the right + drawCircle(x + r/2, y, r/2); + drawCircle(x - r/2, y, r/2); + } +} diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde new file mode 100644 index 000000000..a2caee41c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde @@ -0,0 +1,72 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector start; + PVector end; + + KochLine(PVector a, PVector b) { + start = a.get(); + end = b.get(); + } + + void display() { + stroke(0); + line(start.x, start.y, end.x, end.y); + } + + PVector kochA() { + return start.get(); + } + + + // This is easy, just 1/3 of the way + PVector kochB() { + PVector v = PVector.sub(end, start); + v.div(3); + v.add(start); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochC() { + PVector a = start.get(); // Start at the beginning + + PVector v = PVector.sub(end, start); + v.div(3); + a.add(v); // Move to point B + + rotate(v, -radians(60)); // Rotate 60 degrees + a.add(v); // Move to point C + + return a; + } + + // Easy, just 2/3 of the way + PVector kochD() { + PVector v = PVector.sub(end, start); + v.mult(2/3.0); + v.add(start); + return v; + } + + PVector kochE() { + return end.get(); + } +} + +public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*PApplet.cos(theta) - v.y*PApplet.sin(theta); + v.y = xTemp*PApplet.sin(theta) + v.y*PApplet.cos(theta); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde new file mode 100644 index 000000000..9b9f8be19 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde @@ -0,0 +1,51 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// Renders a simple fractal, the Koch snowflake +// Each recursive level drawn in sequence + +ArrayList lines ; // A list to keep track of all the lines + +void setup() { + size(600, 300); + background(255); + lines = new ArrayList(); + PVector start = new PVector(0, 200); + PVector end = new PVector(width, 200); + lines.add(new KochLine(start, end)); + + for (int i = 0; i < 5; i++) { + generate(); + } + + smooth(); +} + +void draw() { + background(255); + for (KochLine l : lines) { + l.display(); + } +} + +void generate() { + ArrayList next = new ArrayList(); // Create emtpy list + for (KochLine l : lines) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.kochA(); + PVector b = l.kochB(); + PVector c = l.kochC(); + PVector d = l.kochD(); + PVector e = l.kochE(); + // Make line segments between all the PVectors and add them + next.add(new KochLine(a, b)); + next.add(new KochLine(b, c)); + next.add(new KochLine(c, d)); + next.add(new KochLine(d, e)); + } + lines = next; +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde new file mode 100644 index 000000000..b0e5834ed --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Recursion + +void setup() { + size(800, 200); +} + +void draw() { + background(255); + drawCircle(width/2, height/2, 400); + noLoop(); +} + +void drawCircle(float x, float y, float radius) { + noFill(); + stroke(0); + ellipse(x, y, radius, radius); + if (radius > 8) { + // Four circles! left right, up and down + drawCircle(x + radius/2, y, radius/2); + drawCircle(x - radius/2, y, radius/2); + drawCircle(x, y + radius/2, radius/2); + drawCircle(x, y - radius/2, radius/2); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_04_CantorSet/NOC_8_04_CantorSet.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_04_CantorSet/NOC_8_04_CantorSet.pde new file mode 100644 index 000000000..47da39851 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_04_CantorSet/NOC_8_04_CantorSet.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Cantor Set +// Renders a simple fractal, the Cantor Set + +void setup() { + size(800, 200); + background(255); + + // Call the recursive function + cantor(35, 0, 730); +} + +void draw() { + // No need to loop + noLoop(); +} + + +void cantor(float x, float y, float len) { + + float h = 30; + + // recursive exit condition + if (len >= 1) { + // Draw line (as rectangle to make it easier to see) + noStroke(); + fill(0); + rect(x, y, len, h/3); + // Go down to next y position + y += h; + // Draw 2 more lines 1/3rd the length (without the middle section) + cantor(x, y, len/3); + cantor(x+len*2/3, y, len/3); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_04_Tree/NOC_8_04_Tree.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_04_Tree/NOC_8_04_Tree.pde new file mode 100644 index 000000000..cb35ab15f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_04_Tree/NOC_8_04_Tree.pde @@ -0,0 +1,53 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree +// Renders a simple tree-like structure via recursion +// Branching angle calculated as a function of horizontal mouse location + +float theta; + +void setup() { + size(300, 200); + smooth(); +} + +void draw() { + background(255); + // Let's pick an angle 0 to 90 degrees based on the mouse position + theta = map(mouseX,0,width,0,PI/2); + + // Start the tree from the bottom of the screen + translate(width/2, height); + stroke(0); + branch(60); +} + +void branch(float len) { + // Each branch will be 2/3rds the size of the previous one + + float sw = map(len,2,120,1,10); + strokeWeight(sw); + + line(0, 0, 0, -len); + // Move to the end of that line + translate(0, -len); + + len *= 0.66; + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (len > 2) { + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(len); // Ok, now call myself to draw two new branches!! + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + pushMatrix(); + rotate(-theta); + branch(len); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/KochFractal.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/KochFractal.pde new file mode 100644 index 000000000..76a8f1cd7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/KochFractal.pde @@ -0,0 +1,71 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// A class to manage the list of line segments in the snowflake pattern + +class KochFractal { + PVector start; // A PVector for the start + PVector end; // A PVector for the end + ArrayList lines; // A list to keep track of all the lines + int count; + + public KochFractal() { + start = new PVector(0,height-20); + end = new PVector(width,height-20); + lines = new ArrayList(); + restart(); + } + + void nextLevel() { + // For every line that is in the arraylist + // create 4 more lines in a new arraylist + lines = iterate(lines); + count++; + } + + void restart() { + count = 0; // Reset count + lines.clear(); // Empty the array list + lines.add(new KochLine(start,end)); // Add the initial line (from one end PVector to the other) + } + + int getCount() { + return count; + } + + // This is easy, just draw all the lines + void render() { + for(KochLine l : lines) { + l.display(); + } + } + + // This is where the **MAGIC** happens + // Step 1: Create an empty arraylist + // Step 2: For every line currently in the arraylist + // - calculate 4 line segments based on Koch algorithm + // - add all 4 line segments into the new arraylist + // Step 3: Return the new arraylist and it becomes the list of line segments for the structure + + // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . . + ArrayList iterate(ArrayList before) { + ArrayList now = new ArrayList(); // Create emtpy list + for(KochLine l : before) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.start(); + PVector b = l.kochleft(); + PVector c = l.kochmiddle(); + PVector d = l.kochright(); + PVector e = l.end(); + // Make line segments between all the PVectors and add them + now.add(new KochLine(a,b)); + now.add(new KochLine(b,c)); + now.add(new KochLine(c,d)); + now.add(new KochLine(d,e)); + } + return now; + } + +} diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/KochLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/KochLine.pde new file mode 100644 index 000000000..6f3ff6913 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/KochLine.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector a; + PVector b; + + KochLine(PVector start, PVector end) { + a = start.get(); + b = end.get(); + } + + void display() { + stroke(0); + line(a.x, a.y, b.x, b.y); + } + + PVector start() { + return a.get(); + } + + PVector end() { + return b.get(); + } + + // This is easy, just 1/3 of the way + PVector kochleft() { + PVector v = PVector.sub(b, a); + v.div(3); + v.add(a); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochmiddle() { + PVector v = PVector.sub(b, a); + v.div(3); + + PVector p = a.get(); + p.add(v); + + rotate(v,-radians(60)); + p.add(v); + + return p; + } + + + // Easy, just 2/3 of the way + PVector kochright() { + PVector v = PVector.sub(a, b); + v.div(3); + v.add(b); + return v; + } +} + + public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*cos(theta) - v.y*sin(theta); + v.y = xTemp*sin(theta) + v.y*cos(theta); + } + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/NOC_8_05_Koch.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/NOC_8_05_Koch.pde new file mode 100644 index 000000000..f61293171 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/NOC_8_05_Koch.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Koch Curve + +// Renders a simple fractal, the Koch snowflake +// Each recursive level drawn in sequence + +KochFractal k; + +void setup() { + size(800,250); + background(255); + frameRate(1); // Animate slowly + k = new KochFractal(); + smooth(); +} + +void draw() { + background(255); + // Draws the snowflake! + k.render(); + // Iterate + k.nextLevel(); + // Let's not do it more than 5 times. . . + if (k.getCount() > 5) { + k.restart(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties new file mode 100644 index 000000000..140966b6e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties @@ -0,0 +1,2 @@ +mode.id=processing.mode.javascript.JavaScriptMode +mode=JavaScript diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_KochSimple/KochLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_KochSimple/KochLine.pde new file mode 100644 index 000000000..f66510428 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_KochSimple/KochLine.pde @@ -0,0 +1,73 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector start; + PVector end; + + KochLine(PVector a, PVector b) { + start = a.get(); + end = b.get(); + } + + void display() { + stroke(0); + line(start.x, start.y, end.x, end.y); + } + + PVector kochA() { + return start.get(); + } + + + // This is easy, just 1/3 of the way + PVector kochB() { + PVector v = PVector.sub(end, start); + v.div(3); + v.add(start); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochC() { + PVector a = start.get(); // Start at the beginning + + PVector v = PVector.sub(end, start); + v.div(3); + a.add(v); // Move to point B + + rotate(v, -radians(60)); // Rotate 60 degrees + a.add(v); // Move to point C + + return a; + } + + // Easy, just 2/3 of the way + PVector kochD() { + PVector v = PVector.sub(end, start); + v.mult(2/3.0); + v.add(start); + return v; + } + + PVector kochE() { + return end.get(); + } +} + +public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*PApplet.cos(theta) - v.y*PApplet.sin(theta); + v.y = xTemp*PApplet.sin(theta) + v.y*PApplet.cos(theta); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_KochSimple/NOC_8_05_KochSimple.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_KochSimple/NOC_8_05_KochSimple.pde new file mode 100644 index 000000000..b8268ee9f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_KochSimple/NOC_8_05_KochSimple.pde @@ -0,0 +1,51 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// Renders a simple fractal, the Koch snowflake +// Each recursive level drawn in sequence + +ArrayList lines ; // A list to keep track of all the lines + +void setup() { + size(383, 200); + background(255); + lines = new ArrayList(); + PVector start = new PVector(0, 150); + PVector end = new PVector(width, 150); + lines.add(new KochLine(start, end)); + + for (int i = 0; i < 5; i++) { + generate(); + } + + smooth(); +} + +void draw() { + background(255); + for (KochLine l : lines) { + l.display(); + } +} + +void generate() { + ArrayList next = new ArrayList(); // Create emtpy list + for (KochLine l : lines) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.kochA(); + PVector b = l.kochB(); + PVector c = l.kochC(); + PVector d = l.kochD(); + PVector e = l.kochE(); + // Make line segments between all the PVectors and add them + next.add(new KochLine(a, b)); + next.add(new KochLine(b, c)); + next.add(new KochLine(c, d)); + next.add(new KochLine(d, e)); + } + lines = next; +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_TreeStochastic/NOC_8_05_TreeStochastic.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_TreeStochastic/NOC_8_05_TreeStochastic.pde new file mode 100644 index 000000000..0c642b221 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_TreeStochastic/NOC_8_05_TreeStochastic.pde @@ -0,0 +1,63 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stochastic Tree +// Renders a simple tree-like structure via recursion +// Angles and number of branches are random + +void setup() { + size(600, 400); + newTree(); +} + +void draw() { + +} + +void mousePressed() { + newTree(); +} + +void newTree() { + background(255); + fill(0); + text("Click mouse to generate a new tree", 10, height-20); + + stroke(0); + // Start the tree from the bottom of the screen + translate(width/2, height); + // Start the recursive branching! + branch(120); +} + + + +void branch(float h) { + // thickness of the branch is mapped to its length + float sw = map(h, 2, 120, 1, 5); + strokeWeight(sw); + // Draw the actual branch + line(0, 0, 0, -h); + // Move along to end + translate(0, -h); + + // Each branch will be 2/3rds the size of the previous one + h *= 0.66f; + + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (h > 2) { + // A random number of branches + int n = int(random(1, 4)); + for (int i = 0; i < n; i++) { + // Picking a random angle + float theta = random(-PI/2, PI/2); + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(h); // Ok, now call myself to branch again + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_SimpleLSystem/NOC_8_06_SimpleLSystem.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_SimpleLSystem/NOC_8_06_SimpleLSystem.pde new file mode 100644 index 000000000..b14d7b021 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_SimpleLSystem/NOC_8_06_SimpleLSystem.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// L-System +// Just demonstrating working with L-System strings +// No drawing + +// Start with "A" +String current = "A"; +// Number of generations +int count = 0; + +void setup() { + size(200, 200); + println("Generation " + count + ": " + current); +} + +void draw() { + background(255); + fill(0); + text("Click mouse to generate", 10, height-20); + noLoop(); +} + +void mousePressed() { + // A new StringBuffer for the next generation + StringBuffer next = new StringBuffer(); + + // Look through the current String to replace according to L-System rules + for (int i = 0; i < current.length(); i++) { + char c = current.charAt(i); + if (c == 'A') { + // If we find A replace with AB + next.append("AB"); + } else if (c == 'B') { + // If we find B replace with A + next.append("A"); + } + } + // The current String is now the next one + current = next.toString(); + count++; + // Print to message console + println("Generation " + count + ": " + current); + println(count + " " + current.length()); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_Tree/NOC_8_06_Tree.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_Tree/NOC_8_06_Tree.pde new file mode 100644 index 000000000..ca1ee0a25 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_Tree/NOC_8_06_Tree.pde @@ -0,0 +1,54 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree +// Renders a simple tree-like structure via recursion +// Branching angle calculated as a function of horizontal mouse location + +float theta; + +void setup() { + size(250, 200); + smooth(); +} + +void draw() { + background(255); + // Let's pick an angle 0 to 90 degrees based on the mouse position + theta = map(mouseX,0,width,0,PI/2); + + // Start the tree from the bottom of the screen + translate(width/2, height); + stroke(0); + branch(60); +} + +void branch(float len) { + // Each branch will be 2/3rds the size of the previous one + + //float sw = map(len,2,120,1,10); + //strokeWeight(sw); + strokeWeight(2); + + line(0, 0, 0, -len); + // Move to the end of that line + translate(0, -len); + + len *= 0.66; + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (len > 2) { + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(len); // Ok, now call myself to draw two new branches!! + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + pushMatrix(); + rotate(-theta); + branch(len); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_Tree_static/NOC_8_06_Tree_static.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_Tree_static/NOC_8_06_Tree_static.pde new file mode 100644 index 000000000..92805fdb4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_06_Tree_static/NOC_8_06_Tree_static.pde @@ -0,0 +1,45 @@ +// Recursive Tree +// Daniel Shiffman +// Nature of Code, Chapter 8 + +// Renders a simple tree-like structure via recursion +// Branching angle calculated as a function of horizontal mouse location + +void setup() { + size(800, 200); + smooth(); +} + +void draw() { + background(255); + // Start the tree from the bottom of the screen + translate(width/2, height); + stroke(0); + branch(60); + noLoop(); +} + +void branch(float len) { + strokeWeight(2); + + line(0, 0, 0, -len); + // Move to the end of that line + translate(0, -len); + + len *= 0.66; + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (len > 2) { + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(PI/5); // Rotate by theta + branch(len); // Ok, now call myself to draw two new branches!! + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + pushMatrix(); + rotate(-PI/5); + branch(len); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_07_TreeStochastic/NOC_8_07_TreeStochastic.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_07_TreeStochastic/NOC_8_07_TreeStochastic.pde new file mode 100644 index 000000000..c0e22fb7b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_07_TreeStochastic/NOC_8_07_TreeStochastic.pde @@ -0,0 +1,66 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stochastic Tree +// Renders a simple tree-like structure via recursion +// Angles and number of branches are random + +void setup() { + size(800, 200); + newTree(); +} + +void draw() { + noLoop(); +} + +void mousePressed() { + newTree(); + redraw(); +} + +void newTree() { + background(255); + fill(0); + text("Click mouse to generate a new tree", 10, height-10); + + stroke(0); + pushMatrix(); + // Start the tree from the bottom of the screen + translate(width/2, height); + // Start the recursive branching! + branch(80); + popMatrix(); +} + + + +void branch(float h) { + // thickness of the branch is mapped to its length + float sw = map(h, 2, 120, 1, 5); + strokeWeight(sw); + // Draw the actual branch + line(0, 0, 0, -h); + // Move along to end + translate(0, -h); + + // Each branch will be 2/3rds the size of the previous one + h *= 0.66f; + + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (h > 2) { + // A random number of branches + int n = int(random(1, 4)); + for (int i = 0; i < n; i++) { + // Picking a random angle + float theta = random(-PI/2, PI/2); + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(h); // Ok, now call myself to branch again + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_07_TreeStochastic_angleonly/NOC_8_07_TreeStochastic_angleonly.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_07_TreeStochastic_angleonly/NOC_8_07_TreeStochastic_angleonly.pde new file mode 100644 index 000000000..5c73557a5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_07_TreeStochastic_angleonly/NOC_8_07_TreeStochastic_angleonly.pde @@ -0,0 +1,59 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stochastic Tree +// Renders a simple tree-like structure via recursion +// Angles and number of branches are random + +void setup() { + size(800, 200); + newTree(); +} + +void draw() { + noLoop(); +} + +void mousePressed() { + pushMatrix(); + newTree(); + popMatrix(); + redraw(); +} + +void newTree() { + background(255); + fill(0); + text("Click mouse to generate a new tree", 10, height-10); + + stroke(0); + // Start the tree from the bottom of the screen + translate(width/2, height); + // Start the recursive branching! + branch(60); +} + + + +void branch(float h) { + // thickness of the branch is mapped to its length + float sw = map(h, 2, 120, 1, 5); + strokeWeight(sw); + float theta = random(0,PI/3); + + line(0, 0, 0, -h); + translate(0, -h); + h *= 0.66; + if (h > 2) { + pushMatrix(); + rotate(theta); + branch(h); + popMatrix(); + pushMatrix(); + rotate(-theta); + branch(h); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_08_SimpleLSystem/NOC_8_08_SimpleLSystem.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_08_SimpleLSystem/NOC_8_08_SimpleLSystem.pde new file mode 100644 index 000000000..9f1b0dac3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_08_SimpleLSystem/NOC_8_08_SimpleLSystem.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// L-System +// Just demonstrating working with L-System strings +// No drawing + +// Start with "A" +String current = "A"; +// Number of generations +int count = 0; + +void setup() { + size(800, 200); + println("Generation " + count + ": " + current); +} + +void draw() { + background(255); + fill(0); + text("Click mouse to generate", 10, height-20); + noLoop(); +} + +void mousePressed() { + // A new StringBuffer for the next generation + StringBuffer next = new StringBuffer(); + + // Look through the current String to replace according to L-System rules + for (int i = 0; i < current.length(); i++) { + char c = current.charAt(i); + if (c == 'A') { + // If we find A replace with AB + next.append("AB"); + } else if (c == 'B') { + // If we find B replace with A + next.append("A"); + } + } + // The current String is now the next one + current = next.toString(); + count++; + // Print to message console + println("Generation " + count + ": " + current); + //println(count + " " + current.length()); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/LSystem.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/LSystem.pde new file mode 100644 index 000000000..a51c255ee --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/LSystem.pde @@ -0,0 +1,63 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// An LSystem has a starting sentence +// An a ruleset +// Each generation recursively replaces characteres in the sentence +// Based on the rulset + +class LSystem { + + String sentence; // The sentence (a String) + Rule[] ruleset; // The ruleset (an array of Rule objects) + int generation; // Keeping track of the generation # + + // Construct an LSystem with a startin sentence and a ruleset + LSystem(String axiom, Rule[] r) { + sentence = axiom; + ruleset = r; + generation = 0; + } + + // Generate the next generation + void generate() { + // An empty StringBuffer that we will fill + StringBuffer nextgen = new StringBuffer(); + // For every character in the sentence + for (int i = 0; i < sentence.length(); i++) { + // What is the character + char curr = sentence.charAt(i); + // We will replace it with itself unless it matches one of our rules + String replace = "" + curr; + // Check every rule + for (int j = 0; j < ruleset.length; j++) { + char a = ruleset[j].getA(); + // if we match the Rule, get the replacement String out of the Rule + if (a == curr) { + replace = ruleset[j].getB(); + break; + } + } + // Append replacement String + nextgen.append(replace); + } + // Replace sentence + sentence = nextgen.toString(); + // Increment generation + generation++; + } + + String getSentence() { + return sentence; + } + + int getGeneration() { + return generation; + } + + +} + + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/NOC_8_09_LSystem.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/NOC_8_09_LSystem.pde new file mode 100644 index 000000000..a870be857 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/NOC_8_09_LSystem.pde @@ -0,0 +1,62 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +LSystem lsys; +Turtle turtle; + +void setup() { + size(800, 200); + /* + // Create an empty ruleset + Rule[] ruleset = new Rule[2]; + // Fill with two rules (These are rules for the Sierpinksi Gasket Triangle) + ruleset[0] = new Rule('F',"F--F--F--G"); + ruleset[1] = new Rule('G',"GG"); + // Create LSystem with axiom and ruleset + lsys = new LSystem("F--F--F",ruleset); + turtle = new Turtle(lsys.getSentence(),width*2,TWO_PI/3); + */ + + /*Rule[] ruleset = new Rule[1]; + //ruleset[0] = new Rule('F',"F[F]-F+F[--F]+F-F"); + ruleset[0] = new Rule['F',"FF+[+F-F-F]-[-F+F+F]"); + lsys = new LSystem("F-F-F-F",ruleset); + turtle = new Turtle(lsys.getSentence(),width-1,PI/2); + */ + + Rule[] ruleset = new Rule[1]; + ruleset[0] = new Rule('F', "FF+[+F-F-F]-[-F+F+F]"); + lsys = new LSystem("F", ruleset); + turtle = new Turtle(lsys.getSentence(), height/3, radians(25)); + + + + smooth(); +} + +void draw() { + background(255); + fill(0); + //text("Click mouse to generate", 10, height-10); + + translate(width/2, height); + rotate(-PI/2); + turtle.render(); + noLoop(); +} + +int counter = 0; + +void mousePressed() { + if (counter < 5) { + pushMatrix(); + lsys.generate(); + turtle.setToDo(lsys.getSentence()); + turtle.changeLen(0.5); + popMatrix(); + redraw(); + counter++; + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/Rule.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/Rule.pde new file mode 100644 index 000000000..49353e772 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/Rule.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// LSystem Rule class + +class Rule { + char a; + String b; + + Rule(char a_, String b_) { + a = a_; + b = b_; + } + + char getA() { + return a; + } + + String getB() { + return b; + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/Turtle.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/Turtle.pde new file mode 100644 index 000000000..cede7d5c7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/Turtle.pde @@ -0,0 +1,54 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Turtle { + + String todo; + float len; + float theta; + + Turtle(String s, float l, float t) { + todo = s; + len = l; + theta = t; + } + + void render() { + stroke(0,175); + for (int i = 0; i < todo.length(); i++) { + char c = todo.charAt(i); + if (c == 'F' || c == 'G') { + line(0,0,len,0); + translate(len,0); + } + else if (c == '+') { + rotate(theta); + } + else if (c == '-') { + rotate(-theta); + } + else if (c == '[') { + pushMatrix(); + } + else if (c == ']') { + popMatrix(); + } + } + } + + void setLen(float l) { + len = l; + } + + void changeLen(float percent) { + len *= percent; + } + + void setToDo(String s) { + todo = s; + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/sketch.properties b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/sketch.properties new file mode 100644 index 000000000..b3cbe600e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_09_LSystem/sketch.properties @@ -0,0 +1,2 @@ +mode.id=processing.mode.java.JavaMode +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde new file mode 100644 index 000000000..f75ac71c9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde @@ -0,0 +1,61 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree (w/ ArrayList) + +// A class for one branch in the system + +class Branch { + // Each has a location, velocity, and timer + // We could implement this same idea with different data + PVector loc; + PVector vel; + float timer; + float timerstart; + + Branch(PVector l, PVector v, float n) { + loc = l.get(); + vel = v.get(); + timerstart = n; + timer = timerstart; + } + + // Move location + void update() { + loc.add(vel); + } + + // Draw a dot at location + void render() { + fill(0); + noStroke(); + ellipseMode(CENTER); + ellipse(loc.x,loc.y,2,2); + } + + // Did the timer run out? + boolean timeToBranch() { + timer--; + if (timer < 0) { + return true; + } else { + return false; + } + } + + // Create a new branch at the current location, but change direction by a given angle + Branch branch(float angle) { + // What is my current heading + float theta = vel.heading2D(); + // What is my current speed + float mag = vel.mag(); + // Turn me + theta += radians(angle); + // Look, polar coordinates to cartesian!! + PVector newvel = new PVector(mag*cos(theta),mag*sin(theta)); + // Return a new Branch + return new Branch(loc,newvel,timerstart*0.66f); + } + +} diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Tree2.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Tree2.pde new file mode 100644 index 000000000..9d3918d43 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Tree2.pde @@ -0,0 +1,47 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree (w/ ArrayList) + +// Recursive branching "structure" without an explicitly recursive function +// Instead we have an ArrayList to hold onto N number of elements +// For every element in the ArrayList, we add 2 more elements, etc. (this is the recursion) + +// An arraylist that will keep track of all current branches +ArrayList tree; + +void setup() { + size(200,200); + background(255); + // Setup the arraylist and add one branch to it + tree = new ArrayList(); + // A branch has a starting location, a starting "velocity", and a starting "timer" + Branch b = new Branch(new PVector(width/2,height),new PVector(0,-0.5),100); + // Add to arraylist + tree.add(b); +} + +void draw() { + // Try erasing the background to see how it works + // background(255); + + // Let's stop when the arraylist gets too big + if (tree.size() < 1024) { + // For every branch in the arraylist + for (int i = tree.size()-1; i >= 0; i--) { + // Get the branch, update and draw it + Branch b = tree.get(i); + b.update(); + b.render(); + // If it's ready to split + if (b.timeToBranch()) { + tree.remove(i); // Delete it + tree.add(b.branch( 30)); // Add one going right + tree.add(b.branch(-25)); // Add one going left + } + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde new file mode 100644 index 000000000..7c5e8b9c8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde @@ -0,0 +1,68 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree (w/ ArrayList) + +// A class for one branch in the system + +class Branch { + // Each has a location, velocity, and timer + // We could implement this same idea with different data + PVector start; + PVector end; + PVector vel; + float timer; + float timerstart; + + boolean growing = true; + + Branch(PVector l, PVector v, float n) { + start = l.get(); + end = l.get(); + vel = v.get(); + timerstart = n; + timer = timerstart; + } + + // Move location + void update() { + if (growing) { + end.add(vel); + } + } + + // Draw a dot at location + void render() { + stroke(0); + line(start.x,start.y,end.x,end.y); + } + + // Did the timer run out? + boolean timeToBranch() { + timer--; + if (timer < 0 && growing) { + growing = false; + return true; + } + else { + return false; + } + } + + // Create a new branch at the current location, but change direction by a given angle + Branch branch(float angle) { + // What is my current heading + float theta = vel.heading2D(); + // What is my current speed + float mag = vel.mag(); + // Turn me + theta += radians(angle); + // Look, polar coordinates to cartesian!! + PVector newvel = new PVector(mag*cos(theta),mag*sin(theta)); + // Return a new Branch + return new Branch(end,newvel,timerstart*0.66f); + } + +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Leaf.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Leaf.pde new file mode 100644 index 000000000..94ffd407e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Leaf.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree (w/ ArrayList) + +// A class for a leaf that gets placed at the end of +// the last branches + +class Leaf { + PVector loc; + + Leaf(PVector l) { + loc = l.get(); + } + + void display() { + noStroke(); + fill(50,100); + ellipse(loc.x,loc.y,4,4); + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Tree3.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Tree3.pde new file mode 100644 index 000000000..485409940 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Tree3.pde @@ -0,0 +1,59 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Recursive Tree (w/ ArrayList) +// Nature of Code, Chapter 8 + +// Recursive branching "structure" without an explicitly recursive function +// Instead we have an ArrayList to hold onto N number of elements +// For every element in the ArrayList, we add 2 more elements, etc. (this is the recursion) + +// An arraylist that will keep track of all current branches +ArrayList tree; +ArrayList leaves; + +void setup() { + size(200,200); + background(255); + // Setup the arraylist and add one branch to it + tree = new ArrayList(); + leaves = new ArrayList(); + // A branch has a starting location, a starting "velocity", and a starting "timer" + Branch b = new Branch(new PVector(width/2,height),new PVector(0,-0.5),100); + // Add to arraylist + tree.add(b); +} + +void draw() { + background(255); + + // Let's stop when the arraylist gets too big + // For every branch in the arraylist + for (int i = tree.size()-1; i >= 0; i--) { + // Get the branch, update and draw it + Branch b = tree.get(i); + b.update(); + b.render(); + // If it's ready to split + if (b.timeToBranch()) { + if (tree.size() < 1024) { + //tree.remove(i); // Delete it + tree.add(b.branch( 30)); // Add one going right + tree.add(b.branch(-25)); // Add one going left + } + else { + leaves.add(new Leaf(b.end)); + } + } + } + + for (Leaf leaf : leaves) { + leaf.display(); + } + +} + + + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/TreeStochasticNoise/TreeStochasticNoise.pde b/java/examples/Books/Nature of Code/chp8_fractals/TreeStochasticNoise/TreeStochasticNoise.pde new file mode 100644 index 000000000..5a0bf3792 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/TreeStochasticNoise/TreeStochasticNoise.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Stochastic Tree with angles fluctuating with Perlin noise +// Nature of Code, Chapter 8 + +// Perlin noise offset +float yoff = 0; +// Random seed to control randomness while drawing the tree +int seed = 5; + + +void setup() { + size(800, 200); + smooth(); +} + +void draw() { + background(255); + fill(0); + //text("Click mouse to generate a new tree", 10, height-20); + + stroke(0); + // Start the tree from the bottom of the screen + translate(width/2, height); + // Move alogn through noise + yoff += 0.005; + randomSeed(seed); + // Start the recursive branching! + branch(60, 0); +} + + +void mousePressed() { + // New tree starts with new noise offset and new random seed + yoff = random(1000); + seed = millis(); +} + + +void branch(float h, float xoff) { + // thickness of the branch is mapped to its length + float sw = map(h, 2, 100, 1, 5); + strokeWeight(sw); + // Draw the branch + line(0, 0, 0, -h); + // Move along to end + translate(0, -h); + + // Each branch will be 2/3rds the size of the previous one + h *= 0.7f; + + // Move along through noise space + xoff += 0.1; + + if (h > 4) { + // Random number of branches + int n = int(random(0, 5)); + for (int i = 0; i < n; i++) { + + // Here the angle is controlled by perlin noise + // This is a totally arbitrary way to do it, try others! + float theta = map(noise(xoff+i, yoff), 0, 1, -PI/3, PI/3); + if (n%2==0) theta *= -1; + + pushMatrix(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + branch(h, xoff); // Ok, now call myself to branch again + popMatrix(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/TreeStochasticNoise/sketch.properties b/java/examples/Books/Nature of Code/chp8_fractals/TreeStochasticNoise/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/TreeStochasticNoise/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp8_fractals/lsys/LSystem.pde b/java/examples/Books/Nature of Code/chp8_fractals/lsys/LSystem.pde new file mode 100644 index 000000000..108afbb34 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/lsys/LSystem.pde @@ -0,0 +1,65 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +/* LSystem Class */ + +// An LSystem has a starting sentence +// An a ruleset +// Each generation recursively replaces characteres in the sentence +// Based on the rulset + +class LSystem { + + String sentence; // The sentence (a String) + Rule[] ruleset; // The ruleset (an array of Rule objects) + int generation; // Keeping track of the generation # + + // Construct an LSystem with a startin sentence and a ruleset + LSystem(String axiom, Rule[] r) { + sentence = axiom; + ruleset = r; + generation = 0; + } + + // Generate the next generation + void generate() { + // An empty StringBuffer that we will fill + StringBuffer nextgen = new StringBuffer(); + // For every character in the sentence + for (int i = 0; i < sentence.length(); i++) { + // What is the character + char curr = sentence.charAt(i); + // We will replace it with itself unless it matches one of our rules + String replace = "" + curr; + // Check every rule + for (int j = 0; j < ruleset.length; j++) { + char a = ruleset[j].getA(); + // if we match the Rule, get the replacement String out of the Rule + if (a == curr) { + replace = ruleset[j].getB(); + break; + } + } + // Append replacement String + nextgen.append(replace); + } + // Replace sentence + sentence = nextgen.toString(); + // Increment generation + generation++; + } + + String getSentence() { + return sentence; + } + + int getGeneration() { + return generation; + } + + +} + + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/lsys/Rule.pde b/java/examples/Books/Nature of Code/chp8_fractals/lsys/Rule.pde new file mode 100644 index 000000000..2fb2c4b5c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/lsys/Rule.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A Class to describe an LSystem Rule + +class Rule { + char a; + String b; + + Rule(char a_, String b_) { + a = a_; + b = b_; + } + + char getA() { + return a; + } + + String getB() { + return b; + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/lsys/Turtle.pde b/java/examples/Books/Nature of Code/chp8_fractals/lsys/Turtle.pde new file mode 100644 index 000000000..ac0ffa8d9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/lsys/Turtle.pde @@ -0,0 +1,53 @@ +/* Daniel Shiffman */ +/* http://www.shiffman.net */ + +class Turtle { + + String todo; + float len; + float theta; + + Turtle(String s, float l, float t) { + todo = s; + len = l; + theta = t; + } + + void render() { + stroke(0); + for (int i = 0; i < todo.length(); i++) { + char c = todo.charAt(i); + if (c == 'F' || c == 'G') { + line(0,0,len,0); + translate(len,0); + } + else if (c == '+') { + rotate(theta); + } + else if (c == '-') { + rotate(-theta); + } + else if (c == '[') { + pushMatrix(); + } + else if (c == ']') { + popMatrix(); + } + } + } + + void setLen(float l) { + len = l; + } + + void changeLen(float percent) { + len *= percent; + } + + void setToDo(String s) { + todo = s; + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/lsys/lsys.pde b/java/examples/Books/Nature of Code/chp8_fractals/lsys/lsys.pde new file mode 100644 index 000000000..3629dd48c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/lsys/lsys.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +LSystem lsys; +Turtle turtle; + +void setup() { + size(600, 600); + /* + // Create an empty ruleset + Rule[] ruleset = new Rule[2]; + // Fill with two rules (These are rules for the Sierpinksi Gasket Triangle) + ruleset[0] = new Rule('F',"F--F--F--G"); + ruleset[1] = new Rule('G',"GG"); + // Create LSystem with axiom and ruleset + lsys = new LSystem("F--F--F",ruleset); + turtle = new Turtle(lsys.getSentence(),width*2,TWO_PI/3); + */ + + /*Rule[] ruleset = new Rule[1]; + //ruleset[0] = new Rule('F',"F[F]-F+F[--F]+F-F"); + ruleset[0] = new Rule['F',"FF+[+F-F-F]-[-F+F+F]"); + lsys = new LSystem("F-F-F-F",ruleset); + turtle = new Turtle(lsys.getSentence(),width-1,PI/2); + */ + + Rule[] ruleset = new Rule[1]; + ruleset[0] = new Rule('F', "FF+[+F-F-F]-[-F+F+F]"); + lsys = new LSystem("F", ruleset); + turtle = new Turtle(lsys.getSentence(), width/4, radians(25)); + + + + smooth(); +} + +void draw() { + background(255); + fill(0); + text("Click mouse to generate", 10, height-20); + + translate(width/2, height); + rotate(-PI/2); + turtle.render(); + noLoop(); +} + +void mousePressed() { + lsys.generate(); + turtle.setToDo(lsys.getSentence()); + turtle.changeLen(0.5); + redraw(); +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/DNA.pde new file mode 100644 index 000000000..5cc15f3e1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/DNA.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// DNA is an array of vectors + +class DNA { + + // The genetic sequence + PVector[] genes; + + // Constructor (makes a DNA of random PVectors) + DNA(int num) { + genes = new PVector[num]; + for (int i = 0; i < genes.length; i++) { + float angle = random(TWO_PI); + genes[i] = new PVector(cos(angle), sin(angle)); + } + } + + // Constructor #2, creates the instance based on an existing array + DNA(PVector[] newgenes) { + // We could make a copy if necessary + // genes = (PVector []) newgenes.clone(); + genes = newgenes; + } + + // CROSSOVER + // Creates new DNA sequence from two (this & and a partner) + DNA crossover(DNA partner) { + PVector[] child = new PVector[genes.length]; + // Pick a midpoint + int crossover = int(random(genes.length)); + // Take "half" from one and "half" from the other + for (int i = 0; i < genes.length; i++) { + if (i > crossover) child[i] = genes[i]; + else child[i] = partner.genes[i]; + } + DNA newgenes = new DNA(child); + return newgenes; + } + + // Based on a mutation probability, picks a new random Vector + void mutate(float m) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < m) { + float angle = random(TWO_PI); + genes[i] = new PVector(cos(angle), sin(angle)); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/EvolveFlowField.pde b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/EvolveFlowField.pde new file mode 100644 index 000000000..c3a6584f1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/EvolveFlowField.pde @@ -0,0 +1,103 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding Flowfield w/ Genetic Algorithms + +// This example produces an obstacle course with a start and finish +// Virtual "creatures" are rewarded for making it closer to the finish + +// Each creature's DNA is a "flowfield" of PVectors that +// determine steering vectors for each cell on the screen + +import java.awt.Rectangle; + +int gridscale = 24; // Scale of grid is 1/24 of screen size + +// DNA needs one vector for every spot on the grid +// (it's like a pixel array, but with vectors instead of colors) +int dnasize; + +int lifetime; // How long should each generation live + +// Global maxforce and maxspeed (hmmm, could make this part of DNA??) +float maxspeed = 4.0; +float maxforce = 1.0; + +Population population; // Population +int lifecycle; // Timer for cycle of generation +int recordtime; // Fastest time to target +Obstacle target; // Target location +Obstacle start; // Start location +int diam = 24; // Size of target + +ArrayList obstacles; //an array list to keep track of all the obstacles! + +void setup() { + size(640,480); + dnasize = (width / gridscale) * (height / gridscale); + lifetime = width/2; + + // Initialize variables + lifecycle = 0; + recordtime = lifetime; + target = new Obstacle(width-diam-diam/2,height/2-diam/2,diam,diam); + start = new Obstacle(diam/2,height/2-diam/2,diam,diam); + + // Create a population with a mutation rate, and population max + int popmax = 1000; + float mutationRate = 0.05; + population = new Population(mutationRate,popmax); + + // Create the obstacle course + obstacles = new ArrayList(); + obstacles.add(new Obstacle(width/4,40,10,height-80)); + obstacles.add(new Obstacle(width/2,0,10,height/2-10)); + obstacles.add(new Obstacle(width/2,height-height/2+10,10,height/2-10)); + obstacles.add(new Obstacle(2*width/3,height/2-height/8,10,height/4)); +} + +void draw() { + background(255); + + // Draw the start and target locations + start.display(); + target.display(); + + // Draw the obstacles + for (Obstacle obs : obstacles) { + obs.display(); + } + + + // If the generation hasn't ended yet + if (lifecycle < lifetime) { + population.live(obstacles); + if ((population.targetReached()) && (lifecycle < recordtime)) { + recordtime = lifecycle; + } + lifecycle++; + // Otherwise a new generation + } else { + lifecycle = 0; + population.calcFitness(); + population.naturalSelection(); + population.generate(); + } + + // Display some info + textAlign(RIGHT); + fill(0); + text("Generation #:" + population.getGenerations(),width-10,18); + text("Cycles left:" + ((lifetime-lifecycle)/10),width-10,36); + text("Record cycles: " + recordtime,width-10,54); + +} + +// Move the target if the mouse is pressed +// System will adapt to new target +void mousePressed() { + target = new Obstacle(mouseX,mouseY,diam,diam); + recordtime = lifetime; +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Obstacle.pde b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Obstacle.pde new file mode 100644 index 000000000..6322a02ae --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Obstacle.pde @@ -0,0 +1,35 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// A class for an obstacle, just a simple rectangle that is drawn +// and can check if a creature touches it + +// Also using this class for starting point and target location + +class Obstacle { + + Rectangle r; + + Obstacle(int x, int y, int w, int h) { + r = new Rectangle(x,y,w,h); + } + + void display() { + stroke(0); + fill(175); + rectMode(CORNER); + rect(r.x,r.y,r.width,r.height); + } + + boolean contains(PVector spot) { + if (r.contains((int)spot.x,(int)spot.y)) { + return true; + } else { + return false; + } + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Population.pde b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Population.pde new file mode 100644 index 000000000..ab0e43897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Population.pde @@ -0,0 +1,116 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class to describe a population of "creatures" + +class Population { + + float mutationRate; // Mutation rate + Rocket[] population; // Array to hold the current population + ArrayList darwin; // ArrayList which we will use for our "mating pool" + int generations; // Number of generations + + int order; // Keep track of the order of creature's finishing the maze + + // Initialize the population + Population(float m, int num) { + mutationRate = m; + population = new Rocket[num]; + darwin = new ArrayList(); + generations = 0; + //make a new set of creatures + for (int i = 0; i < population.length; i++) { + PVector location = new PVector(start.r.x+start.r.width/2,start.r.y+start.r.height/2); + population[i] = new Rocket(location, new DNA(dnasize)); + } + order = 1; // The first one to finish will be #1 + } + + void live (ArrayList o) { + // For every creature + for (int i = 0; i < population.length; i++) { + // If it finishes, mark it down as done! + if ((population[i].finished()) && (!population[i].stopped())) { + population[i].setFinish(order); + order++; + } + // Run it + population[i].run(o); + } + } + + // Did anything finish? + boolean targetReached() { + for (int i = 0; i < population.length; i++) { + if (population[i].finished()) return true; + } + return false; + } + + // Calculate fitness for each creature + void calcFitness() { + for (int i = 0; i < population.length; i++) { + population[i].calcFitness(); + } + order = 1; // Hmmm, awkward place for this, we have to reset this for the next generation + } + + // Generate a mating pool + void naturalSelection() { + // Clear the ArrayList + darwin.clear(); + + // Calculate total fitness of whole population + float totalFitness = getTotalFitness(); + + // Calculate normalized fitness for each member of the population + // Based on normalized fitness, each member will get added to the mating pool a certain number of times a la roulette wheel + // A higher fitness = more entries to mating pool = more likely to be picked as a parent + // A lower fitness = fewer entries to mating pool = less likely to be picked as a parent + for (int i = 0; i < population.length; i++) { + float fitnessNormal = population[i].getFitness() / totalFitness; + int n = (int) (fitnessNormal * 50000); // Arbitrary multiplier, consider mapping fix + for (int j = 0; j < n; j++) { + darwin.add(population[i]); + } + } + } + + // Making the next generation + void generate() { + // Refill the population with children from the mating pool + for (int i = 0; i < population.length; i++) { + int m = int(random(darwin.size())); + int d = int(random(darwin.size())); + // Pick two parents + Rocket mom = darwin.get(m); + Rocket dad = darwin.get(d); + // Get their genes + DNA momgenes = mom.getDNA(); + DNA dadgenes = dad.getDNA(); + // Mate their genes + DNA child = momgenes.crossover(dadgenes); + // Mutate their genes + child.mutate(mutationRate); + // Fill the new population with the new child + PVector location = new PVector(start.r.x+start.r.width/2,start.r.y+start.r.height/2); + population[i] = new Rocket(location, child); + } + generations++; + } + + int getGenerations() { + return generations; + } + + //compute total fitness for the population + float getTotalFitness() { + float total = 0; + for (int i = 0; i < population.length; i++) { + total += population[i].getFitness(); + } + return total; + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde new file mode 100644 index 000000000..7bc8a0524 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde @@ -0,0 +1,152 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// Rocket class -- this is just like our Boid / Particle class +// the only difference is that it has DNA & fitness + +class Rocket { + + // All of our physics stuff + PVector location; + PVector velocity; + PVector acceleration; + float r; + float recordDist; + + float fitness; + DNA dna; + + boolean stopped; // Am I stuck? + int finish; // What was my finish? (first, second, etc. . . ) + + //constructor + Rocket(PVector l, DNA dna_) { + acceleration = new PVector(); + velocity = new PVector(); + location = l.get(); + r = 2; + dna = dna_; + stopped = false; + finish = 100000; // Some high number to begin with + recordDist = width; + } + + // FITNESS FUNCTION + // distance = distance from target + // finish = what order did i finish (first, second, etc. . .) + // f(distance,finish) = (1.0f / finish^1.5) * (1.0f / distance^6); + // a lower finish is rewarded (exponentially) and/or shorter distance to target (exponetially) + void calcFitness() { + float d = recordDist; + if (d < diam/2) { + d = 1.0; + } + // Reward finishing faster and getting closer + fitness = (1.0f / pow(finish,1.5)) * (1 / (pow(d,6))); + } + + void setFinish(int f) { + finish = f; + } + + // Run in relation to all the obstacles + // If I'm stuck, don't bother updating or checking for intersection + void run(ArrayList o) { + if (!stopped) { + update(); + // If I hit an edge or an obstacle + if ((borders()) || (obstacles(o))) { + stopped = true; + } + } + // Draw me! + display(); + } + + // Did I hit an edge? + boolean borders() { + if ((location.x < 0) || (location.y < 0) || (location.x > width) || (location.y > height)) { + return true; + } else { + return false; + } + } + + // Did I make it to the target? + boolean finished() { + float d = dist(location.x,location.y,target.r.x,target.r.y); + if (d < recordDist) recordDist = d; + if (target.contains(location)) { + stopped = true; + return true; + } + return false; + } + + // Did I hit an obstacle? + boolean obstacles(ArrayList o) { + for (Obstacle obs : o) { + if (obs.contains(location)) { + return true; + } + } + return false; + } + + void update() { + if (!finished()) { + // Where are we? Our location will tell us what steering vector to look up in our DNA; + int x = (int) location.x/gridscale; + int y = (int) location.y/gridscale; + x = constrain(x,0,width/gridscale-1); // Make sure we are not off the edge + y = constrain(y,0,height/gridscale-1); // Make sure we are not off the edge + + // Get the steering vector out of our genes in the right spot + // We could do (desired - velocity) to be more in line with the Reynolds flow field following + acceleration.add(dna.genes[x+y*width/gridscale]); + + // This is all the same stuff we've done before + acceleration.mult(maxforce); + velocity.add(acceleration); + velocity.limit(maxspeed); + location.add(velocity); + acceleration.mult(0); + } + } + + void display() { + //fill(0,150); + //stroke(0); + //ellipse(location.x,location.y,r,r); + float theta = velocity.heading2D() + PI/2; + fill(200,100); + stroke(0); + pushMatrix(); + translate(location.x,location.y); + rotate(theta); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + popMatrix(); + + + } + + float getFitness() { + return fitness; + } + + DNA getDNA() { + return dna; + } + + boolean stopped() { + return stopped; + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/DNA.pde new file mode 100644 index 000000000..8286ab0c0 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/DNA.pde @@ -0,0 +1,70 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// A class to describe a psuedo-DNA, i.e. genotype +// Here, a virtual organism's DNA is an array of character. +// Functionality: +// -- convert DNA into a string +// -- calculate DNA's "fitness" +// -- mate DNA with another set of DNA +// -- mutate DNA + + +class DNA { + + // The genetic sequence + char[] genes; + + float fitness; + + // Constructor (makes a random DNA) + DNA(int num) { + genes = new char[num]; + for (int i = 0; i < genes.length; i++) { + genes[i] = (char) random(32,128); // Pick from range of chars + } + } + + // Converts character array to a String + String getPhrase() { + return new String(genes); + } + + // Fitness function (returns floating point % of "correct" characters) + void fitness (String target) { + int score = 0; + for (int i = 0; i < genes.length; i++) { + if (genes[i] == target.charAt(i)) { + score++; + } + } + fitness = pow(2,score); + } + + // Crossover + DNA crossover(DNA partner) { + // A new child + DNA child = new DNA(genes.length); + + int midpoint = int(random(genes.length)); // Pick a midpoint + + // Half from one, half from the other + for (int i = 0; i < genes.length; i++) { + if (i > midpoint) child.genes[i] = genes[i]; + else child.genes[i] = partner.genes[i]; + } + return child; + } + + // Based on a mutation probability, picks a new random character + void mutate(float mutationRate) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < mutationRate) { + genes[i] = (char) random(32,128); + } + } + } +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/GA_Shakespeare_fancyfitness.pde b/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/GA_Shakespeare_fancyfitness.pde new file mode 100644 index 000000000..a50ef3319 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/GA_Shakespeare_fancyfitness.pde @@ -0,0 +1,89 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// Demonstration of using a genetic algorithm to perform a search + +// setup() +// # Step 1: The populationation +// # Create an empty populationation (an array or ArrayList) +// # Fill it with DNA encoded objects (pick random values to start) + +// draw() +// # Step 1: Selection +// # Create an empty mating pool (an empty ArrayList) +// # For every member of the populationation, evaluate its fitness based on some criteria / function, +// and add it to the mating pool in a manner consistant with its fitness, i.e. the more fit it +// is the more times it appears in the mating pool, in order to be more likely picked for reproduction. + +// # Step 2: Reproduction Create a new empty populationation +// # Fill the new populationation by executing the following steps: +// 1. Pick two "parent" objects from the mating pool. +// 2. Crossover -- create a "child" object by mating these two parents. +// 3. Mutation -- mutate the child's DNA based on a given probability. +// 4. Add the child object to the new populationation. +// # Replace the old populationation with the new populationation +// +// # Rinse and repeat + + +PFont f; +String target; +int popmax; +float mutationRate; +Population population; + +void setup() { + size(600, 200); + f = createFont("Courier", 32, true); + target = "To be or not to be."; + popmax = 150; + mutationRate = 0.01; + + // Create a populationation with a target phrase, mutation rate, and populationation max + population = new Population(target, mutationRate, popmax); +} + +void draw() { + // Generate mating pool + population.naturalSelection(); + //Create next generation + population.generate(); + // Calculate fitness + population.calcFitness(); + displayInfo(); + + // If we found the target phrase, stop + if (population.finished()) { + println(millis()/1000.0); + noLoop(); + } +} + +void displayInfo() { + background(255); + // Display current status of populationation + String answer = population.getBest(); + textFont(f); + textAlign(LEFT); + fill(0); + + + textSize(16); + text("Best phrase:",20,30); + textSize(32); + text(answer, 20, 75); + + textSize(12); + text("total generations: " + population.getGenerations(), 20, 140); + text("average fitness: " + nf(population.getAverageFitness(), 0, 2), 20, 155); + text("total populationation: " + popmax, 20, 170); + text("mutation rate: " + int(mutationRate * 100) + "%", 20, 185); + + textSize(10); + text("All phrases:\n" + population.allPhrases(), 450, 10); +} + + diff --git a/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/Population.pde b/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/Population.pde new file mode 100644 index 000000000..03630a706 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/GA_Shakespeare_fancyfitness/Population.pde @@ -0,0 +1,127 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// A class to describe a population of virtual organisms +// In this case, each organism is just an instance of a DNA object + +class Population { + + float mutationRate; // Mutation rate + DNA[] population; // Array to hold the current population + ArrayList matingPool; // ArrayList which we will use for our "mating pool" + String target; // Target phrase + int generations; // Number of generations + boolean finished; // Are we finished evolving? + int perfectScore; + + Population(String p, float m, int num) { + target = p; + mutationRate = m; + population = new DNA[num]; + for (int i = 0; i < population.length; i++) { + population[i] = new DNA(target.length()); + } + calcFitness(); + matingPool = new ArrayList(); + finished = false; + generations = 0; + + perfectScore = int(pow(2,target.length())); + } + + // Fill our fitness array with a value for every member of the population + void calcFitness() { + for (int i = 0; i < population.length; i++) { + population[i].fitness(target); + } + } + + // Generate a mating pool + void naturalSelection() { + // Clear the ArrayList + matingPool.clear(); + + float maxFitness = 0; + for (int i = 0; i < population.length; i++) { + if (population[i].fitness > maxFitness) { + maxFitness = population[i].fitness; + } + } + + // Based on fitness, each member will get added to the mating pool a certain number of times + // a higher fitness = more entries to mating pool = more likely to be picked as a parent + // a lower fitness = fewer entries to mating pool = less likely to be picked as a parent + for (int i = 0; i < population.length; i++) { + + float fitness = map(population[i].fitness,0,maxFitness,0,1); + int n = int(fitness * 100); // Arbitrary multiplier, we can also use monte carlo method + for (int j = 0; j < n; j++) { // and pick two random numbers + matingPool.add(population[i]); + } + } + } + + // Create a new generation + void generate() { + // Refill the population with children from the mating pool + for (int i = 0; i < population.length; i++) { + int a = int(random(matingPool.size())); + int b = int(random(matingPool.size())); + DNA partnerA = matingPool.get(a); + DNA partnerB = matingPool.get(b); + DNA child = partnerA.crossover(partnerB); + child.mutate(mutationRate); + population[i] = child; + } + generations++; + } + + + // Compute the current "most fit" member of the population + String getBest() { + float worldrecord = 0.0f; + int index = 0; + for (int i = 0; i < population.length; i++) { + if (population[i].fitness > worldrecord) { + index = i; + worldrecord = population[i].fitness; + } + } + + if (worldrecord == perfectScore ) finished = true; + return population[index].getPhrase(); + } + + boolean finished() { + return finished; + } + + int getGenerations() { + return generations; + } + + // Compute average fitness for the population + float getAverageFitness() { + float total = 0; + for (int i = 0; i < population.length; i++) { + total += population[i].fitness; + } + return total / (population.length); + } + + String allPhrases() { + String everything = ""; + + int displayLimit = min(population.length,50); + + + for (int i = 0; i < displayLimit; i++) { + everything += population[i].getPhrase() + "\n"; + } + return everything; + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/DNA.pde new file mode 100644 index 000000000..efb8845af --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/DNA.pde @@ -0,0 +1,70 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// A class to describe a psuedo-DNA, i.e. genotype +// Here, a virtual organism's DNA is an array of character. +// Functionality: +// -- convert DNA into a string +// -- calculate DNA's "fitness" +// -- mate DNA with another set of DNA +// -- mutate DNA + + +class DNA { + + // The genetic sequence + char[] genes; + + float fitness; + + // Constructor (makes a random DNA) + DNA(int num) { + genes = new char[num]; + for (int i = 0; i < genes.length; i++) { + genes[i] = (char) random(32,128); // Pick from range of chars + } + } + + // Converts character array to a String + String getPhrase() { + return new String(genes); + } + + // Fitness function (returns floating point % of "correct" characters) + void fitness (String target) { + int score = 0; + for (int i = 0; i < genes.length; i++) { + if (genes[i] == target.charAt(i)) { + score++; + } + } + fitness = (float)score / (float)target.length(); + } + + // Crossover + DNA crossover(DNA partner) { + // A new child + DNA child = new DNA(genes.length); + + int midpoint = int(random(genes.length)); // Pick a midpoint + + // Half from one, half from the other + for (int i = 0; i < genes.length; i++) { + if (i > midpoint) child.genes[i] = genes[i]; + else child.genes[i] = partner.genes[i]; + } + return child; + } + + // Based on a mutation probability, picks a new random character + void mutate(float mutationRate) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < mutationRate) { + genes[i] = (char) random(32,128); + } + } + } +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/NOC_9_01_GA_Shakespeare.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/NOC_9_01_GA_Shakespeare.pde new file mode 100644 index 000000000..4f29b56d7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/NOC_9_01_GA_Shakespeare.pde @@ -0,0 +1,90 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// Demonstration of using a genetic algorithm to perform a search + +// setup() +// # Step 1: The Population +// # Create an empty population (an array or ArrayList) +// # Fill it with DNA encoded objects (pick random values to start) + +// draw() +// # Step 1: Selection +// # Create an empty mating pool (an empty ArrayList) +// # For every member of the population, evaluate its fitness based on some criteria / function, +// and add it to the mating pool in a manner consistant with its fitness, i.e. the more fit it +// is the more times it appears in the mating pool, in order to be more likely picked for reproduction. + +// # Step 2: Reproduction Create a new empty population +// # Fill the new population by executing the following steps: +// 1. Pick two "parent" objects from the mating pool. +// 2. Crossover -- create a "child" object by mating these two parents. +// 3. Mutation -- mutate the child's DNA based on a given probability. +// 4. Add the child object to the new population. +// # Replace the old population with the new population +// +// # Rinse and repeat + + +PFont f; +String target; +int popmax; +float mutationRate; +Population population; + +void setup() { + size(800, 200); + f = createFont("Courier", 32, true); + target = "To be or not to be."; + popmax = 150; + mutationRate = 0.01; + + // Create a populationation with a target phrase, mutation rate, and populationation max + population = new Population(target, mutationRate, popmax); +} + +void draw() { + // Generate mating pool + population.naturalSelection(); + //Create next generation + population.generate(); + // Calculate fitness + population.calcFitness(); + displayInfo(); + + // If we found the target phrase, stop + if (population.finished()) { + println(millis()/1000.0); + noLoop(); + } +} + +void displayInfo() { + background(255); + // Display current status of populationation + String answer = population.getBest(); + textFont(f); + textAlign(LEFT); + fill(0); + + + textSize(16); + text("Best phrase:",20,30); + textSize(32); + text(answer, 20, 75); + + textSize(12); + text("total generations: " + population.getGenerations(), 20, 140); + text("average fitness: " + nf(population.getAverageFitness(), 0, 2), 20, 155); + text("total populationation: " + popmax, 20, 170); + text("mutation rate: " + int(mutationRate * 100) + "%", 20, 185); + + textSize(10); + text("All phrases:\n" + population.allPhrases(), 650, 10); +} + + + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/Population.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/Population.pde new file mode 100644 index 000000000..03630a706 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/Population.pde @@ -0,0 +1,127 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// A class to describe a population of virtual organisms +// In this case, each organism is just an instance of a DNA object + +class Population { + + float mutationRate; // Mutation rate + DNA[] population; // Array to hold the current population + ArrayList matingPool; // ArrayList which we will use for our "mating pool" + String target; // Target phrase + int generations; // Number of generations + boolean finished; // Are we finished evolving? + int perfectScore; + + Population(String p, float m, int num) { + target = p; + mutationRate = m; + population = new DNA[num]; + for (int i = 0; i < population.length; i++) { + population[i] = new DNA(target.length()); + } + calcFitness(); + matingPool = new ArrayList(); + finished = false; + generations = 0; + + perfectScore = int(pow(2,target.length())); + } + + // Fill our fitness array with a value for every member of the population + void calcFitness() { + for (int i = 0; i < population.length; i++) { + population[i].fitness(target); + } + } + + // Generate a mating pool + void naturalSelection() { + // Clear the ArrayList + matingPool.clear(); + + float maxFitness = 0; + for (int i = 0; i < population.length; i++) { + if (population[i].fitness > maxFitness) { + maxFitness = population[i].fitness; + } + } + + // Based on fitness, each member will get added to the mating pool a certain number of times + // a higher fitness = more entries to mating pool = more likely to be picked as a parent + // a lower fitness = fewer entries to mating pool = less likely to be picked as a parent + for (int i = 0; i < population.length; i++) { + + float fitness = map(population[i].fitness,0,maxFitness,0,1); + int n = int(fitness * 100); // Arbitrary multiplier, we can also use monte carlo method + for (int j = 0; j < n; j++) { // and pick two random numbers + matingPool.add(population[i]); + } + } + } + + // Create a new generation + void generate() { + // Refill the population with children from the mating pool + for (int i = 0; i < population.length; i++) { + int a = int(random(matingPool.size())); + int b = int(random(matingPool.size())); + DNA partnerA = matingPool.get(a); + DNA partnerB = matingPool.get(b); + DNA child = partnerA.crossover(partnerB); + child.mutate(mutationRate); + population[i] = child; + } + generations++; + } + + + // Compute the current "most fit" member of the population + String getBest() { + float worldrecord = 0.0f; + int index = 0; + for (int i = 0; i < population.length; i++) { + if (population[i].fitness > worldrecord) { + index = i; + worldrecord = population[i].fitness; + } + } + + if (worldrecord == perfectScore ) finished = true; + return population[index].getPhrase(); + } + + boolean finished() { + return finished; + } + + int getGenerations() { + return generations; + } + + // Compute average fitness for the population + float getAverageFitness() { + float total = 0; + for (int i = 0; i < population.length; i++) { + total += population[i].fitness; + } + return total / (population.length); + } + + String allPhrases() { + String everything = ""; + + int displayLimit = min(population.length,50); + + + for (int i = 0; i < displayLimit; i++) { + everything += population[i].getPhrase() + "\n"; + } + return everything; + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/sketch.properties b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/sketch.properties new file mode 100644 index 000000000..b3cbe600e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare/sketch.properties @@ -0,0 +1,2 @@ +mode.id=processing.mode.java.JavaMode +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare_simplified/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare_simplified/DNA.pde new file mode 100644 index 000000000..e4ce06c31 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare_simplified/DNA.pde @@ -0,0 +1,70 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// A class to describe a psuedo-DNA, i.e. genotype +// Here, a virtual organism's DNA is an array of character. +// Functionality: +// -- convert DNA into a string +// -- calculate DNA's "fitness" +// -- mate DNA with another set of DNA +// -- mutate DNA + + +class DNA { + + // The genetic sequence + char[] genes; + + float fitness; + + // Constructor (makes a random DNA) + DNA(int num) { + genes = new char[num]; + for (int i = 0; i < genes.length; i++) { + genes[i] = (char) random(32,128); // Pick from range of chars + } + } + + // Converts character array to a String + String getPhrase() { + return new String(genes); + } + + // Fitness function (returns floating point % of "correct" characters) + void calcFitness (String target) { + int score = 0; + for (int i = 0; i < genes.length; i++) { + if (genes[i] == target.charAt(i)) { + score++; + } + } + fitness = (float)score / (float)target.length(); + } + + // Crossover + DNA crossover(DNA partner) { + // A new child + DNA child = new DNA(genes.length); + + int midpoint = int(random(genes.length)); // Pick a midpoint + + // Half from one, half from the other + for (int i = 0; i < genes.length; i++) { + if (i > midpoint) child.genes[i] = genes[i]; + else child.genes[i] = partner.genes[i]; + } + return child; + } + + // Based on a mutation probability, picks a new random character + void mutate(float mutationRate) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < mutationRate) { + genes[i] = (char) random(32,128); + } + } + } +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare_simplified/NOC_9_01_GA_Shakespeare_simplified.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare_simplified/NOC_9_01_GA_Shakespeare_simplified.pde new file mode 100644 index 000000000..a46d90a23 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_01_GA_Shakespeare_simplified/NOC_9_01_GA_Shakespeare_simplified.pde @@ -0,0 +1,89 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Genetic Algorithm, Evolving Shakespeare + +// Demonstration of using a genetic algorithm to perform a search + +// setup() +// # Step 1: The Population +// # Create an empty population (an array or ArrayList) +// # Fill it with DNA encoded objects (pick random values to start) + +// draw() +// # Step 1: Selection +// # Create an empty mating pool (an empty ArrayList) +// # For every member of the population, evaluate its fitness based on some criteria / function, +// and add it to the mating pool in a manner consistant with its fitness, i.e. the more fit it +// is the more times it appears in the mating pool, in order to be more likely picked for reproduction. + +// # Step 2: Reproduction Create a new empty population +// # Fill the new population by executing the following steps: +// 1. Pick two "parent" objects from the mating pool. +// 2. Crossover -- create a "child" object by mating these two parents. +// 3. Mutation -- mutate the child's DNA based on a given probability. +// 4. Add the child object to the new population. +// # Replace the old population with the new population +// +// # Rinse and repeat + + +float mutationRate = 0.01; // Mutation rate +int totalPopulation = 150; // Total Population + +DNA[] population; // Array to hold the current population +ArrayList matingPool; // ArrayList which we will use for our "mating pool" +String target; // Target phrase + +PFont f; + +void setup() { + size(800, 200); + target = "to be or not to be"; + + population = new DNA[totalPopulation]; + + for (int i = 0; i < population.length; i++) { + population[i] = new DNA(target.length()); + } + + f = createFont("Courier",12,true); +} + +void draw() { + for (int i = 0; i < population.length; i++) { + population[i].calcFitness(target); + } + + ArrayList matingPool = new ArrayList(); // ArrayList which we will use for our "mating pool" + + for (int i = 0; i < population.length; i++) { + int nnnn = int(population[i].fitness * 100); // Arbitrary multiplier, we can also use monte carlo method + for (int j = 0; j crossover) child[i] = genes[i]; + else child[i] = partner.genes[i]; + } + DNA newgenes = new DNA(child); + return newgenes; + } + + // Based on a mutation probability, picks a new random Vector + void mutate(float m) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < m) { + float angle = random(TWO_PI); + genes[i] = new PVector(cos(angle), sin(angle)); + genes[i].mult(random(0, maxforce)); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/NOC_9_02_SmartRockets_superbasic.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/NOC_9_02_SmartRockets_superbasic.pde new file mode 100644 index 000000000..ef3443995 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/NOC_9_02_SmartRockets_superbasic.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Smart Rockets w/ Genetic Algorithms + +// Each Rocket's DNA is an array of PVectors +// Each PVector acts as a force for each frame of animation +// Imagine an booster on the end of the rocket that can point in any direction +// and fire at any strength every frame + +// The Rocket's fitness is a function of how close it gets to the target as well as how fast it gets there + +// This example is inspired by Jer Thorp's Smart Rockets +// http://www.blprnt.com/smartrockets/ + +int lifetime; // How long should each generation live + +Population population; // Population + +int lifeCounter; // Timer for cycle of generation + +PVector target; // Target location + +void setup() { + size(800, 200); + // The number of cycles we will allow a generation to live + lifetime = 200; + + // Initialize variables + lifeCounter = 0; + + target = new PVector(width/2, 24); + + // Create a population with a mutation rate, and population max + float mutationRate = 0.01; + population = new Population(mutationRate, 50); + +} + +void draw() { + background(255); + + // Draw the start and target locations + fill(0); + ellipse(target.x,target.y,24,24); + + + // If the generation hasn't ended yet + if (lifeCounter < lifetime) { + population.live(); + lifeCounter++; + // Otherwise a new generation + } + else { + lifeCounter = 0; + population.fitness(); + population.selection(); + population.reproduction(); + } + + // Display some info + fill(0); + text("Generation #: " + population.getGenerations(), 10, 18); + text("Cycles left: " + (lifetime-lifeCounter), 10, 36); +} + +// Move the target if the mouse is pressed +// System will adapt to new target +void mousePressed() { + target.x = mouseX; + target.y = mouseY; +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Population.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Population.pde new file mode 100644 index 000000000..128d38636 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Population.pde @@ -0,0 +1,103 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// A class to describe a population of "creatures" + +class Population { + + float mutationRate; // Mutation rate + Rocket[] population; // Array to hold the current population + ArrayList matingPool; // ArrayList which we will use for our "mating pool" + int generations; // Number of generations + + // Initialize the population + Population(float m, int num) { + mutationRate = m; + population = new Rocket[num]; + matingPool = new ArrayList(); + generations = 0; + //make a new set of creatures + for (int i = 0; i < population.length; i++) { + PVector location = new PVector(width/2,height+20); + population[i] = new Rocket(location, new DNA()); + } + } + + void live () { + // Run every rocket + for (int i = 0; i < population.length; i++) { + population[i].run(); + } + } + + // Calculate fitness for each creature + void fitness() { + for (int i = 0; i < population.length; i++) { + population[i].fitness(); + } + } + + // Generate a mating pool + void selection() { + // Clear the ArrayList + matingPool.clear(); + + // Calculate total fitness of whole population + float maxFitness = getMaxFitness(); + + // Calculate fitness for each member of the population (scaled to value between 0 and 1) + // Based on fitness, each member will get added to the mating pool a certain number of times + // A higher fitness = more entries to mating pool = more likely to be picked as a parent + // A lower fitness = fewer entries to mating pool = less likely to be picked as a parent + for (int i = 0; i < population.length; i++) { + float fitnessNormal = map(population[i].getFitness(),0,maxFitness,0,1); + int n = (int) (fitnessNormal * 100); // Arbitrary multiplier + for (int j = 0; j < n; j++) { + matingPool.add(population[i]); + } + } + } + + // Making the next generation + void reproduction() { + // Refill the population with children from the mating pool + for (int i = 0; i < population.length; i++) { + // Sping the wheel of fortune to pick two parents + int m = int(random(matingPool.size())); + int d = int(random(matingPool.size())); + // Pick two parents + Rocket mom = matingPool.get(m); + Rocket dad = matingPool.get(d); + // Get their genes + DNA momgenes = mom.getDNA(); + DNA dadgenes = dad.getDNA(); + // Mate their genes + DNA child = momgenes.crossover(dadgenes); + // Mutate their genes + child.mutate(mutationRate); + // Fill the new population with the new child + PVector location = new PVector(width/2,height+20); + population[i] = new Rocket(location, child); + } + generations++; + } + + int getGenerations() { + return generations; + } + + // Find highest fintess for the population + float getMaxFitness() { + float record = 0; + for (int i = 0; i < population.length; i++) { + if(population[i].getFitness() > record) { + record = population[i].getFitness(); + } + } + return record; + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde new file mode 100644 index 000000000..2456856e4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde @@ -0,0 +1,108 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// Rocket class -- this is just like our Boid / Particle class +// the only difference is that it has DNA & fitness + +class Rocket { + + // All of our physics stuff + PVector location; + PVector velocity; + PVector acceleration; + + // Size + float r; + + // Fitness and DNA + float fitness; + DNA dna; + // To count which force we're on in the genes + int geneCounter = 0; + + boolean hitTarget = false; // Did I reach the target + + //constructor + Rocket(PVector l, DNA dna_) { + acceleration = new PVector(); + velocity = new PVector(); + location = l.get(); + r = 4; + dna = dna_; + } + + // Fitness function + // fitness = one divided by distance squared + void fitness() { + float d = dist(location.x, location.y, target.x, target.y); + fitness = pow(1/d, 2); + } + + // Run in relation to all the obstacles + // If I'm stuck, don't bother updating or checking for intersection + void run() { + checkTarget(); // Check to see if we've reached the target + if (!hitTarget) { + applyForce(dna.genes[geneCounter]); + geneCounter = (geneCounter + 1) % dna.genes.length; + update(); + } + display(); + } + + // Did I make it to the target? + void checkTarget() { + float d = dist(location.x, location.y, target.x, target.y); + if (d < 12) { + hitTarget = true; + } + } + + void applyForce(PVector f) { + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + float theta = velocity.heading2D() + PI/2; + fill(200, 100); + stroke(0); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + + // Thrusters + rectMode(CENTER); + fill(0); + rect(-r/2, r*2, r/2, r); + rect(r/2, r*2, r/2, r); + + // Rocket body + fill(175); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + + popMatrix(); + } + + float getFitness() { + return fitness; + } + + DNA getDNA() { + return dna; + } + +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/DNA.pde new file mode 100644 index 000000000..b4eefe1cf --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/DNA.pde @@ -0,0 +1,68 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// DNA is an array of vectors + +class DNA { + + // The genetic sequence + PVector[] genes; + + // The maximum strength of the forces + float maxforce = 0.1; + + // Constructor (makes a DNA of random PVectors) + DNA() { + genes = new PVector[lifetime]; + for (int i = 0; i < genes.length; i++) { + float angle = random(TWO_PI); + genes[i] = new PVector(cos(angle), sin(angle)); + genes[i].mult(random(0, maxforce)); + } + + // Let's give each Rocket an extra boost of strength for its first frame + genes[0].normalize(); + } + + // Constructor #2, creates the instance based on an existing array + DNA(PVector[] newgenes) { + // We could make a copy if necessary + // genes = (PVector []) newgenes.clone(); + genes = newgenes; + } + + // CROSSOVER + // Creates new DNA sequence from two (this & and a partner) + DNA crossover(DNA partner) { + PVector[] child = new PVector[genes.length]; + // Pick a midpoint + int crossover = int(random(genes.length)); + // Take "half" from one and "half" from the other + for (int i = 0; i < genes.length; i++) { + if (i > crossover) child[i] = genes[i]; + else child[i] = partner.genes[i]; + } + DNA newgenes = new DNA(child); + return newgenes; + } + + // Based on a mutation probability, picks a new random Vector + void mutate(float m) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < m) { + float angle = random(TWO_PI); + genes[i] = new PVector(cos(angle), sin(angle)); + genes[i].mult(random(0, maxforce)); + // float angle = random(-0.1,0.1); + // genes[i].rotate(angle); + // float factor = random(0.9,1.1); + // genes[i].mult(factor); + if (i ==0) genes[i].normalize(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/NOC_9_03_SmartRockets.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/NOC_9_03_SmartRockets.pde new file mode 100644 index 000000000..1c0bba4ea --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/NOC_9_03_SmartRockets.pde @@ -0,0 +1,94 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Smart Rockets w/ Genetic Algorithms + +// Each Rocket's DNA is an array of PVectors +// Each PVector acts as a force for each frame of animation +// Imagine an booster on the end of the rocket that can point in any direction +// and fire at any strength every frame + +// The Rocket's fitness is a function of how close it gets to the target as well as how fast it gets there + +// This example is inspired by Jer Thorp's Smart Rockets +// http://www.blprnt.com/smartrockets/ + +int lifetime; // How long should each generation live + +Population population; // Population + +int lifecycle; // Timer for cycle of generation +int recordtime; // Fastest time to target + +Obstacle target; // Target location + +//int diam = 24; // Size of target + +ArrayList obstacles; //an array list to keep track of all the obstacles! + +void setup() { + size(800, 200); + // The number of cycles we will allow a generation to live + lifetime = 300; + + // Initialize variables + lifecycle = 0; + recordtime = lifetime; + + target = new Obstacle(width/2-12, 24, 24, 24); + + // Create a population with a mutation rate, and population max + float mutationRate = 0.01; + population = new Population(mutationRate, 50); + + // Create the obstacle course + obstacles = new ArrayList(); + obstacles.add(new Obstacle(300, height/2, width-600, 10)); +} + +void draw() { + background(255); + + // Draw the start and target locations + target.display(); + + + // If the generation hasn't ended yet + if (lifecycle < lifetime) { + population.live(obstacles); + if ((population.targetReached()) && (lifecycle < recordtime)) { + recordtime = lifecycle; + } + lifecycle++; + // Otherwise a new generation + } + else { + lifecycle = 0; + population.fitness(); + population.selection(); + population.reproduction(); + } + + // Draw the obstacles + for (Obstacle obs : obstacles) { + obs.display(); + } + + // Display some info + fill(0); + text("Generation #: " + population.getGenerations(), 10, 18); + text("Cycles left: " + (lifetime-lifecycle), 10, 36); + text("Record cycles: " + recordtime, 10, 54); + + +} + +// Move the target if the mouse is pressed +// System will adapt to new target +void mousePressed() { + target.location.x = mouseX; + target.location.y = mouseY; + recordtime = lifetime; +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Obstacle.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Obstacle.pde new file mode 100644 index 000000000..e7d3d249f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Obstacle.pde @@ -0,0 +1,40 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// A class for an obstacle, just a simple rectangle that is drawn +// and can check if a Rocket touches it + +// Also using this class for target location + + +class Obstacle { + + PVector location; + float w,h; + + Obstacle(float x, float y, float w_, float h_) { + location = new PVector(x,y); + w = w_; + h = h_; + } + + void display() { + stroke(0); + fill(175); + strokeWeight(2); + rectMode(CORNER); + rect(location.x,location.y,w,h); + } + + boolean contains(PVector spot) { + if (spot.x > location.x && spot.x < location.x + w && spot.y > location.y && spot.y < location.y + h) { + return true; + } else { + return false; + } + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Population.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Population.pde new file mode 100644 index 000000000..432bf3b14 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Population.pde @@ -0,0 +1,113 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Pathfinding w/ Genetic Algorithms + +// A class to describe a population of "creatures" + +class Population { + + float mutationRate; // Mutation rate + Rocket[] population; // Array to hold the current population + ArrayList matingPool; // ArrayList which we will use for our "mating pool" + int generations; // Number of generations + + // Initialize the population + Population(float m, int num) { + mutationRate = m; + population = new Rocket[num]; + matingPool = new ArrayList(); + generations = 0; + //make a new set of creatures + for (int i = 0; i < population.length; i++) { + PVector location = new PVector(width/2,height+20); + population[i] = new Rocket(location, new DNA(),population.length); + } + } + + void live (ArrayList os) { + // For every creature + for (int i = 0; i < population.length; i++) { + // If it finishes, mark it down as done! + population[i].checkTarget(); + population[i].run(os); + } + } + + // Did anything finish? + boolean targetReached() { + for (int i = 0; i < population.length; i++) { + if (population[i].hitTarget) return true; + } + return false; + } + + // Calculate fitness for each creature + void fitness() { + for (int i = 0; i < population.length; i++) { + population[i].fitness(); + } + } + + // Generate a mating pool + void selection() { + // Clear the ArrayList + matingPool.clear(); + + // Calculate total fitness of whole population + float maxFitness = getMaxFitness(); + + // Calculate fitness for each member of the population (scaled to value between 0 and 1) + // Based on fitness, each member will get added to the mating pool a certain number of times + // A higher fitness = more entries to mating pool = more likely to be picked as a parent + // A lower fitness = fewer entries to mating pool = less likely to be picked as a parent + for (int i = 0; i < population.length; i++) { + float fitnessNormal = map(population[i].getFitness(),0,maxFitness,0,1); + int n = (int) (fitnessNormal * 100); // Arbitrary multiplier + for (int j = 0; j < n; j++) { + matingPool.add(population[i]); + } + } + } + + // Making the next generation + void reproduction() { + // Refill the population with children from the mating pool + for (int i = 0; i < population.length; i++) { + // Sping the wheel of fortune to pick two parents + int m = int(random(matingPool.size())); + int d = int(random(matingPool.size())); + // Pick two parents + Rocket mom = matingPool.get(m); + Rocket dad = matingPool.get(d); + // Get their genes + DNA momgenes = mom.getDNA(); + DNA dadgenes = dad.getDNA(); + // Mate their genes + DNA child = momgenes.crossover(dadgenes); + // Mutate their genes + child.mutate(mutationRate); + // Fill the new population with the new child + PVector location = new PVector(width/2,height+20); + population[i] = new Rocket(location, child,population.length); + } + generations++; + } + + int getGenerations() { + return generations; + } + + // Find highest fintess for the population + float getMaxFitness() { + float record = 0; + for (int i = 0; i < population.length; i++) { + if(population[i].getFitness() > record) { + record = population[i].getFitness(); + } + } + return record; + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde new file mode 100644 index 000000000..5ce1b313b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde @@ -0,0 +1,148 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Rocket class -- this is just like our Boid / Particle class +// the only difference is that it has DNA & fitness + +class Rocket { + + // All of our physics stuff + PVector location; + PVector velocity; + PVector acceleration; + + // Size + float r; + + // How close did it get to the target + float recordDist; + + // Fitness and DNA + float fitness; + DNA dna; + // To count which force we're on in the genes + int geneCounter = 0; + + boolean hitObstacle = false; // Am I stuck on an obstacle? + boolean hitTarget = false; // Did I reach the target + int finishTime; // What was my finish time? + + //constructor + Rocket(PVector l, DNA dna_, int totalRockets) { + acceleration = new PVector(); + velocity = new PVector(); + location = l.get(); + r = 4; + dna = dna_; + finishTime = 0; // We're going to count how long it takes to reach target + recordDist = 10000; // Some high number that will be beat instantly + } + + // FITNESS FUNCTION + // distance = distance from target + // finish = what order did i finish (first, second, etc. . .) + // f(distance,finish) = (1.0f / finish^1.5) * (1.0f / distance^6); + // a lower finish is rewarded (exponentially) and/or shorter distance to target (exponetially) + void fitness() { + if (recordDist < 1) recordDist = 1; + + // Reward finishing faster and getting close + fitness = (1/(finishTime*recordDist)); + + // Make the function exponential + fitness = pow(fitness, 4); + + if (hitObstacle) fitness *= 0.1; // lose 90% of fitness hitting an obstacle + if (hitTarget) fitness *= 2; // twice the fitness for finishing! + } + + // Run in relation to all the obstacles + // If I'm stuck, don't bother updating or checking for intersection + void run(ArrayList os) { + if (!hitObstacle && !hitTarget) { + applyForce(dna.genes[geneCounter]); + geneCounter = (geneCounter + 1) % dna.genes.length; + update(); + // If I hit an edge or an obstacle + obstacles(os); + } + // Draw me! + if (!hitObstacle) { + display(); + } + } + + // Did I make it to the target? + void checkTarget() { + float d = dist(location.x, location.y, target.location.x, target.location.y); + if (d < recordDist) recordDist = d; + + if (target.contains(location) && !hitTarget) { + hitTarget = true; + } + else if (!hitTarget) { + finishTime++; + } + } + + // Did I hit an obstacle? + void obstacles(ArrayList os) { + for (Obstacle obs : os) { + if (obs.contains(location)) { + hitObstacle = true; + } + } + } + + void applyForce(PVector f) { + acceleration.add(f); + } + + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + //background(255,0,0); + float theta = velocity.heading2D() + PI/2; + fill(200, 100); + stroke(0); + strokeWeight(1); + pushMatrix(); + translate(location.x, location.y); + rotate(theta); + + // Thrusters + rectMode(CENTER); + fill(0); + rect(-r/2, r*2, r/2, r); + rect(r/2, r*2, r/2, r); + + // Rocket body + fill(175); + beginShape(TRIANGLES); + vertex(0, -r*2); + vertex(-r, r*2); + vertex(r, r*2); + endShape(); + + popMatrix(); + } + + float getFitness() { + return fitness; + } + + DNA getDNA() { + return dna; + } + + boolean stopped() { + return hitObstacle; + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/sketch.properties b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Button.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Button.pde new file mode 100644 index 000000000..eb35675ce --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Button.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +//import java.awt.Rectangle; + +class Button { + Rectangle r; // Button's rectangle + String txt; // Button's text + boolean clickedOn; // Did i click on it? + boolean rolloverOn; // Did i rollover it? + + Button(int x, int y, int w, int h, String s) { + r = new Rectangle(x,y,w,h); + txt = s; + } + + void display() { + // Draw rectangle and text based on whether rollover or clicked + rectMode(CORNER); + stroke(0); noFill(); + if (rolloverOn) fill(0.5); + if (clickedOn) fill(0); + rect(r.x,r.y,r.width,r.height); + float b = 0.0; + if (clickedOn) b = 1; + else if (rolloverOn) b = 0.2; + else b = 0; + fill(b); + textAlign(LEFT); + text(txt,r.x+10,r.y+14); + + } + + + // Methods to check rollover, clicked, or released (must be called from appropriate + // Places in draw, mousePressed, mouseReleased + boolean rollover(int mx, int my) { + if (r.contains(mx,my)) rolloverOn = true; + else rolloverOn = false; + return rolloverOn; + } + + boolean clicked(int mx, int my) { + if (r.contains(mx,my)) clickedOn = true; + return clickedOn; + } + + void released() { + clickedOn = false; + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/DNA.pde new file mode 100644 index 000000000..8825979b1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/DNA.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +class DNA { + + // The genetic sequence + float[] genes; + int len = 20; // Arbitrary length + + //Constructor (makes a random DNA) + DNA() { + // DNA is random floating point values between 0 and 1 (!!) + genes = new float[len]; + for (int i = 0; i < genes.length; i++) { + genes[i] = random(0,1); + } + } + + DNA(float[] newgenes) { + genes = newgenes; + } + + + // Crossover + // Creates new DNA sequence from two (this & + DNA crossover(DNA partner) { + float[] child = new float[genes.length]; + int crossover = int(random(genes.length)); + for (int i = 0; i < genes.length; i++) { + if (i > crossover) child[i] = genes[i]; + else child[i] = partner.genes[i]; + } + DNA newgenes = new DNA(child); + return newgenes; + } + + // Based on a mutation probability, picks a new random character in array spots + void mutate(float m) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < m) { + genes[i] = random(0,1); + } + } + } +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Face.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Face.pde new file mode 100644 index 000000000..4a2992b6f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Face.pde @@ -0,0 +1,103 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +// The class for our "face", contains DNA sequence, fitness value, position on screen + +// Fitness Function f(t) = t (where t is "time" mouse rolls over face) + +class Face { + + DNA dna; // Face's DNA + float fitness; // How good is this face? + float x, y; // Position on screen + int wh = 70; // Size of square enclosing face + boolean rolloverOn; // Are we rolling over this face? + + Rectangle r; + + // Create a new face + Face(DNA dna_, float x_, float y_) { + dna = dna_; + x = x_; + y = y_; + fitness = 1; + // Using java.awt.Rectangle (see: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Rectangle.html) + r = new Rectangle(int(x-wh/2), int(y-wh/2), int(wh), int(wh)); + } + + // Display the face + void display() { + // We are using the face's DNA to pick properties for this face + // such as: head size, color, eye position, etc. + // Now, since every gene is a floating point between 0 and 1, we map the values + float r = map(dna.genes[0],0,1,0,70); + color c = color(dna.genes[1],dna.genes[2],dna.genes[3]); + float eye_y = map(dna.genes[4],0,1,0,5); + float eye_x = map(dna.genes[5],0,1,0,10); + float eye_size = map(dna.genes[5],0,1,0,10); + color eyecolor = color(dna.genes[4],dna.genes[5],dna.genes[6]); + color mouthColor = color(dna.genes[7],dna.genes[8],dna.genes[9]); + float mouth_y = map(dna.genes[5],0,1,0,25); + float mouth_x = map(dna.genes[5],0,1,-25,25); + float mouthw = map(dna.genes[5],0,1,0,50); + float mouthh = map(dna.genes[5],0,1,0,10); + + // Once we calculate all the above properties, we use those variables to draw rects, ellipses, etc. + pushMatrix(); + translate(x, y); + noStroke(); + + // Draw the head + fill(c); + ellipseMode(CENTER); + ellipse(0, 0, r, r); + + // Draw the eyes + fill(eyecolor); + rectMode(CENTER); + rect(-eye_x, -eye_y, eye_size, eye_size); + rect( eye_x, -eye_y, eye_size, eye_size); + + // Draw the mouth + fill(mouthColor); + rectMode(CENTER); + rect(mouth_x, mouth_y, mouthw, mouthh); + + // Draw the bounding box + stroke(0.25); + if (rolloverOn) fill(0, 0.25); + else noFill(); + rectMode(CENTER); + rect(0, 0, wh, wh); + popMatrix(); + + // Display fitness value + textAlign(CENTER); + if (rolloverOn) fill(0); + else fill(0.25); + text(int(fitness), x, y+55); + } + + float getFitness() { + return fitness; + } + + DNA getDNA() { + return dna; + } + + // Increment fitness if mouse is rolling over face + void rollover(int mx, int my) { + if (r.contains(mx, my)) { + rolloverOn = true; + fitness += 0.25; + } else { + rolloverOn = false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/NOC_9_04_Faces_interactiveselection.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/NOC_9_04_Faces_interactiveselection.pde new file mode 100644 index 000000000..e85545805 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/NOC_9_04_Faces_interactiveselection.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +Population population; +Button button; + +void setup() { + size(800,200); + colorMode(RGB,1.0); + int popmax = 10; + float mutationRate = 0.05; // A pretty high mutation rate here, our population is rather small we need to enforce variety + // Create a population with a target phrase, mutation rate, and population max + population = new Population(mutationRate,popmax); + // A simple button class + button = new Button(15,150,160,20, "evolve new generation"); +} + +void draw() { + background(1.0); + // Display the faces + population.display(); + population.rollover(mouseX,mouseY); + // Display some text + textAlign(LEFT); + fill(0); + text("Generation #:" + population.getGenerations(),15,190); + + // Display the button + button.display(); + button.rollover(mouseX,mouseY); + +} + +// If the button is clicked, evolve next generation +void mousePressed() { + if (button.clicked(mouseX,mouseY)) { + population.selection(); + population.reproduction(); + } +} + +void mouseReleased() { + button.released(); +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Population.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Population.pde new file mode 100644 index 000000000..625c6f9d1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Population.pde @@ -0,0 +1,102 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Interactive Selection +// http://www.genarts.com/karl/papers/siggraph91.html + +// A class to describe a population of faces +// this hasn't changed very much from example to example + +class Population { + + float mutationRate; // Mutation rate + Face[] population; // array to hold the current population + ArrayList matingPool; // ArrayList which we will use for our "mating pool" + int generations; // Number of generations + + // Create the population + Population(float m, int num) { + mutationRate = m; + population = new Face[num]; + matingPool = new ArrayList(); + generations = 0; + for (int i = 0; i < population.length; i++) { + population[i] = new Face(new DNA(), 50+i*75, 60); + } + } + + // Display all faces + void display() { + for (int i = 0; i < population.length; i++) { + population[i].display(); + } + } + + // Are we rolling over any of the faces? + void rollover(int mx, int my) { + for (int i = 0; i < population.length; i++) { + population[i].rollover(mx, my); + } + } + + // Generate a mating pool + void selection() { + // Clear the ArrayList + matingPool.clear(); + + // Calculate total fitness of whole population + float maxFitness = getMaxFitness(); + + // Calculate fitness for each member of the population (scaled to value between 0 and 1) + // Based on fitness, each member will get added to the mating pool a certain number of times + // A higher fitness = more entries to mating pool = more likely to be picked as a parent + // A lower fitness = fewer entries to mating pool = less likely to be picked as a parent + for (int i = 0; i < population.length; i++) { + float fitnessNormal = map(population[i].getFitness(), 0, maxFitness, 0, 1); + int n = (int) (fitnessNormal * 100); // Arbitrary multiplier + for (int j = 0; j < n; j++) { + matingPool.add(population[i]); + } + } + } + + // Making the next generation + void reproduction() { + // Refill the population with children from the mating pool + for (int i = 0; i < population.length; i++) { + // Sping the wheel of fortune to pick two parents + int m = int(random(matingPool.size())); + int d = int(random(matingPool.size())); + // Pick two parents + Face mom = matingPool.get(m); + Face dad = matingPool.get(d); + // Get their genes + DNA momgenes = mom.getDNA(); + DNA dadgenes = dad.getDNA(); + // Mate their genes + DNA child = momgenes.crossover(dadgenes); + // Mutate their genes + child.mutate(mutationRate); + // Fill the new population with the new child + population[i] = new Face(child, 50+i*75, 60); + } + generations++; + } + + int getGenerations() { + return generations; + } + + // Find highest fintess for the population + float getMaxFitness() { + float record = 0; + for (int i = 0; i < population.length; i++) { + if (population[i].getFitness() > record) { + record = population[i].getFitness(); + } + } + return record; + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Rectangle.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Rectangle.pde new file mode 100644 index 000000000..ed6d6d70c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_04_Faces_interactiveselection/Rectangle.pde @@ -0,0 +1,25 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Re-implementing java.awt.Rectangle +// so JS mode works + +class Rectangle { + int x; + int y; + int width; + int height; + + Rectangle(int x_, int y_, int w, int h) { + x = x_; + y = y_; + width = w; + height = h; + } + + boolean contains(int px, int py) { + return (px > x && px < x + width && py > y && py < y + height); + } + +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/Bloop.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/Bloop.pde new file mode 100644 index 000000000..7859b6630 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/Bloop.pde @@ -0,0 +1,108 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Evolution EcoSystem + +// Creature class + +class Bloop { + PVector location; // Location + DNA dna; // DNA + float health; // Life timer + float xoff; // For perlin noise + float yoff; + // DNA will determine size and maxspeed + float r; + float maxspeed; + + // Create a "bloop" creature + Bloop(PVector l, DNA dna_) { + location = l.get(); + health = 200; + xoff = random(1000); + yoff = random(1000); + dna = dna_; + // Gene 0 determines maxspeed and r + // The bigger the bloop, the slower it is + maxspeed = map(dna.genes[0], 0, 1, 15, 0); + r = map(dna.genes[0], 0, 1, 0, 50); + } + + void run() { + update(); + borders(); + display(); + } + + // A bloop can find food and eat it + void eat(Food f) { + ArrayList food = f.getFood(); + // Are we touching any food objects? + for (int i = food.size()-1; i >= 0; i--) { + PVector foodLocation = food.get(i); + float d = PVector.dist(location, foodLocation); + // If we are, juice up our strength! + if (d < r/2) { + health += 100; + food.remove(i); + } + } + } + + // At any moment there is a teeny, tiny chance a bloop will reproduce + Bloop reproduce() { + // asexual reproduction + if (random(1) < 0.0005) { + // Child is exact copy of single parent + DNA childDNA = dna.copy(); + // Child DNA can mutate + childDNA.mutate(0.01); + return new Bloop(location, childDNA); + } + else { + return null; + } + } + + // Method to update location + void update() { + // Simple movement based on perlin noise + float vx = map(noise(xoff),0,1,-maxspeed,maxspeed); + float vy = map(noise(yoff),0,1,-maxspeed,maxspeed); + PVector velocity = new PVector(vx,vy); + xoff += 0.01; + yoff += 0.01; + + location.add(velocity); + // Death always looming + health -= 0.2; + } + + // Wraparound + void borders() { + if (location.x < -r) location.x = width+r; + if (location.y < -r) location.y = height+r; + if (location.x > width+r) location.x = -r; + if (location.y > height+r) location.y = -r; + } + + // Method to display + void display() { + ellipseMode(CENTER); + stroke(0,health); + fill(0, health); + ellipse(location.x, location.y, r, r); + } + + // Death + boolean dead() { + if (health < 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/DNA.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/DNA.pde new file mode 100644 index 000000000..807e776a7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/DNA.pde @@ -0,0 +1,44 @@ +// Evolution EcoSystem +// Daniel Shiffman + +// Class to describe DNA +// Has more features for two parent mating (not used in this example) + +class DNA { + + // The genetic sequence + float[] genes; + + // Constructor (makes a random DNA) + DNA() { + // DNA is random floating point values between 0 and 1 (!!) + genes = new float[1]; + for (int i = 0; i < genes.length; i++) { + genes[i] = random(0,1); + } + } + + DNA(float[] newgenes) { + genes = newgenes; + } + + DNA copy() { + float[] newgenes = new float[genes.length]; + //arraycopy(genes,newgenes); + // JS mode not supporting arraycopy + for (int i = 0; i < newgenes.length; i++) { + newgenes[i] = genes[i]; + } + + return new DNA(newgenes); + } + + // Based on a mutation probability, picks a new random character in array spots + void mutate(float m) { + for (int i = 0; i < genes.length; i++) { + if (random(1) < m) { + genes[i] = random(0,1); + } + } + } +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/Food.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/Food.pde new file mode 100644 index 000000000..ea0cb59b1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/Food.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Evolution EcoSystem + +// A collection of food in the world + +class Food { + ArrayList food; + + Food(int num) { + // Start with some food + food = new ArrayList(); + for (int i = 0; i < num; i++) { + food.add(new PVector(random(width),random(height))); + } + } + + // Add some food at a location + void add(PVector l) { + food.add(l.get()); + } + + // Display the food + void run() { + for (PVector f : food) { + rectMode(CENTER); + stroke(0); + fill(175); + rect(f.x,f.y,8,8); + } + + // There's a small chance food will appear randomly + if (random(1) < 0.001) { + food.add(new PVector(random(width),random(height))); + } + } + + // Return the list of food + ArrayList getFood() { + return food; + } +} diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/NOC_9_05_EvolutionEcosystem.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/NOC_9_05_EvolutionEcosystem.pde new file mode 100644 index 000000000..f92a22e37 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/NOC_9_05_EvolutionEcosystem.pde @@ -0,0 +1,33 @@ +// Evolution EcoSystem +// Daniel Shiffman +// The Nature of Code + +// A World of creatures that eat food +// The more they eat, the longer they survive +// The longer they survive, the more likely they are to reproduce +// The bigger they are, the easier it is to land on food +// The bigger they are, the slower they are to find food +// When the creatures die, food is left behind + + +World world; + +void setup() { + size(800, 200); + // World starts with 20 creatures + // and 20 pieces of food + world = new World(20); + smooth(); +} + +void draw() { + background(255); + world.run(); +} + +// We can add a creature manually if we so desire +void mousePressed() { + world.born(mouseX,mouseY); +} + + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/World.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/World.pde new file mode 100644 index 000000000..c0789604d --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/World.pde @@ -0,0 +1,56 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Evolution EcoSystem + +// The World we live in +// Has bloops and food + +class World { + + ArrayList bloops; // An arraylist for all the creatures + Food food; + + // Constructor + World(int num) { + // Start with initial food and creatures + food = new Food(num); + bloops = new ArrayList(); // Initialize the arraylist + for (int i = 0; i < num; i++) { + PVector l = new PVector(random(width),random(height)); + DNA dna = new DNA(); + bloops.add(new Bloop(l,dna)); + } + } + + // Make a new creature + void born(float x, float y) { + PVector l = new PVector(x,y); + DNA dna = new DNA(); + bloops.add(new Bloop(l,dna)); + } + + // Run the world + void run() { + // Deal with food + food.run(); + + // Cycle through the ArrayList backwards b/c we are deleting + for (int i = bloops.size()-1; i >= 0; i--) { + // All bloops run and eat + Bloop b = bloops.get(i); + b.run(); + b.eat(food); + // If it's dead, kill it and make food + if (b.dead()) { + bloops.remove(i); + food.add(b.location); + } + // Perhaps this bloop would like to make a baby? + Bloop child = b.reproduce(); + if (child != null) bloops.add(child); + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/sketch.properties b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/sketch.properties new file mode 100644 index 000000000..28faa5897 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_05_EvolutionEcosystem/sketch.properties @@ -0,0 +1 @@ +mode=Standard diff --git a/java/examples/Books/Nature of Code/chp9_ga/bruteforce/bruteforce.pde b/java/examples/Books/Nature of Code/chp9_ga/bruteforce/bruteforce.pde new file mode 100644 index 000000000..d502a7151 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp9_ga/bruteforce/bruteforce.pde @@ -0,0 +1,18 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +int now = millis(); + +int passedTime = millis() - now; +int count = 0; +while (passedTime < 1000) { + for (int i = 0; i < 33; i++) { + float r = random(27); + } + count++; + passedTime = millis() - now; +} +println(count); + + diff --git a/java/examples/Books/Nature of Code/introduction/Exercise_I_10_NoiseLandscape/Exercise_I_10_NoiseLandscape.pde b/java/examples/Books/Nature of Code/introduction/Exercise_I_10_NoiseLandscape/Exercise_I_10_NoiseLandscape.pde new file mode 100644 index 000000000..aae2bf669 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Exercise_I_10_NoiseLandscape/Exercise_I_10_NoiseLandscape.pde @@ -0,0 +1,32 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Landscape with height values according to Perlin noise + +Landscape land; +float theta = 0.0; + +void setup() { + + size(800,200,P3D); + + // Create a landscape object + land = new Landscape(20,800,400); +} + +void draw() { + + // Ok, visualize the landscape space + background(255); + pushMatrix(); + translate(width/2,height/2+20,-160); + rotateX(PI/3); + rotateZ(theta); + land.render(); + popMatrix(); + + land.calculate(); + + theta += 0.0025; +} diff --git a/java/examples/Books/Nature of Code/introduction/Exercise_I_10_NoiseLandscape/Landscape.pde b/java/examples/Books/Nature of Code/introduction/Exercise_I_10_NoiseLandscape/Landscape.pde new file mode 100644 index 000000000..661e5502d --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Exercise_I_10_NoiseLandscape/Landscape.pde @@ -0,0 +1,67 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// "Landscape" example + +class Landscape { + + int scl; // size of each cell + int w, h; // width and height of thingie + int rows, cols; // number of rows and columns + float zoff = 0.0; // perlin noise argument + float[][] z; // using an array to store all the height values + + Landscape(int scl_, int w_, int h_) { + scl = scl_; + w = w_; + h = h_; + cols = w/scl; + rows = h/scl; + z = new float[cols][rows]; + } + + + // Calculate height values (based off a neural netork) + void calculate() { + float xoff = 0; + for (int i = 0; i < cols; i++) + { + float yoff = 0; + for (int j = 0; j < rows; j++) + { + z[i][j] = map(noise(xoff, yoff,zoff), 0, 1, -120, 120); + yoff += 0.1; + } + xoff += 0.1; + } + zoff+=0.01; + } + + // Render landscape as grid of quads + void render() { + // Every cell is an individual quad + // (could use quad_strip here, but produces funny results, investigate this) + for (int x = 0; x < z.length-1; x++) + { + for (int y = 0; y < z[x].length-1; y++) + { + // one quad at a time + // each quad's color is determined by the height value at each vertex + // (clean this part up) + stroke(0); + fill(100, 100); + pushMatrix(); + beginShape(QUADS); + translate(x*scl-w/2, y*scl-h/2, 0); + vertex(0, 0, z[x][y]); + vertex(scl, 0, z[x+1][y]); + vertex(scl, scl, z[x+1][y+1]); + vertex(0, scl, z[x][y+1]); + endShape(); + popMatrix(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/Exercise_I_1_WalkerTendsToDownRight/Exercise_I_1_WalkerTendsToDownRight.pde b/java/examples/Books/Nature of Code/introduction/Exercise_I_1_WalkerTendsToDownRight/Exercise_I_1_WalkerTendsToDownRight.pde new file mode 100644 index 000000000..e1c34a553 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Exercise_I_1_WalkerTendsToDownRight/Exercise_I_1_WalkerTendsToDownRight.pde @@ -0,0 +1,20 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(800,200); + // Create a walker object + w = new Walker(); + background(255); +} + +void draw() { + // Run the walker object + w.step(); + w.render(); +} + + diff --git a/java/examples/Books/Nature of Code/introduction/Exercise_I_1_WalkerTendsToDownRight/Walker.pde b/java/examples/Books/Nature of Code/introduction/Exercise_I_1_WalkerTendsToDownRight/Walker.pde new file mode 100644 index 000000000..42a020bce --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Exercise_I_1_WalkerTendsToDownRight/Walker.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker object! + +class Walker { + int x,y; + + Walker() { + x = width/2; + y = height/2; + } + + void render() { + stroke(0); + strokeWeight(2); + point(x,y); + } + + // Randomly move up, down, left, right, or stay in one place + void step() { + + float r = random(1); + // A 40% of moving to the right! + if (r < 0.4) { + x++; + } else if (r < 0.5) { + x--; + } else if (r < 0.9) { + y++; + } else { + y--; + } + + x = constrain(x,0,width-1); + y = constrain(y,0,height-1); + } +} diff --git a/java/examples/Books/Nature of Code/introduction/Exercise_I_9_Noise3D/Exercise_I_9_Noise3D.pde b/java/examples/Books/Nature of Code/introduction/Exercise_I_9_Noise3D/Exercise_I_9_Noise3D.pde new file mode 100644 index 000000000..3b839de9c --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Exercise_I_9_Noise3D/Exercise_I_9_Noise3D.pde @@ -0,0 +1,47 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float increment = 0.01; +// The noise function's 3rd argument, a global variable that increments once per cycle +float zoff = 0.0; +// We will increment zoff differently than xoff and yoff +float zincrement = 0.02; + +void setup() { + size(200,200); +} + +void draw() { + background(0); + + // Optional: adjust noise detail here + // noiseDetail(8,0.65f); + + loadPixels(); + + float xoff = 0.0; // Start xoff at 0 + + // For every x,y coordinate in a 2D space, calculate a noise value and produce a brightness value + for (int x = 0; x < width; x++) { + xoff += increment; // Increment xoff + float yoff = 0.0; // For every xoff, start yoff at 0 + for (int y = 0; y < height; y++) { + yoff += increment; // Increment yoff + + // Calculate noise and scale by 255 + float bright = noise(xoff,yoff,zoff)*255; + + // Try using this line instead + //float bright = random(0,255); + + // Set each pixel onscreen to a grayscale value + pixels[x+y*width] = color(bright,bright,bright); + } + } + updatePixels(); + + zoff += zincrement; // Increment zoff + + +} diff --git a/java/examples/Books/Nature of Code/introduction/Figure_I_2_BellCurve/Figure_I_2_BellCurve.pde b/java/examples/Books/Nature of Code/introduction/Figure_I_2_BellCurve/Figure_I_2_BellCurve.pde new file mode 100644 index 000000000..af69b84fd --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Figure_I_2_BellCurve/Figure_I_2_BellCurve.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float[] heights; + +void setup() { + size(400, 200); + smooth(); +} + +void draw() { + background(255); + float e = 2.71828183; //"e", see http://mathforum.org/dr.math/faq/faq.e.html for more info + float[] heights = new float[width]; //use an array to store all the "y" values + float m = 0; //default mean of 0 + float sd = map(mouseX,0,width,0.4,2); //standard deviation based on mouseX + for (int i = 0; i < heights.length; i++) { + float xcoord = map(i,0,width,-3,3); + float sq2pi = sqrt(2*PI); //square root of 2 * PI + float xmsq = -1*(xcoord-m)*(xcoord-m); //-(x - mu)^2 + float sdsq = sd*sd; //variance (standard deviation squared) + heights[i] = (1 / (sd * sq2pi)) * (pow(e, (xmsq/sdsq))); //P(x) function + } + + // a little for loop that draws a line between each point on the graph + stroke(0); + strokeWeight(2); + noFill(); + beginShape(); + for (int i = 0; i < heights.length-1; i++) { + float x = i; + float y = map(heights[i], 0, 1, height-2, 2); + vertex(x, y); + } + endShape(); +} + diff --git a/java/examples/Books/Nature of Code/introduction/Figure_I_5_Noise1DGraph/Figure_I_5_Noise1DGraph.pde b/java/examples/Books/Nature of Code/introduction/Figure_I_5_Noise1DGraph/Figure_I_5_Noise1DGraph.pde new file mode 100644 index 000000000..1d3dc21d8 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Figure_I_5_Noise1DGraph/Figure_I_5_Noise1DGraph.pde @@ -0,0 +1,28 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// TIME +float t = 0.0; + +void setup() { + size(400,200); + smooth(); +} + + +void draw() { + background(255); + float xoff = t; + noFill(); + stroke(0); + strokeWeight(2); + beginShape(); + for (int i = 0; i < width; i++) { + float y = noise(xoff)*height; + xoff += 0.01; + vertex(i,y); + } + endShape(); + t+= 0.01; +} diff --git a/java/examples/Books/Nature of Code/introduction/Figure_I_6_RandomGraph/Figure_I_6_RandomGraph.pde b/java/examples/Books/Nature of Code/introduction/Figure_I_6_RandomGraph/Figure_I_6_RandomGraph.pde new file mode 100644 index 000000000..fad4fe2d7 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Figure_I_6_RandomGraph/Figure_I_6_RandomGraph.pde @@ -0,0 +1,23 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +void setup() { + size(400,200); + smooth(); +} + + +void draw() { + background(255); + noFill(); + stroke(0); + strokeWeight(2); + beginShape(); + for (int i = 0; i < width; i++) { + float y = random(height); + vertex(i,y); + } + endShape(); + noLoop(); +} diff --git a/java/examples/Books/Nature of Code/introduction/Gaussian2/Gaussian2.pde b/java/examples/Books/Nature of Code/introduction/Gaussian2/Gaussian2.pde new file mode 100644 index 000000000..50eb81f69 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/Gaussian2/Gaussian2.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Random generator; + +void setup() { + size(200,200); + background(0); + generator = new Random(); +} + +void draw() { + //create an alpha blended background + fill(0,1); + rect(0,0,width,height); + + //get 3 gaussian random numbers w/ mean of 0 and standard deviation of 1.0 + float r = (float) generator.nextGaussian(); + float g = (float) generator.nextGaussian(); + float b = (float) generator.nextGaussian(); + + //define standard deviation and mean + float sd = 100; float mean = 100; + //scale by standard deviation and mean + //also constrain to between (0,255) since we are dealing with color + r = constrain((r * sd) + mean,0,255); + + //repeat for g & b + sd = 20; mean = 200; + g = constrain((g * sd) + mean,0,255); + sd = 50; mean = 0; + b = constrain((b * sd) + mean,0,255); + + //get more gaussian numbers, this time for location + float xloc = (float) generator.nextGaussian(); + float yloc = (float) generator.nextGaussian(); + sd = width/10; + mean = width/2; + xloc = ( xloc * sd ) + mean; + yloc = ( yloc * sd ) + mean; + + //draw an ellipse with gaussian generated color and location + noStroke(); + fill(r,g,b); + ellipse(xloc,yloc,8,8); +} + diff --git a/java/examples/Books/Nature of Code/introduction/MonteCarloDistribution/MonteCarloDistribution.pde b/java/examples/Books/Nature of Code/introduction/MonteCarloDistribution/MonteCarloDistribution.pde new file mode 100644 index 000000000..ea68bef4b --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/MonteCarloDistribution/MonteCarloDistribution.pde @@ -0,0 +1,65 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float[] vals; // Array to count how often a random # is picked +float[] norms; // Normalized version of above + +void setup() { + size(200, 200); + vals = new float[width]; + norms = new float[width]; +} + +void draw() { + background(100); + + // Pick a random number between 0 and 1 based on custom probability function + float n = montecarlo(); + + // What spot in the array did we pick + int index = int(n*width); + vals[index]++; + stroke(255); + + boolean normalization = false; + float maxy = 0.0; + + // Draw graph based on values in norms array + // If a value is greater than the height, set normalization to true + for (int x = 0; x < vals.length; x++) { + line(x, height, x, height-norms[x]); + if (vals[x] > height) normalization = true; + if (vals[x] > maxy) maxy = vals[x]; + } + + // If normalization is true then normalize to height + // Otherwise, just copy the info + for (int x = 0; x < vals.length; x++) { + if (normalization) norms[x] = (vals[x] / maxy) * (height); + else norms[x] = vals[x]; + } +} + +// An algorithm for picking a random number based on monte carlo method +// Here probability is determined by formula y = x +float montecarlo() { + // Have we found one yet + boolean foundone = false; + int hack = 0; // let's count just so we don't get stuck in an infinite loop by accident + while (!foundone && hack < 10000) { + // Pick two random numbers + float r1 = (float) random(1); + float r2 = (float) random(1); + float y = r1*r1; // y = x*x (change for different results) + // If r2 is valid, we'll use this one + if (r2 < y) { + foundone = true; + return r1; + } + hack++; + } + // Hack in case we run into a problem (need to improve this) + return 0; +} + diff --git a/java/examples/Books/Nature of Code/introduction/MultipleProbability/MultipleProbability.pde b/java/examples/Books/Nature of Code/introduction/MultipleProbability/MultipleProbability.pde new file mode 100644 index 000000000..21ac11af4 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/MultipleProbability/MultipleProbability.pde @@ -0,0 +1,38 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +int x,y; + +void setup() { + size(200,200); + background(0); + smooth(); +} + +void draw() { + //create an alpha blended background + fill(0,1); + rect(0,0,width,height); + + //probabilities for 3 different cases (these need to add up to 100% since something always occurs here!) + float p1 = 0.05; // 5% chance of pure white occurring + float p2 = 0.80 + p1; // 80% chance of gray occuring + //float p3 = 1.0 - p2 ; // 15% chance of black (we don't actually need this line since it is + // by definit n, the "in all other cases" part of our else + float num = random(1); // pick a random number between 0 and 1 + if (num height) normalization = true; + if(vals[x] > maxy) maxy = vals[x]; + } + for (int x = 0; x < vals.length; x++) { + if (normalization) norms[x] = (vals[x] / maxy) * (height); + else norms[x] = vals[x]; + } +} diff --git a/java/examples/Books/Nature of Code/introduction/NoiseWalkAcceleration/NoiseWalkAcceleration.pde b/java/examples/Books/Nature of Code/introduction/NoiseWalkAcceleration/NoiseWalkAcceleration.pde new file mode 100644 index 000000000..0f516cb1a --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/NoiseWalkAcceleration/NoiseWalkAcceleration.pde @@ -0,0 +1,22 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(640,360); + // Create a walker object + w = new Walker(); + +} + +void draw() { + background(255); + // Run the walker object + w.walk(); + w.display(); +} + + + diff --git a/java/examples/Books/Nature of Code/introduction/NoiseWalkAcceleration/Walker.pde b/java/examples/Books/Nature of Code/introduction/NoiseWalkAcceleration/Walker.pde new file mode 100644 index 000000000..ebedbbd66 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/NoiseWalkAcceleration/Walker.pde @@ -0,0 +1,65 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker class! + +class Walker { + PVector location; + PVector velocity; + PVector acceleration; + + ArrayList history; + + PVector noff; + + + Walker() { + location = new PVector(width/2, height/2); + history = new ArrayList(); + noff = new PVector(random(1000), random(1000)); + velocity = new PVector(); + acceleration = new PVector(); + } + + void display() { + stroke(0); + fill(175); + rectMode(CENTER); + rect(location.x, location.y, 16, 16); + + beginShape(); + stroke(0); + noFill(); + for (PVector v: history) { + vertex(v.x, v.y); + } + endShape(); + } + + // Randomly move up, down, left, right, or stay in one place + void walk() { + + + acceleration.x = map(noise(noff.x), 0, 1, -1, 1); + acceleration.y = map(noise(noff.y), 0, 1, -1, 1); + acceleration.mult(0.1); + + noff.add(0.01, 0.01, 0); + + velocity.add(acceleration); + velocity.limit(1); + location.add(velocity); + + + history.add(location.get()); + if (history.size() > 1000) { + history.remove(0); + } + + // Stay on the screen + location.x = constrain(location.x, 0, width-1); + location.y = constrain(location.y, 0, height-1); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/NoiseWalkVelocity/NoiseWalkVelocity.pde b/java/examples/Books/Nature of Code/introduction/NoiseWalkVelocity/NoiseWalkVelocity.pde new file mode 100644 index 000000000..aaca5448a --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/NoiseWalkVelocity/NoiseWalkVelocity.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(400,400); + frameRate(30); + + // Create a walker object + w = new Walker(); + +} + +void draw() { + background(255); + // Run the walker object + w.walk(); + w.display(); +} + + + diff --git a/java/examples/Books/Nature of Code/introduction/NoiseWalkVelocity/Walker.pde b/java/examples/Books/Nature of Code/introduction/NoiseWalkVelocity/Walker.pde new file mode 100644 index 000000000..2749b5095 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/NoiseWalkVelocity/Walker.pde @@ -0,0 +1,60 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker class! + +class Walker { + PVector location; + PVector velocity; + + ArrayList history; + + PVector noff; + + + Walker() { + location = new PVector(width/2, height/2); + history = new ArrayList(); + noff = new PVector(random(1000), random(1000)); + velocity = new PVector(); + } + + void display() { + stroke(0); + fill(175); + rectMode(CENTER); + rect(location.x, location.y, 16, 16); + + beginShape(); + stroke(0); + noFill(); + for (PVector v: history) { + vertex(v.x, v.y); + } + endShape(); + } + + // Randomly move up, down, left, right, or stay in one place + void walk() { + + + velocity.x = map(noise(noff.x), 0, 1, -1, 1); + velocity.y = map(noise(noff.y), 0, 1, -1, 1); + velocity.mult(5); + + noff.add(0.01, 0.01, 0); + + location.add(velocity); + + history.add(location.get()); + if (history.size() > 1000) { + history.remove(0); + } + + // Stay on the screen + location.x = constrain(location.x, 0, width-1); + location.y = constrain(location.y, 0, height-1); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalk/RandomWalk.pde b/java/examples/Books/Nature of Code/introduction/RandomWalk/RandomWalk.pde new file mode 100644 index 000000000..7832e2b77 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalk/RandomWalk.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(400,400); + frameRate(30); + + // Create a walker object + w = new Walker(); + +} + +void draw() { + background(255); + // Run the walker object + w.walk(); + w.render(); +} + + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalk/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalk/Walker.pde new file mode 100644 index 000000000..55d0dc60a --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalk/Walker.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker class! + +class Walker { + float x, y; + + Walker() { + x = width/2; + y = height/2; + } + + void render() { + stroke(0); + fill(175); + rectMode(CENTER); + rect(x, y, 40, 40); + } + + // Randomly move up, down, left, right, or stay in one place + void walk() { + float vx = random(-2, 2); + float vy = random(-2, 2); + x += vx; + y += vy; + + // Stay on the screen + x = constrain(x, 0, width-1); + y = constrain(y, 0, height-1); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkLevy/RandomWalkLevy.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkLevy/RandomWalkLevy.pde new file mode 100644 index 000000000..32a0d4a54 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkLevy/RandomWalkLevy.pde @@ -0,0 +1,20 @@ +// Daniel Shiffman +// The Nature of Code +// http://natureofcode.com + +Walker w; + +void setup() { + size(640,480); + // Create a walker object + w = new Walker(); + background(0); +} + +void draw() { + // Run the walker object + w.step(); + w.render(); +} + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkLevy/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkLevy/Walker.pde new file mode 100644 index 000000000..fa48396e2 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkLevy/Walker.pde @@ -0,0 +1,54 @@ +// Daniel Shiffman +// The Nature of Code +// http://natureofcode.com + +// A random walker object! + +class Walker { + float x, y; + + float prevX, prevY; + + Walker() { + x = width/2; + y = height/2; + } + + void render() { + stroke(255); + line(prevX,prevY,x, y); + } + + // Randomly move according to floating point values + void step() { + prevX = x; + prevY = y; + + float stepx = random(-1, 1); + float stepy = random(-1, 1); + + float stepsize = montecarlo()*50; + stepx *= stepsize; + stepy *= stepsize; + + x += stepx; + y += stepy; + x = constrain(x, 0, width-1); + y = constrain(y, 0, height-1); + } +} + + +float montecarlo() { + while (true) { + + float r1 = random(1); + float probability = pow(1.0 - r1,8); + + float r2 = random(1); + if (r2 < probability) { + return r1; + } + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkNoise/RandomWalkNoise.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkNoise/RandomWalkNoise.pde new file mode 100644 index 000000000..cb1143921 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkNoise/RandomWalkNoise.pde @@ -0,0 +1,19 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(640,360); + w = new Walker(); + background(0); +} + +void draw() { + // Run the walker object + w.step(); + w.render(); +} + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkNoise/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkNoise/Walker.pde new file mode 100644 index 000000000..be8f1b716 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkNoise/Walker.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker object! + +class Walker { + float x, y; + float tx, ty; + + float prevX, prevY; + + Walker() { + tx = 0; + ty = 10000; + x = map(noise(tx), 0, 1, 0, width); + y = map(noise(ty), 0, 1, 0, height); + } + + void render() { + stroke(255); + line(prevX, prevY, x, y); + } + + // Randomly move according to floating point values + void step() { + + prevX = x; + prevY = y; + + x = map(noise(tx), 0, 1, 0, width); + y = map(noise(ty), 0, 1, 0, height); + + tx += 0.01; + ty += 0.01; + + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkPVector/RandomWalkPVector.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkPVector/RandomWalkPVector.pde new file mode 100644 index 000000000..7832e2b77 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkPVector/RandomWalkPVector.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(400,400); + frameRate(30); + + // Create a walker object + w = new Walker(); + +} + +void draw() { + background(255); + // Run the walker object + w.walk(); + w.render(); +} + + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkPVector/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkPVector/Walker.pde new file mode 100644 index 000000000..27e4f6a22 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkPVector/Walker.pde @@ -0,0 +1,31 @@ +// Daniel Shiffman +// The Nature of Code +// http://natureofcode.com + +// A random walker class! + +class Walker { + PVector loc; + + Walker() { + loc = new PVector(width/2,height/2); + } + + void render() { + stroke(0); + fill(175); + rectMode(CENTER); + rect(loc.x,loc.y,40,40); + } + + // Randomly move up, down, left, right, or stay in one place + void walk() { + PVector vel = new PVector(random(-2,2),random(-2,2)); + loc.add(vel); + + // Stay on the screen + loc.x = constrain(loc.x,0,width-1); + loc.y = constrain(loc.y,0,height-1); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional2/RandomWalkTraditional2.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional2/RandomWalkTraditional2.pde new file mode 100644 index 000000000..9cb6af8c6 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional2/RandomWalkTraditional2.pde @@ -0,0 +1,20 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(200,200); + // Create a walker object + w = new Walker(); + background(0); +} + +void draw() { + // Run the walker object + w.step(); + w.render(); +} + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional2/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional2/Walker.pde new file mode 100644 index 000000000..856cf0bb5 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional2/Walker.pde @@ -0,0 +1,29 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker object! + +class Walker { + int x,y; + + Walker() { + x = width/2; + y = height/2; + } + + void render() { + stroke(255); + point(x,y); + } + + // Randomly move to any neighboring pixel (or stay in the same spot) + void step() { + int stepx = int(random(3))-1; + int stepy = int(random(3))-1; + x += stepx; + y += stepy; + x = constrain(x,0,width-1); + y = constrain(y,0,height-1); + } +} diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional3/RandomWalkTraditional3.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional3/RandomWalkTraditional3.pde new file mode 100644 index 000000000..9cb6af8c6 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional3/RandomWalkTraditional3.pde @@ -0,0 +1,20 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(200,200); + // Create a walker object + w = new Walker(); + background(0); +} + +void draw() { + // Run the walker object + w.step(); + w.render(); +} + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional3/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional3/Walker.pde new file mode 100644 index 000000000..fdd0271d0 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTraditional3/Walker.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker object! + +class Walker { + float x, y; + + Walker() { + x = width/2; + y = height/2; + } + + void render() { + stroke(255); + point(x, y); + } + + // Randomly move according to floating point values + void step() { + float stepx = random(-1, 1); + float stepy = random(-1, 1); + x += stepx; + y += stepy; + x = constrain(x, 0, width-1); + y = constrain(y, 0, height-1); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTrail/RandomWalkTrail.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTrail/RandomWalkTrail.pde new file mode 100644 index 000000000..aaca5448a --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTrail/RandomWalkTrail.pde @@ -0,0 +1,24 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(400,400); + frameRate(30); + + // Create a walker object + w = new Walker(); + +} + +void draw() { + background(255); + // Run the walker object + w.walk(); + w.display(); +} + + + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTrail/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTrail/Walker.pde new file mode 100644 index 000000000..d0dddfa8b --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTrail/Walker.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker class! + +class Walker { + PVector location; + + ArrayList history; + + + Walker() { + location = new PVector(width/2, height/2); + history = new ArrayList(); + } + + void display() { + stroke(0); + fill(175); + rectMode(CENTER); + rect(location.x, location.y, 16, 16); + + beginShape(); + stroke(0); + noFill(); + for (PVector v: history) { + vertex(v.x, v.y); + } + endShape(); + } + + // Randomly move up, down, left, right, or stay in one place + void walk() { + PVector vel = new PVector(random(-2, 2), random(-2, 2)); + location.add(vel); + + // Stay on the screen + location.x = constrain(location.x, 0, width-1); + location.y = constrain(location.y, 0, height-1); + + + history.add(location.get()); + if (history.size() > 1000) { + history.remove(0); + } + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/SimpleProbablility/SimpleProbablility.pde b/java/examples/Books/Nature of Code/introduction/SimpleProbablility/SimpleProbablility.pde new file mode 100644 index 000000000..d3d5511be --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/SimpleProbablility/SimpleProbablility.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +int x,y; + +void setup() { + size(200,200); + background(0); + smooth(); +} + +void draw() { + //create an alpha blended background + fill(0,1); + rect(0,0,width,height); + + //calculate a probability between 0 and 100% based on mouseX location + float prob = (mouseX / (float) width); + + //get a random floating point value between 0 and 1 + float r = random(1); + + //test the random value against the probability and trigger an event + if (r < prob) { + noStroke(); + fill(255); + ellipse(x,y,10,10); + } + + // X and Y walk through a grid + x = (x + 10) % width; + if (x == 0) y = (y + 10) % width; +}