mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
updating nature of code examples for noc repo
This commit is contained in:
+2
-2
@@ -7,7 +7,7 @@
|
||||
Network network;
|
||||
|
||||
void setup() {
|
||||
size(750,200);
|
||||
size(640,360);
|
||||
// Create the Network object
|
||||
network = new Network(width/2, height/2);
|
||||
|
||||
@@ -17,7 +17,7 @@ void setup() {
|
||||
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 x = map(i, 0, layers, -250, 300);
|
||||
float y = map(j, 0, inputs-1, -75, 75);
|
||||
Neuron n = new Neuron(x, y);
|
||||
if (i > 0) {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ float f(float x) {
|
||||
}
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
|
||||
// The perceptron has 3 inputs -- x, y, and bias
|
||||
// Second value is "Learning Constant"
|
||||
|
||||
+7
-6
@@ -11,7 +11,7 @@ PVector desired;
|
||||
ArrayList<PVector> targets;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
// The Vehicle's desired location
|
||||
desired = new PVector(width/2,height/2);
|
||||
|
||||
@@ -35,19 +35,20 @@ void makeTargets() {
|
||||
void draw() {
|
||||
background(255);
|
||||
|
||||
// Draw a rectangle to show the Vehicle's goal
|
||||
rectMode(CENTER);
|
||||
// Draw a circle to show the Vehicle's goal
|
||||
stroke(0);
|
||||
strokeWeight(2);
|
||||
fill(0, 100);
|
||||
rect(desired.x, desired.y, 36, 36);
|
||||
ellipse(desired.x, desired.y, 36, 36);
|
||||
|
||||
// Draw the targets
|
||||
for (PVector target : targets) {
|
||||
fill(0, 100);
|
||||
noFill();
|
||||
stroke(0);
|
||||
strokeWeight(2);
|
||||
ellipse(target.x, target.y, 30, 30);
|
||||
ellipse(target.x, target.y, 16, 16);
|
||||
line(target.x,target.y-16,target.x,target.y+16);
|
||||
line(target.x-16,target.y,target.x+16,target.y);
|
||||
}
|
||||
|
||||
// Update the Vehicle
|
||||
|
||||
+3
-3
@@ -7,15 +7,15 @@
|
||||
Network network;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
// Create the Network object
|
||||
network = new Network(width/2,height/2);
|
||||
|
||||
// Create a bunch of Neurons
|
||||
Neuron a = new Neuron(-300,0);
|
||||
Neuron a = new Neuron(-200,0);
|
||||
Neuron b = new Neuron(0,75);
|
||||
Neuron c = new Neuron(0,-75);
|
||||
Neuron d = new Neuron(300,0);
|
||||
Neuron d = new Neuron(200,0);
|
||||
|
||||
// Connect them
|
||||
network.connect(a,b);
|
||||
|
||||
+5
-5
@@ -7,17 +7,17 @@
|
||||
Network network;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
// 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 a = new Neuron(-275, 0);
|
||||
Neuron b = new Neuron(-150, 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);
|
||||
Neuron e = new Neuron(150, 0);
|
||||
Neuron f = new Neuron(275, 0);
|
||||
|
||||
// Connect them
|
||||
network.connect(a, b,1);
|
||||
|
||||
@@ -11,7 +11,7 @@ class Mover {
|
||||
|
||||
Mover(float m, float x, float y) {
|
||||
mass = m;
|
||||
location = new PVector(random(width), random(height));
|
||||
location = new PVector(x, y);
|
||||
velocity = new PVector(1, 0);
|
||||
acceleration = new PVector(0, 0);
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,8 +30,8 @@ class ParticleSystem {
|
||||
}
|
||||
}
|
||||
|
||||
void addParticle(Particle p) {
|
||||
particles.add(p);
|
||||
void addParticle() {
|
||||
particles.add(new Particle(origin));
|
||||
}
|
||||
|
||||
// A method to test if the particle system still has particles
|
||||
|
||||
-1
@@ -9,7 +9,6 @@ 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;
|
||||
|
||||
@@ -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<Vehicle> vehicles;
|
||||
|
||||
void setup() {
|
||||
size(640,360);
|
||||
// We are now making random vehicles and storing them in an ArrayList
|
||||
vehicles = new ArrayList<Vehicle>();
|
||||
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.align(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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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 = PVector.random2D();
|
||||
velocity.mult(random(1,4));
|
||||
}
|
||||
|
||||
void applyForce(PVector force) {
|
||||
// We could add mass here if we want A = F / M
|
||||
acceleration.add(force);
|
||||
}
|
||||
|
||||
// Alignment
|
||||
// For every nearby boid in the system, calculate the average velocity
|
||||
void align (ArrayList<Vehicle> boids) {
|
||||
float neighbordist = 30;
|
||||
PVector sum = new PVector(0, 0);
|
||||
int count = 0;
|
||||
for (Vehicle other : vehicles) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+1
-2
@@ -11,9 +11,8 @@ Vehicle wanderer;
|
||||
boolean debug = true;
|
||||
|
||||
void setup() {
|
||||
size(740,200);
|
||||
size(640,360);
|
||||
wanderer = new Vehicle(width/2,height/2);
|
||||
smooth();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// 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<Vehicle> vehicles;
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
// Make a new flow field with "resolution" of 16
|
||||
flowfield = new FlowField(20);
|
||||
vehicles = new ArrayList<Vehicle>();
|
||||
// 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);
|
||||
flowfield.update();
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// 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
|
||||
|
||||
float zoff = 0.0; // 3rd dimension of noise
|
||||
|
||||
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];
|
||||
update();
|
||||
}
|
||||
|
||||
void update() {
|
||||
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,zoff),0,1,0,TWO_PI);
|
||||
// Make a vector from an angle
|
||||
field[i][j] = PVector.fromAngle(theta);
|
||||
yoff += 0.1;
|
||||
}
|
||||
xoff += 0.1;
|
||||
}
|
||||
// Animate by changing 3rd dimension of noise every frame
|
||||
zoff += 0.01;
|
||||
}
|
||||
|
||||
// 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,150);
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+87
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -6,8 +6,7 @@
|
||||
// Using the dot product to compute the angle between two vectors
|
||||
|
||||
void setup() {
|
||||
size(383, 200);
|
||||
smooth();
|
||||
size(640, 360);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ Path path;
|
||||
ArrayList<Vehicle> vehicles;
|
||||
|
||||
void setup() {
|
||||
size(720,200);
|
||||
size(640,360);
|
||||
// Call a function to generate new Path object
|
||||
newPath();
|
||||
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
// Flocking
|
||||
// Daniel Shiffman <http://www.shiffman.net>
|
||||
// The Nature of Code, Spring 2009
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
color col;
|
||||
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 = 5.0;
|
||||
maxspeed = 3;
|
||||
maxforce = 0.05;
|
||||
|
||||
col = color(175);
|
||||
}
|
||||
|
||||
void run(ArrayList<Boid> boids) {
|
||||
//flock(boids);
|
||||
update();
|
||||
borders();
|
||||
render();
|
||||
}
|
||||
|
||||
void applyForce(PVector force) {
|
||||
// We could add mass here if we want A = F / M
|
||||
acceleration.add(force);
|
||||
}
|
||||
|
||||
// We accumulate a new acceleration each time based on three rules
|
||||
void flock(ArrayList<Boid> boids) {
|
||||
PVector sep = separate(boids); // Separation
|
||||
PVector ali = align(boids); // Alignment
|
||||
PVector coh = cohesion(boids); // Cohesion
|
||||
|
||||
// Not for every boid yet
|
||||
// PVector view = view(boids); // view
|
||||
|
||||
// Arbitrarily weight these forces
|
||||
sep.mult(1.5);
|
||||
ali.mult(1.0);
|
||||
coh.mult(1.0);
|
||||
|
||||
// Not for every boid yet
|
||||
// view.mult(1.0);
|
||||
|
||||
// Add the force vectors to acceleration
|
||||
applyForce(sep);
|
||||
applyForce(ali);
|
||||
applyForce(coh);
|
||||
|
||||
// Not for every boid yet
|
||||
// applyForce(view);
|
||||
}
|
||||
|
||||
// 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.heading() + radians(90);
|
||||
fill(col);
|
||||
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<Boid> boids) {
|
||||
float desiredseparation = 25.0f;
|
||||
PVector steer = new PVector(0, 0, 0);
|
||||
int count = 0;
|
||||
// For every boid in the system, check if it's too close
|
||||
for (Boid other : boids) {
|
||||
float d = PVector.dist(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<Boid> 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<Boid> 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);
|
||||
}
|
||||
}
|
||||
|
||||
// View
|
||||
// move laterally away from any boid that blocks the view
|
||||
// Right now we are just drawing the view and highlighting boids
|
||||
PVector view (ArrayList<Boid> boids) {
|
||||
|
||||
// How far can it see?
|
||||
float sightDistance = 100;
|
||||
float periphery = PI/4;
|
||||
|
||||
for (Boid other : boids) {
|
||||
// A vector that points to another boid and that angle
|
||||
PVector comparison = PVector.sub(other.location, location);
|
||||
|
||||
// How far is it
|
||||
float d = PVector.dist(location, other.location);
|
||||
|
||||
// What is the angle between the other boid and this one's current direction
|
||||
float diff = PVector.angleBetween(comparison, velocity);
|
||||
|
||||
// If it's within the periphery and close enough to see it
|
||||
if (diff < periphery && d > 0 && d < sightDistance) {
|
||||
// Just change its color
|
||||
other.highlight();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Debug Drawing
|
||||
float currentHeading = velocity.heading();
|
||||
pushMatrix();
|
||||
translate(location.x, location.y);
|
||||
rotate(currentHeading);
|
||||
fill(0, 100);
|
||||
arc(0, 0, sightDistance*2, sightDistance*2, -periphery, periphery);
|
||||
popMatrix();
|
||||
|
||||
return new PVector();
|
||||
}
|
||||
|
||||
void highlight() {
|
||||
col = color(255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// The Nature of Code
|
||||
// Daniel Shiffman
|
||||
// http://natureofcode.com
|
||||
|
||||
// Exercise 6.17: Implement Flake's "View" rule
|
||||
|
||||
// This answer doesn't implement the rule, but rather demonstrates how a boid can
|
||||
// detect what is "in front" of it based on peripheral vision
|
||||
|
||||
Flock flock;
|
||||
|
||||
void setup() {
|
||||
size(640,360);
|
||||
flock = new Flock();
|
||||
// Add an initial set of boids into the system
|
||||
for (int i = 0; i < 25; i++) {
|
||||
Boid b = new Boid(width/2+random(0,75),height/2+random(0,75));
|
||||
flock.addBoid(b);
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(255);
|
||||
|
||||
flock.run();
|
||||
}
|
||||
|
||||
// Add a new boid into the System
|
||||
void mouseDragged() {
|
||||
flock.addBoid(new Boid(mouseX,mouseY));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Flocking
|
||||
// Daniel Shiffman <http://www.shiffman.net>
|
||||
// The Nature of Code, Spring 2011
|
||||
|
||||
// Flock class
|
||||
// Does very little, simply manages the ArrayList of all the boids
|
||||
|
||||
class Flock {
|
||||
ArrayList<Boid> boids; // An ArrayList for all the boids
|
||||
|
||||
Flock() {
|
||||
boids = new ArrayList<Boid>(); // Initialize the ArrayList
|
||||
}
|
||||
|
||||
void run() {
|
||||
for (Boid b : boids) {
|
||||
b.col = color(175);
|
||||
}
|
||||
|
||||
Boid b1 = boids.get(0);
|
||||
b1.col = color(0, 0, 255);
|
||||
b1.view(boids);
|
||||
|
||||
for (Boid b : boids) {
|
||||
b.flock(boids); // Passing the entire list of boids to each boid individually
|
||||
}
|
||||
|
||||
for (Boid b : boids) {
|
||||
b.run(boids); // Passing the entire list of boids to each boid individually
|
||||
}
|
||||
}
|
||||
|
||||
void addBoid(Boid b) {
|
||||
boids.add(b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// 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
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
|
||||
int x = i*resolution;
|
||||
int y = j*resolution;
|
||||
int c = img.pixels[x + y * img.width];
|
||||
|
||||
// Map brightness to an angle
|
||||
float theta = 0;//map(brightness(c),0,255,0,PI/2);
|
||||
// Polar to cartesian coordinate transformation to get x and y components of the vector
|
||||
field[i][j] = PVector.fromAngle(theta);
|
||||
|
||||
// Map magnitude to an angle (how fast is the desired velocity in the flow field)
|
||||
float m = map(brightness(c),0,255,0,1);
|
||||
field[i][j].mult(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
strokeWeight(2);
|
||||
stroke(255,0,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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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;
|
||||
|
||||
PImage img;
|
||||
|
||||
// Flowfield object
|
||||
FlowField flowfield;
|
||||
// An ArrayList of vehicles
|
||||
ArrayList<Vehicle> vehicles;
|
||||
|
||||
void setup() {
|
||||
size(600, 568);
|
||||
img = loadImage("sil.jpg");
|
||||
// Make a new flow field with "resolution" of 16
|
||||
flowfield = new FlowField(20);
|
||||
vehicles = new ArrayList<Vehicle>();
|
||||
// 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);
|
||||
image(img,0,0);
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ class Vehicle {
|
||||
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);
|
||||
// Scale to maximum speed
|
||||
desired.setMag(maxspeed);
|
||||
|
||||
// Steering = Desired minus velocity
|
||||
PVector steer = PVector.sub(desired,velocity);
|
||||
steer.limit(maxforce); // Limit to maximum steering force
|
||||
|
||||
+11
-14
@@ -11,26 +11,23 @@ Vehicle v;
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
v = new Vehicle(width/2, height/2);
|
||||
smooth();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if (mousePressed) {
|
||||
|
||||
background(255);
|
||||
background(255);
|
||||
|
||||
PVector mouse = new PVector(mouseX, mouseY);
|
||||
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);
|
||||
// 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();
|
||||
}
|
||||
// Call the appropriate steering behaviors for our agents
|
||||
v.seek(mouse);
|
||||
v.update();
|
||||
v.display();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,13 +43,12 @@ class Vehicle {
|
||||
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();
|
||||
// Scale with arbitrary damping within 100 pixels
|
||||
if (d < 100) {
|
||||
float m = map(d,0,100,0,maxspeed);
|
||||
desired.mult(m);
|
||||
desired.setMag(m);
|
||||
} else {
|
||||
desired.mult(maxspeed);
|
||||
desired.setMag(maxspeed);
|
||||
}
|
||||
|
||||
// Steering = Desired minus Velocity
|
||||
|
||||
+1
-3
@@ -11,11 +11,9 @@ boolean debug = true;
|
||||
|
||||
float d = 25;
|
||||
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
v = new Vehicle(width/2, height/2);
|
||||
smooth();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+1
-2
@@ -13,9 +13,8 @@ float d = 25;
|
||||
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
v = new Vehicle(width/2, height/2);
|
||||
smooth();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+6
-2
@@ -21,8 +21,8 @@ void setup() {
|
||||
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);
|
||||
car1 = new Vehicle(new PVector(0, height/2), 2, 0.02);
|
||||
car2 = new Vehicle(new PVector(0, height/2), 3, 0.05);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
@@ -36,6 +36,10 @@ void draw() {
|
||||
car1.run();
|
||||
car2.run();
|
||||
|
||||
// Check if it gets to the end of the path since it's not a loop
|
||||
car1.borders(path);
|
||||
car2.borders(path);
|
||||
|
||||
// Instructions
|
||||
fill(0);
|
||||
text("Hit space bar to toggle debugging lines.", 10, height-30);
|
||||
|
||||
+9
-10
@@ -27,8 +27,7 @@ class Vehicle {
|
||||
// Main "run" function
|
||||
void run() {
|
||||
update();
|
||||
borders();
|
||||
render();
|
||||
display();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,10 +35,10 @@ class Vehicle {
|
||||
// http://www.red3d.com/cwr/steer/PathFollow.html
|
||||
void follow(Path p) {
|
||||
|
||||
// Predict location 25 (arbitrary choice) frames ahead
|
||||
// Predict location 50 (arbitrary choice) frames ahead
|
||||
PVector predict = velocity.get();
|
||||
predict.normalize();
|
||||
predict.mult(25);
|
||||
predict.mult(50);
|
||||
PVector predictLoc = PVector.add(location, predict);
|
||||
|
||||
// Look at the line segment
|
||||
@@ -134,7 +133,7 @@ class Vehicle {
|
||||
applyForce(steer);
|
||||
}
|
||||
|
||||
void render() {
|
||||
void display() {
|
||||
// Draw a triangle rotated in the direction of velocity
|
||||
float theta = velocity.heading2D() + radians(90);
|
||||
fill(175);
|
||||
@@ -151,11 +150,11 @@ class Vehicle {
|
||||
}
|
||||
|
||||
// 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;
|
||||
void borders(Path p) {
|
||||
if (location.x > p.end.x + r) {
|
||||
location.x = p.start.x - r;
|
||||
location.y = p.start.y + (location.y-p.end.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -21,8 +21,8 @@ void setup() {
|
||||
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);
|
||||
car1 = new Vehicle(new PVector(0, height/2), 2, 0.04);
|
||||
car2 = new Vehicle(new PVector(0, height/2), 3, 0.1);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
@@ -35,6 +35,9 @@ void draw() {
|
||||
// Call the generic run method (update, borders, display, etc.)
|
||||
car1.run();
|
||||
car2.run();
|
||||
|
||||
car1.borders(path);
|
||||
car2.borders(path);
|
||||
|
||||
// Instructions
|
||||
fill(0);
|
||||
@@ -45,10 +48,10 @@ 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(-20, 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);
|
||||
path.addPoint(width+20, height/2);
|
||||
}
|
||||
|
||||
public void keyPressed() {
|
||||
|
||||
@@ -22,6 +22,15 @@ class Path {
|
||||
PVector point = new PVector(x, y);
|
||||
points.add(point);
|
||||
}
|
||||
|
||||
PVector getStart() {
|
||||
return points.get(0);
|
||||
}
|
||||
|
||||
PVector getEnd() {
|
||||
return points.get(points.size()-1);
|
||||
}
|
||||
|
||||
|
||||
// Draw the path
|
||||
void display() {
|
||||
|
||||
@@ -29,8 +29,7 @@ class Vehicle {
|
||||
// Main "run" function
|
||||
public void run() {
|
||||
update();
|
||||
borders();
|
||||
render();
|
||||
display();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +37,11 @@ class Vehicle {
|
||||
// http://www.red3d.com/cwr/steer/PathFollow.html
|
||||
void follow(Path p) {
|
||||
|
||||
// Predict location 25 (arbitrary choice) frames ahead
|
||||
// Predict location 50 (arbitrary choice) frames ahead
|
||||
// This could be based on speed
|
||||
PVector predict = velocity.get();
|
||||
predict.normalize();
|
||||
predict.mult(25);
|
||||
predict.mult(50);
|
||||
PVector predictLoc = PVector.add(location, predict);
|
||||
|
||||
// Now we must find the normal to the path from the predicted location
|
||||
@@ -165,7 +165,7 @@ class Vehicle {
|
||||
applyForce(steer);
|
||||
}
|
||||
|
||||
void render() {
|
||||
void display() {
|
||||
// Draw a triangle rotated in the direction of velocity
|
||||
float theta = velocity.heading2D() + radians(90);
|
||||
fill(175);
|
||||
@@ -182,11 +182,11 @@ class Vehicle {
|
||||
}
|
||||
|
||||
// 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;
|
||||
void borders(Path p) {
|
||||
if (location.x > p.getEnd().x + r) {
|
||||
location.x = p.getStart().x - r;
|
||||
location.y = p.getStart().y + (location.y-p.getEnd().y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ class Vehicle {
|
||||
void applyBehaviors(ArrayList<Vehicle> vehicles) {
|
||||
PVector separateForce = separate(vehicles);
|
||||
PVector seekForce = seek(new PVector(mouseX,mouseY));
|
||||
separateForce.mult(map(mouseX,0,width,0,2));
|
||||
separateForce.mult(2);
|
||||
seekForce.mult(1);
|
||||
applyForce(separateForce);
|
||||
applyForce(seekForce);
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
void setup() {
|
||||
size(600, 360);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(255);
|
||||
|
||||
PVector a = new PVector(20,300);
|
||||
PVector b = new PVector(500,250);
|
||||
PVector mouse = new PVector(mouseX,mouseY);
|
||||
|
||||
stroke(0);
|
||||
strokeWeight(2);
|
||||
line(a.x,a.y,b.x,b.y);
|
||||
line(a.x,a.y,mouse.x,mouse.y);
|
||||
fill(0);
|
||||
ellipse(a.x,a.y,8,8);
|
||||
ellipse(b.x,b.y,8,8);
|
||||
ellipse(mouse.x,mouse.y,8,8);
|
||||
|
||||
PVector norm = scalarProjection(mouse,a,b);
|
||||
strokeWeight(1);
|
||||
stroke(50);
|
||||
line(mouse.x,mouse.y,norm.x,norm.y);
|
||||
|
||||
noStroke();
|
||||
fill(255,0,0);
|
||||
ellipse(norm.x,norm.y,16,16);
|
||||
}
|
||||
|
||||
|
||||
PVector scalarProjection(PVector p, PVector a, PVector b) {
|
||||
PVector ap = PVector.sub(p, a);
|
||||
PVector ab = PVector.sub(b, a);
|
||||
ab.normalize(); // Normalize the line
|
||||
ab.mult(ap.dot(ab));
|
||||
PVector normalPoint = PVector.add(a, ab);
|
||||
return normalPoint;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ void setup() {
|
||||
|
||||
circleLocation = new PVector(width/2,height/2);
|
||||
circleRadius = height/2-25;
|
||||
|
||||
smooth();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+1
-5
@@ -33,18 +33,14 @@ void setup() {
|
||||
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() {
|
||||
|
||||
+1
-5
@@ -9,10 +9,6 @@
|
||||
// Rules: Cohesion, Separation, Alignment
|
||||
|
||||
// Click mouse to add boids into the system
|
||||
|
||||
import processing.opengl.*;
|
||||
|
||||
|
||||
Flock flock;
|
||||
PVector center;
|
||||
|
||||
@@ -21,7 +17,7 @@ boolean scrollbar = false;
|
||||
|
||||
|
||||
void setup() {
|
||||
size(1024,768,OPENGL);
|
||||
size(displayWidth,displayHeight,P2D);
|
||||
setupScrollbars();
|
||||
center = new PVector(width/2,height/2);
|
||||
colorMode(RGB,255,255,255,100);
|
||||
|
||||
@@ -10,7 +10,7 @@ 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 w = 4;
|
||||
int[][] matrix; // Store a history of generations in 2D array, not just one
|
||||
|
||||
int cols;
|
||||
@@ -66,10 +66,12 @@ class CA {
|
||||
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);
|
||||
// Only draw if cell state is 1
|
||||
if (matrix[i][j] == 1) {
|
||||
fill(0);
|
||||
noStroke();
|
||||
rect(i*w, (y-1)*w, w, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-14
@@ -12,26 +12,20 @@ CA ca; // An object to describe a Wolfram elementary Cellular Automata
|
||||
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
frameRate(30);
|
||||
size(640, 800);
|
||||
frameRate(24);
|
||||
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
|
||||
//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
|
||||
int[] ruleset = {0,1,0,1,1,0,1,0}; // Rule 90
|
||||
|
||||
ca = new CA(ruleset); // Initialize CA
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(255);
|
||||
ca.display(); // Draw the CA
|
||||
ca.generate();
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
saveFrame("222-####.png");
|
||||
//background(255);
|
||||
//ca.randomize();
|
||||
//ca.restart();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -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(640, 360);
|
||||
gol = new GOL();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(255);
|
||||
gol.display();
|
||||
}
|
||||
|
||||
// reset board when mouse is pressed
|
||||
void mousePressed() {
|
||||
gol.init();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -12,6 +12,7 @@ GOL gol;
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
frameRate(24);
|
||||
gol = new GOL();
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -9,8 +9,7 @@
|
||||
float theta;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
smooth();
|
||||
size(640, 360);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+68
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+59
@@ -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<Branch> tree;
|
||||
ArrayList<Leaf> leaves;
|
||||
|
||||
void setup() {
|
||||
size(640,360);
|
||||
background(255);
|
||||
// Setup the arraylist and add one branch to it
|
||||
tree = new ArrayList<Branch>();
|
||||
leaves = new ArrayList<Leaf>();
|
||||
// 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,-1),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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+23
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+74
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
float theta;
|
||||
|
||||
void setup() {
|
||||
size(250, 200);
|
||||
smooth();
|
||||
size(640, 360);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@ LSystem lsys;
|
||||
Turtle turtle;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(600, 600);
|
||||
/*
|
||||
// Create an empty ruleset
|
||||
Rule[] ruleset = new Rule[2];
|
||||
@@ -52,6 +52,7 @@ void mousePressed() {
|
||||
if (counter < 5) {
|
||||
pushMatrix();
|
||||
lsys.generate();
|
||||
//println(lsys.getSentence());
|
||||
turtle.setToDo(lsys.getSentence());
|
||||
turtle.changeLen(0.5);
|
||||
popMatrix();
|
||||
|
||||
@@ -15,8 +15,7 @@ class DNA {
|
||||
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));
|
||||
genes[i] = PVector.random2D();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +45,38 @@ class DNA {
|
||||
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] = PVector.random2D();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debugDraw() {
|
||||
int cols = width / gridscale;
|
||||
int rows = height / gridscale;
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
drawVector(genes[i+j*cols],i*gridscale,j*gridscale,gridscale-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+gridscale/2,y);
|
||||
stroke(0,100);
|
||||
// Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
|
||||
rotate(v.heading());
|
||||
// Calculate length of vector & scale it to be bigger or smaller if necessary
|
||||
float len = v.mag()*scayl;
|
||||
// Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
|
||||
line(-len/2,0,len/2,0);
|
||||
//noFill();
|
||||
//ellipse(-len/2,0,2,2);
|
||||
popMatrix();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// The Nature of Code
|
||||
// The Nature of Code
|
||||
// Daniel Shiffman
|
||||
// http://natureofcode.com
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
int gridscale = 24; // Scale of grid is 1/24 of screen size
|
||||
int gridscale = 10; // 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)
|
||||
@@ -20,9 +20,6 @@ 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
|
||||
@@ -33,10 +30,14 @@ int diam = 24; // Size of target
|
||||
|
||||
ArrayList<Obstacle> obstacles; //an array list to keep track of all the obstacles!
|
||||
|
||||
boolean debug = false;
|
||||
|
||||
Rectangle newObstacle = null;
|
||||
|
||||
void setup() {
|
||||
size(640,480);
|
||||
size(640,360);
|
||||
dnasize = (width / gridscale) * (height / gridscale);
|
||||
lifetime = width/2;
|
||||
lifetime = width/3;
|
||||
|
||||
// Initialize variables
|
||||
lifecycle = 0;
|
||||
@@ -46,22 +47,23 @@ void setup() {
|
||||
|
||||
// Create a population with a mutation rate, and population max
|
||||
int popmax = 1000;
|
||||
float mutationRate = 0.05;
|
||||
float mutationRate = 0.02;
|
||||
population = new Population(mutationRate,popmax);
|
||||
|
||||
// Create the obstacle course
|
||||
obstacles = new ArrayList<Obstacle>();
|
||||
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));
|
||||
|
||||
|
||||
/*obstacles.add(new Obstacle(width/4,80,10,height-160));
|
||||
obstacles.add(new Obstacle(width/2,0,10,height/2-20));
|
||||
obstacles.add(new Obstacle(width/2,height-height/2+20,10,height/2-20));
|
||||
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();
|
||||
// Draw the target locations
|
||||
target.display();
|
||||
|
||||
// Draw the obstacles
|
||||
@@ -89,15 +91,31 @@ void draw() {
|
||||
textAlign(RIGHT);
|
||||
fill(0);
|
||||
text("Generation #:" + population.getGenerations(),width-10,18);
|
||||
text("Cycles left:" + ((lifetime-lifecycle)/10),width-10,36);
|
||||
text("Cycles left:" + ((lifetime-lifecycle)),width-10,36);
|
||||
text("Record cycles: " + recordtime,width-10,54);
|
||||
|
||||
if (newObstacle != null) {
|
||||
rect(newObstacle.x,newObstacle.y,newObstacle.width,newObstacle.height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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;
|
||||
void keyPressed() {
|
||||
if (key == 'd') {
|
||||
debug = !debug;
|
||||
}
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
newObstacle = new Rectangle(mouseX,mouseY,0,0);
|
||||
}
|
||||
|
||||
void mouseDragged() {
|
||||
newObstacle.width = mouseX-newObstacle.x;
|
||||
newObstacle.height = mouseY-newObstacle.y;
|
||||
}
|
||||
|
||||
void mouseReleased() {
|
||||
obstacles.add(new Obstacle(newObstacle));
|
||||
newObstacle = null;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ class Obstacle {
|
||||
Obstacle(int x, int y, int w, int h) {
|
||||
r = new Rectangle(x,y,w,h);
|
||||
}
|
||||
|
||||
Obstacle(Rectangle r_) {
|
||||
r = r_;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
|
||||
@@ -11,17 +11,19 @@ class Population {
|
||||
ArrayList<Rocket> 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
|
||||
int order; // Keep track of the order of creature's finishing the maze
|
||||
|
||||
// Initialize the population
|
||||
Population(float m, int num) {
|
||||
|
||||
|
||||
// Initialize the population
|
||||
Population(float m, int num) {
|
||||
mutationRate = m;
|
||||
population = new Rocket[num];
|
||||
darwin = new ArrayList<Rocket>();
|
||||
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);
|
||||
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
|
||||
@@ -29,14 +31,31 @@ class Population {
|
||||
|
||||
void live (ArrayList<Obstacle> o) {
|
||||
// For every creature
|
||||
|
||||
|
||||
|
||||
float record = 100000;
|
||||
int closest = 0;
|
||||
|
||||
for (int i = 0; i < population.length; i++) {
|
||||
// If it finishes, mark it down as done!
|
||||
if ((population[i].finished()) && (!population[i].stopped())) {
|
||||
if ((population[i].finished())) {
|
||||
population[i].setFinish(order);
|
||||
order++;
|
||||
}
|
||||
// Run it
|
||||
population[i].run(o);
|
||||
|
||||
if (population[i].recordDist < record) {// && !population[i].dead) {
|
||||
record = population[i].recordDist;
|
||||
closest = i;
|
||||
}
|
||||
}
|
||||
|
||||
population[closest].highlight();
|
||||
// Drawing one example of the DNA
|
||||
if (debug) {
|
||||
population[closest].dna.debugDraw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,18 +82,25 @@ class Population {
|
||||
|
||||
// Calculate total fitness of whole population
|
||||
float totalFitness = getTotalFitness();
|
||||
float avgFitness = totalFitness/population.length;
|
||||
|
||||
// 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
|
||||
int count = 0;
|
||||
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]);
|
||||
}
|
||||
float fitness = population[i].getFitness();
|
||||
//if (fitness > avgFitness) {
|
||||
count++;
|
||||
float fitnessNormal = fitness / totalFitness;
|
||||
int n = (int) (fitnessNormal * 50000); // Arbitrary multiplier, consider mapping fix
|
||||
for (int j = 0; j < n; j++) {
|
||||
darwin.add(population[i]);
|
||||
}
|
||||
//}
|
||||
}
|
||||
//println("Total: " + count + " " + population.length);
|
||||
}
|
||||
|
||||
// Making the next generation
|
||||
@@ -94,7 +120,7 @@ class Population {
|
||||
// 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);
|
||||
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++;
|
||||
@@ -112,5 +138,5 @@ class Population {
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,17 @@ class Rocket {
|
||||
PVector acceleration;
|
||||
float r;
|
||||
float recordDist;
|
||||
|
||||
|
||||
float fitness;
|
||||
DNA dna;
|
||||
|
||||
// Could make this part of DNA??)
|
||||
float maxspeed = 6.0;
|
||||
float maxforce = 1.0;
|
||||
|
||||
boolean stopped; // Am I stuck?
|
||||
boolean dead; // Did I hit an obstacle?
|
||||
|
||||
int finish; // What was my finish? (first, second, etc. . . )
|
||||
|
||||
//constructor
|
||||
@@ -46,6 +52,8 @@ class Rocket {
|
||||
}
|
||||
// Reward finishing faster and getting closer
|
||||
fitness = (1.0f / pow(finish,1.5)) * (1 / (pow(d,6)));
|
||||
|
||||
//if (dead) fitness = 0;
|
||||
}
|
||||
|
||||
void setFinish(int f) {
|
||||
@@ -60,6 +68,7 @@ class Rocket {
|
||||
// If I hit an edge or an obstacle
|
||||
if ((borders()) || (obstacles(o))) {
|
||||
stopped = true;
|
||||
dead = true;
|
||||
}
|
||||
}
|
||||
// Draw me!
|
||||
@@ -78,7 +87,9 @@ class Rocket {
|
||||
// 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 (d < recordDist) {
|
||||
recordDist = d;
|
||||
}
|
||||
if (target.contains(location)) {
|
||||
stopped = true;
|
||||
return true;
|
||||
@@ -105,11 +116,13 @@ class Rocket {
|
||||
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);
|
||||
// A little Reynolds steering here
|
||||
PVector desired = dna.genes[x+y*(width/gridscale)].get();
|
||||
desired.mult(maxspeed);
|
||||
PVector steer = PVector.sub(desired,velocity);
|
||||
acceleration.add(steer);
|
||||
acceleration.limit(maxforce);
|
||||
|
||||
velocity.add(acceleration);
|
||||
velocity.limit(maxspeed);
|
||||
location.add(velocity);
|
||||
@@ -121,7 +134,7 @@ class Rocket {
|
||||
//fill(0,150);
|
||||
//stroke(0);
|
||||
//ellipse(location.x,location.y,r,r);
|
||||
float theta = velocity.heading2D() + PI/2;
|
||||
float theta = velocity.heading() + PI/2;
|
||||
fill(200,100);
|
||||
stroke(0);
|
||||
pushMatrix();
|
||||
@@ -133,8 +146,14 @@ class Rocket {
|
||||
vertex(r, r*2);
|
||||
endShape();
|
||||
popMatrix();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void highlight() {
|
||||
stroke(0);
|
||||
line(location.x,location.y,target.r.x,target.r.y);
|
||||
fill(255,0,0,100);
|
||||
ellipse(location.x,location.y,16,16);
|
||||
|
||||
}
|
||||
|
||||
float getFitness() {
|
||||
|
||||
@@ -41,6 +41,8 @@ class DNA {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fitness = (float)score / (float)target.length();
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -36,7 +36,7 @@ float mutationRate;
|
||||
Population population;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
f = createFont("Courier", 32, true);
|
||||
target = "To be or not to be.";
|
||||
popmax = 150;
|
||||
@@ -71,19 +71,19 @@ void displayInfo() {
|
||||
fill(0);
|
||||
|
||||
|
||||
textSize(16);
|
||||
textSize(24);
|
||||
text("Best phrase:",20,30);
|
||||
textSize(32);
|
||||
text(answer, 20, 75);
|
||||
textSize(40);
|
||||
text(answer, 20, 100);
|
||||
|
||||
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(18);
|
||||
text("total generations: " + population.getGenerations(), 20, 160);
|
||||
text("average fitness: " + nf(population.getAverageFitness(), 0, 2), 20, 180);
|
||||
text("total population: " + popmax, 20, 200);
|
||||
text("mutation rate: " + int(mutationRate * 100) + "%", 20, 220);
|
||||
|
||||
textSize(10);
|
||||
text("All phrases:\n" + population.allPhrases(), 650, 10);
|
||||
text("All phrases:\n" + population.allPhrases(), 500, 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class Population {
|
||||
finished = false;
|
||||
generations = 0;
|
||||
|
||||
perfectScore = int(pow(2,target.length()));
|
||||
perfectScore = 1;
|
||||
}
|
||||
|
||||
// Fill our fitness array with a value for every member of the population
|
||||
@@ -82,7 +82,7 @@ class Population {
|
||||
|
||||
// Compute the current "most fit" member of the population
|
||||
String getBest() {
|
||||
float worldrecord = 0.0f;
|
||||
float worldrecord = 0.0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < population.length; i++) {
|
||||
if (population[i].fitness > worldrecord) {
|
||||
@@ -90,7 +90,7 @@ class Population {
|
||||
worldrecord = population[i].fitness;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (worldrecord == perfectScore ) finished = true;
|
||||
return population[index].getPhrase();
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,9 +23,9 @@ int lifeCounter; // Timer for cycle of generation
|
||||
PVector target; // Target location
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
// The number of cycles we will allow a generation to live
|
||||
lifetime = 200;
|
||||
lifetime = height;
|
||||
|
||||
// Initialize variables
|
||||
lifeCounter = 0;
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ Obstacle target; // Target location
|
||||
ArrayList<Obstacle> obstacles; //an array list to keep track of all the obstacles!
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
// The number of cycles we will allow a generation to live
|
||||
lifetime = 300;
|
||||
|
||||
@@ -44,7 +44,7 @@ void setup() {
|
||||
|
||||
// Create the obstacle course
|
||||
obstacles = new ArrayList<Obstacle>();
|
||||
obstacles.add(new Obstacle(300, height/2, width-600, 10));
|
||||
obstacles.add(new Obstacle(width/2-100, height/2, 200, 10));
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
+5
-1
@@ -13,7 +13,7 @@
|
||||
World world;
|
||||
|
||||
void setup() {
|
||||
size(800, 200);
|
||||
size(640, 360);
|
||||
// World starts with 20 creatures
|
||||
// and 20 pieces of food
|
||||
world = new World(20);
|
||||
@@ -30,4 +30,8 @@ void mousePressed() {
|
||||
world.born(mouseX,mouseY);
|
||||
}
|
||||
|
||||
void mouseDragged() {
|
||||
world.born(mouseX,mouseY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user