Current File : /home/jeshor13/11bsouth.com/MidtownGame/Peds.js |
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// The "Vehicle" class
function Ped(loc, dirI, pROW, birthtime) {
this.position = loc;
this.acceleration = createVector(0, 0);
this.velocity = dirI;
this.dirI = dirI
this.r = 10;
this.maxspeed = 2;
this.maxforce = .3;
this.pROW = pROW
this.isDead = false;
this.birthtime = birthtime
this.obstructed = false
this.stop = false
this.run = function() {
this.display();
this.traffic()
this.update();
}
// This function implements Craig Reynolds' path following algorithm
// http://www.red3d.com/cwr/steer/PathFollow.html
this.follow = function() {
// Predict location 50 (arbitrary choice) frames ahead
// This could be based on speed
var predict = this.velocity.copy();
predict.normalize();
predict.mult(90);
var predictLoc = p5.Vector.add(this.position, 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
var normal = null;
var target = null;
var worldRecord = 1000000; // Start with a very high record distance that can easily be beaten
// Loop through all points of the path
for (var i = 0; i < this.pROW.points.length; i++) {
// Look at a line segment
var a = this.pROW.points[i];
if (i == this.pROW.points.length - 1) {
var b = this.pROW.points[i];
} else {
var b = this.pROW.points[(i + 1) % this.pROW.points.length];
}
//println(b);
// Get the normal point to that line
var 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
var dir = p5.Vector.sub(b, a)
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.copy();
a = this.pROW.points[(i + 1) % this.pROW.points.length]
b = this.pROW.points[(i + 2) % this.pROW.points.length]
dir = p5.Vector.sub(b, a)
}
// How far away are we from the path?
var distance = p5.Vector.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
//var dir = p5.Vector.sub(b, a);
dir.normalize();
// This is an oversimplification
// Should be based on distance to path & velocity
dir.mult(10);
target = normalPoint.copy();
target.add(dir);
}
}
// Only if the distance is greater than the path's radius do we bother to steer
if (worldRecord > this.pROW.radius && target !== null) {
this.seek(target);
}
// //Draw the debugging stuff
// if (debug) {
// // Draw predicted future location
// stroke(255);
// fill(200);
// line(this.position.x, this.position.y, predictLoc.x, predictLoc.y);
// ellipse(predictLoc.x, predictLoc.y, 4, 4);
// // Draw normal location
// stroke(255);
// fill(200);
// 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 > this.pROW.radius) fill(255, 0, 0);
// noStroke();
// ellipse(target.x, target.y, 8, 8);
// }
};
this.applyForce = function(force) {
// We could add mass here if we want A = F / M
this.acceleration.add(force);
};
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
this.seek = function(target) {
var desired = p5.Vector.sub(target, this.position); // A vector pointing from the position 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(this.maxspeed);
// Steering = Desired minus Velocity
var steer = p5.Vector.sub(desired, this.velocity);
steer.limit(this.maxforce); // Limit to maximum steering force
this.applyForce(steer);
};
// Method to update position
this.update = function() {
// Update velocity
this.velocity.add(this.acceleration);
// Limit speed
this.velocity.limit(this.maxspeed);
this.position.add(this.velocity);
// Reset accelerationelertion to 0 each cycle
this.acceleration.mult(0);
};
// Death
this.borders = function() {
if (this.position.x >= width - this.r * 2 && millis() - this.birthtime >= 1000) {
this.isDead = true
}
if (this.position.x <= 0 + this.r * 2 && millis() - this.birthtime >= 1000) {
this.isDead = true
}
if (this.position.y >= height - this.r * 2 && millis() - this.birthtime >= 1000) {
this.isDead = true
}
if (this.position.y <= 0 + this.r * 2 && millis() - this.birthtime >= 1000) {
this.isDead = true
};
}
this.display = function() {
// Draw a triangle rotated in the direction of velocity
colorMode(HSB);
var m = map((millis() - this.birthtime), 0, 30000, 1, 255)
fill(0, 255, m);
stroke(255);
strokeWeight(1);
ellipse(this.position.x, this.position.y, this.r, this.r)
};
// 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
var getNormalPoint = function(p, a, b) {
// Vector from a to p
var ap = p5.Vector.sub(p, a); // subrtacting a (current line point loc) from predicted lcoationt
// Vector from a to b
var ab = p5.Vector.sub(b, a); // subrtacting b (next line point loc) from predicted lcoationt
ab.normalize(); // Normalize the line
// Project vector "diff" onto line by using the dot product
ab.mult(ap.dot(ab));
var normalPoint = p5.Vector.add(a, ab);
return normalPoint;
};
// Separation
// Method checks for nearby boids and steers away
this.separate = function() {
var desiredseparation = this.r * 5;
var steer = createVector(0, 0, 0);
var count = 0;
var predict = this.velocity.copy();
predict.normalize();
predict.mult(this.r * noise(millis()) * 10);
var predictLoc = p5.Vector.add(this.position, predict);
// For every boid in the system, check if it's too close
for (var i = 0; i < cars.length; i++) {
var other = cars[i];
var predictOther = other.velocity.copy();
predictOther.normalize();
predictOther.mult(this.r * noise(millis() + 5) * 10);
var predictOtherLoc = p5.Vector.add(other.position, predict);
var d = p5.Vector.dist(predictLoc, predictOtherLoc);
//var d2 = p5.Vector.dist(this.position, other.position);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
var diff = p5.Vector.sub(predictLoc, predictOtherLoc);
//var diff2 = p5.Vector.sub(this.position, other.position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
steer.div(count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// Implement Reynolds: Steering = Desired - Velocity
steer.normalize();
steer.mult(this.maxspeed);
steer.sub(this.velocity);
steer.limit(this.maxforce);
this.applyForce(steer);
//print("bloop"+" "+steer.mag())
this.obstructed = true
} else {
this.obstructed = false
}
}
this.traffic = function() {
if (this.obstructed === true) {
var c = this.velocity.copy()
c.mult(-.1)
this.applyForce(c)
}
var predict = this.velocity.copy();
predict.normalize();
predict.mult(20);
var predictLoc = p5.Vector.add(this.position, predict);
if (predictLoc.dist(this.pROW.points[0]) < this.position.dist(this.pROW.points[0]) - 5) {
var g = this.velocity.copy()
g.normalize()
g.mult(-this.maxspeed)
this.applyForce(g)
//print("blloop")
}
if (this.velocity.mag() < .5 && this.obstructed === false) {
this.applyForce(this.dirI)
}
}
}