class Agent { float vel = 1.0; float r, amp; float maxforce = 0.01; float max = 4.0f; List<Vec3D> objectTrails; Vec3D speed = new Vec3D(vel, 0, 0); Vec3D acc = new Vec3D(0, 0, 0); Vec3D loc; //------------------------------------------------------------------------------------------- Agent(Vec3D location) { loc = location; this.objectTrails = new ArrayList<Vec3D>(); r = 12; } //------------------------------------------------------------------------------------------- //---------------------------------------Runs all other methods------------------------------ //------------------------------------------------------------------------------------------- void run() { pathFollow(); separate(); if (simulate) { move(); } viz(); trail(); } //------------------------------------------------------------------------------------------- //---------------------------------------Path Follow Method---------------------------------- //------------------------------------------------------------------------------------------- void pathFollow() { Vec3D predict = this.speed.copy(); predict.normalize(); predict.scaleSelf(this.amp); Vec3D nextPosPrev = this.loc.add(predict); Vec3D target = null; Vec3D normal = null; float worldRecord = 1000000; for (int i = 0; i < tempPath.points.size()-1; i++) { Vec3D a = tempPath.points.get(i); Vec3D b = tempPath.points.get(i+1); Vec3D normalPoint = getNormalPoint(nextPosPrev, a, b); //Finding the normals for each line segment if (normalPoint.x < min(a.x, b.x) || normalPoint.x > max(a.x, b.x)) { normalPoint = b.copy(); } float distance = nextPosPrev.distanceTo(normalPoint); if (distance < worldRecord) { worldRecord = distance; normal = normalPoint; Vec3D dir = b.sub(a); // Look at the direction of the line segment so we can seek a little bit ahead of the normal dir.normalize(); dir.scaleSelf(10); target = normalPoint.copy(); target.add(dir); } } if (worldRecord > tempPath.radius ) { seek(target); } else { Vec3D zero = new Vec3D(0, 0, 0); zero.scaleSelf(3); this.acc.addSelf(zero); } // Draw the debugging stuff if (debug) { // Draw predicted future location stroke(255); fill(0); line(this.loc.x, this.loc.y, this.loc.x, this.loc.y); ellipse(nextPosPrev.x, nextPosPrev.y, 4, 4); // Draw normal location stroke(255); fill(0); ellipse(normal.x, normal.y, 4, 4); // Draw actual target (red if steering towards it) line(nextPosPrev.x, nextPosPrev.y, normal.x, normal.y); if (worldRecord > tempPath.radius) fill(255, 0, 0); noStroke(); ellipse(target.x, target.y, 8, 8); } } //------------------------------------------------------------------------------------------- //-------------------Get the Normal Point on the Path Method--------------------------------- //------------------------------------------------------------------------------------------- Vec3D getNormalPoint(Vec3D p, Vec3D a, Vec3D b) { Vec3D ap = p.sub(a); Vec3D ab = b.sub(a); ab.normalize(); ab.scaleSelf(ap.dot(ab)); //Using the dot product for scalar projection Vec3D normalPoint = a.add(ab); // Finding the normal point along the line segment return normalPoint; } //------------------------------------------------------------------------------------------- //---------------------------------------Seek Target Method---------------------------------- //------------------------------------------------------------------------------------------- void seek(Vec3D target) { Vec3D desired = target.sub(loc); desired.normalize(); desired.scaleSelf(max); Vec3D steer = desired.sub(speed); steer.limit(maxforce); // Limit the magnitude of the steering force. steer.scaleSelf(3); applyForce(steer); } //------------------------------------------------------------------------------------------- //---------------------------------------Apply Force Method---------------------------------- //------------------------------------------------------------------------------------------- void applyForce(Vec3D force) { this.acc.addSelf(force); } //------------------------------------------------------------------------------------------- //-------------------------------------------Move Method------------------------------------- //------------------------------------------------------------------------------------------- void move() { this.speed.addSelf(this.acc); this.speed.limit(this.max); this.loc.addSelf(this.speed); this.objectTrails.add(new Vec3D(this.loc)); this.acc.clear(); } //------------------------------------------------------------------------------------------- //-------------------------------------------Viz Method-------------------------------------- //------------------------------------------------------------------------------------------- void viz() { stroke(255, 0, 0); strokeWeight(6); point(this.loc.x, this.loc.y); } //------------------------------------------------------------------------------------------- //---------------------------------------Separation Method---------------------------------- //------------------------------------------------------------------------------------------- void separate () { float desiredseparation = r*2; Vec3D steer = new Vec3D(0, 0, 0); int count = 0; for (int i = 0; i < agentList.size(); i++) { // For every agent in the system, check if it's too close Agent other = (Agent) agentList.get(i); float d = this.loc.distanceTo(other.loc); if ((d > 0) && (d < desiredseparation)) { // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) Vec3D diff = loc.sub(other.loc); // Calculate vector pointing away from neighbor diff.normalize(); diff.normalizeTo(1/d); // Weight by distance steer.addSelf(diff); count++;// Keep track of how many } } if (count > 0) { steer.scaleSelf(1.0/(float)count); // Average } if (steer.magnitude() > 0) { // As long as the vector is greater than 0 // Implement Reynolds: Steering = Desired - Velocity steer.normalize(); steer.scaleSelf(this.max); steer.subSelf(this.speed); steer.limit(this.maxforce); } steer.scaleSelf(1); applyForce(steer); } //------------------------------------------------------------------------------------------- //---------------------------------------Trail Method---------------------------------------- //------------------------------------------------------------------------------------------- void trail() { if (objectTrails.size() > 0) { for (int j = 0; j < objectTrails.size(); j++) { if (j != 0) { Vec3D pos = objectTrails.get(j); Vec3D prevpos = objectTrails.get(j - 1); stroke(255, 0, 0, map(j, 0, objectTrails.size(), 0, 200)); strokeWeight(map(j, 0, objectTrails.size(), 0.45, 1.0)); line(pos.x, pos.y, prevpos.x, prevpos.y); } } } } } Update