import java.util.List; class Tracker { List<PVector> objectTrails; PVector speed, loc; PVector acc = new PVector(0, 0, 0); float maxforce = 0.01; float max = 4.0f; float vel = 1.0; float maxDist = 100; float r, amp; float wandertheta, wanderTVal, wanderD, wanderR, wanderT; float headWidth, strokeWidth, tranparency; boolean sepActive = false; boolean wonderTrigger = false; boolean instanceable; boolean dim; boolean randomize; int maxChildren = 0; int instanceTriggerCount; int seekerMT; int seekerChildMT; int minTrailPtCount = 0; int currentTrailSize = 0; String type, babyType; TColor colorA = TColor.newRGB(255.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f); TColor colorB = TColor.newRGB(120.0f, 0.0f, 0.0f); TColor colorB2 = TColor.newRGB(0.0f, 255.0f, 255.0f); TColor colorC = TColor.newRGB(187.0f / 255.0f, 216.0f / 255.0f, 40.0f / 255.0f); TColor colorD = TColor.newRGB(255.0f, 0.0f, 120.0f); TColor colorE = TColor.newRGB(200.0f / 60.0f, 160.0f / 100.0f, 80.0f / 30.0f); ColorGradient gradA = new ColorGradient(); ColorGradient gradB = new ColorGradient(); ColorGradient gradC = new ColorGradient(); ToneMap toneMapA, toneMapB, toneMapC; //-----------------Flocking Things----------------------------------------------------- String objectType; String behaviorType = "None"; PVector cummVec, alignVector, separateVector, cohesionVector; float maxSpeed, maxForce; float searchRad, av, sv, cv; List<PVector> otherPtsList; List<PVector> otherMoveValues; List<Float> allDist; List<Tracker> creeperCollection; ArrayList<PVector> creeperTrails; //------------------------------------------------------------------------------------- Tracker(PVector location, PVector Speed, boolean instance, String Type, String BabyType) { this.loc = location; this.objectTrails = new ArrayList<PVector>(); this.instanceTriggerCount = 0; this.instanceable = instance; this.type = Type; this.babyType = BabyType; this.speed = Speed; this.r = 12; this.gradA.addColorAt(0.0f, this.colorA); this.gradA.addColorAt(255.0f, this.colorC); this.toneMapA = new ToneMap(0.0f, 1.0f, this.gradA); this.gradB.addColorAt(0.0f, this.colorB); this.gradB.addColorAt(255.0f, this.colorB2); this.toneMapB = new ToneMap(0.0f, 1.0f, this.gradB); this.gradC.addColorAt(0.0f, this.colorD); this.gradC.addColorAt(255.0f, this.colorE); this.toneMapC = new ToneMap(0.0f, 1.0f, this.gradC); } //------------------------------------------------------------------------------------- //Run all of the other methods--------------------------------------------------------- //instanceable is whether or not current creeper is type parent or child, child cannot create instances //------------------------------------------------------------------------------------- void run() { if (enablePathTrack) { pathFollow(); } if (this.sepActive && this.instanceable && this.r != 0) { separate(); } if (masterBehavior_A || subBehavior_AA || subBehavior_AB) { if (enablePathTrack) { if (this.wonderTrigger) { wander(); } } else { wander(); } } if (masterBehavior_B) { this.wonderTrigger = true; this.randomize = true; wanderSolo(); } if (masterBehavior_C) { this.wonderTrigger = true; this.randomize = true; wanderSolo(); } if (masterBehavior_D) { this.wonderTrigger = true; this.randomize = true; wanderSolo(); } if (masterBehavior_E) { flock(); } if (simulate) { move(); } viz(); trail(); } //--------------------------------------------------------------------------------------- public void wanderSolo() { if (this.randomize) { this.wandertheta += random(-this.wanderT, this.wanderT); // Randomly change wander theta } else { this.wandertheta += this.wanderT; } PVector circleLoc = new PVector(this.speed.x, this.speed.y, this.speed.z); circleLoc.normalize(); // Normalize to get heading circleLoc.mult(this.wanderD); circleLoc.add(this.loc); PVector circleOffSet = new PVector(0, 0, 0); if (masterBehavior_B) { circleOffSet = new PVector(this.wanderR*cos(wandertheta), this.wanderR*sin(wandertheta), 0); } else if (masterBehavior_C) { circleOffSet = new PVector(this.wanderR*cos(wandertheta), this.wanderR*sin(wandertheta), random(this.wanderR*cos(wandertheta), this.wanderR*sin(wandertheta))); } else if (masterBehavior_D) { circleOffSet = new PVector(random(this.wanderR*cos(wandertheta), this.wanderR*sin(wandertheta)), random(this.wanderR*cos(wandertheta), this.wanderR*sin(wandertheta)), random(this.wanderR*cos(wandertheta), this.wanderR*sin(wandertheta))); } PVector target = circleLoc.add(circleOffSet); if (drawMovement) drawWanderStuff(this.loc, circleLoc, target, this.wanderR); // Render wandering circle, etc. PVector steer = target.sub(this.loc); steer.normalize(); steer.mult(1); this.acc.add(steer); } //------------------------------------------------------------------------------------- //Wandering Creeper---------------------------------------------------- //“Wandering is a type of random steering which has some long term order: the steering //direction on one frame is related to the steering direction on the next frame. This //produces more interesting motion than, for example, simply generating a random steering //direction each frame.” Reynolds //------------------------------------------------------------------------------------- void wander() { if (stepCount < this.wanderTVal) { if (this.type == "parent") { this.wandertheta = this.wanderT; } else if (this.type == "child") { if (this.babyType == "w_a") { this.wandertheta = this.wanderT; } else { this.wandertheta = -this.wanderT; } } } else if (stepCount >= this.wanderTVal && stepCount < this.wanderTVal*2) { if (this.type == "parent") { this.wandertheta = -this.wanderT; } else if (this.type == "child") { if (this.babyType == "w_a") { this.wandertheta = -this.wanderT; } else { this.wandertheta = this.wanderT; } } } else { stepCount = 0; } // Now we have to calculate the new location to steer towards on the wander circle PVector circleloc = this.speed.copy(); // Start with velocity circleloc.normalize(); // Normalize to get heading circleloc.mult(this.wanderD); // Multiply by distance circleloc.add(this.loc); // Make it relative to boid's location float h, headingXY, headingYZ, headingXZ; PVector circleOffSet; if (D2) { h = this.speed.heading(); circleOffSet = new PVector(this.wanderR*cos(this.wandertheta+h), this.wanderR*sin(this.wandertheta+h), 0); headingXZ = 0; headingYZ = 0; headingXY = 0; } else { headingXY = (float)Math.atan2(this.speed.y, this.speed.x); headingXZ = (float)Math.atan2(this.speed.z, this.speed.x); headingYZ = (float)Math.atan2(this.speed.y, this.speed.z); if (subBehavior_AA) { circleOffSet = new PVector(this.wanderR*cos(this.wandertheta+headingXY), this.wanderR*sin(this.wandertheta+headingXY), this.wanderR*cos(this.wandertheta+headingXZ)); } else if (subBehavior_AB) { circleOffSet = new PVector(this.wanderR*cos(this.wandertheta+headingXY), this.wanderR*sin(this.wandertheta+headingXY), (this.wanderR*cos(this.wandertheta+headingYZ) + this.wanderR*sin(this.wandertheta+headingXZ))/2); } else { circleOffSet = new PVector(this.wanderR*cos(this.wandertheta+headingXY), this.wanderR*sin(this.wandertheta+headingXY), random(this.wanderR*cos(this.wandertheta+(headingYZ + headingXZ)), this.wanderR*sin(this.wandertheta+(headingYZ + headingXZ)))); } } PVector target = PVector.add(circleloc, circleOffSet); seek(target); if (drawMovement) drawWanderStuff(this.loc, circleloc, target, this.wanderR); // Render wandering circle, etc. } //------------------------------------------------------------------------------------- //Draw the wandering creeper movements------------------------------------------------- //------------------------------------------------------------------------------------- // A method just to draw the circle associated with wandering void drawWanderStuff(PVector location, PVector circle, PVector target, float rad) { pushStyle(); stroke(255); noFill(); point(circle.x, circle.y, circle.z); popStyle(); pushStyle(); stroke(120); point(target.x, target.y, target.z); popStyle(); pushStyle(); stroke(160); strokeWeight(1); line(location.x, location.y, location.z, circle.x, circle.y, circle.z); line(circle.x, circle.y, circle.z, target.x, target.y, target.z); popStyle(); } //------------------------------------------------------------------------------------- //Setup for path following------------------------------------------------------------- //So lets check if we are inside the virtual path thickness, if we are and we can create //children then they would spawn here, depending on the max allowed etc. //------------------------------------------------------------------------------------- void pathFollow() { PVector predict = this.speed.copy(); predict.normalize(); predict.mult(this.amp); PVector nextPosPrev = PVector.add(loc, predict); PVector target = null; PVector normal = null; float worldRecord = 1000000; for (int z = 0; z < pathList.size(); z++) { for (int i = 0; i < pathList.get(z).points.size()-1; i++) { PVector a = pathList.get(z).points.get(i); PVector b = pathList.get(z).points.get(i+1); PVector normalPoint = getNormalPoint(nextPosPrev, a, b);//[offset-down] Finding the normals for each line segment if (D2) { if (normalPoint.x < min(a.x, b.x) || normalPoint.x > max(a.x, b.x)) { normalPoint = b.copy(); } } else { 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.z < min(a.z, b.z) || normalPoint.z > max(a.z, b.z))) { normalPoint = b.copy(); } } float distance = nextPosPrev.dist(normalPoint); if (distance < worldRecord) { worldRecord = distance; normal = normalPoint; PVector dir = PVector.sub(b, a); // Look at the direction of the line segment so we can seek a little bit ahead of the normal dir.normalize(); dir.mult(10); target = normalPoint.copy(); target.add(dir); } } } //remove if you want to just go to the line //maxDist = 10000000000000f; if (worldRecord < maxDist) { this.sepActive = true; this.wonderTrigger = true; if (worldRecord > tempPath.radius) { seek(target); } else { if (triggerSeekers && this.instanceable && this.instanceTriggerCount < this.maxChildren) { //check that we have not exceeded the amount of children we are allowed to create addNew = true; triggerLoc = nextPosPrev.copy(); childSpawners.add(new PVector(this.loc.x, this.loc.y, this.loc.z)); childSpawnType.add(this.instanceTriggerCount); triggerCount++; this.instanceTriggerCount ++; } else { addNew = false; } PVector zero = new PVector(0, 0, 0); zero.mult(3); acc.add(zero); } } else { this.wonderTrigger = false; } if (drawPathTargets) { // Draw predicted future location pushStyle(); stroke(255); strokeWeight(1); fill(0); popStyle(); if (D2) { ellipse(nextPosPrev.x, nextPosPrev.y, 4, 4); } else { pushStyle(); stroke(255, 255, 0); strokeWeight(10); point(nextPosPrev.x, nextPosPrev.y, nextPosPrev.z); popStyle(); pushStyle(); stroke(120); line(this.loc.x, this.loc.y, this.loc.z, nextPosPrev.x, nextPosPrev.y, nextPosPrev.z); popStyle(); } // Draw normal location pushStyle(); stroke(255); fill(0); if (D2) { ellipse(normal.x, normal.y, 4, 4); } else { pushStyle(); strokeWeight(4); point(normal.x, normal.y, normal.z); popStyle(); } popStyle(); pushStyle(); stroke(255); strokeWeight(2); // Draw actual target (red if steering towards it) line(nextPosPrev.x, nextPosPrev.y, nextPosPrev.z, normal.x, normal.y, normal.z); popStyle(); pushStyle(); if (worldRecord > tempPath.radius) fill(255, 0, 0); noStroke(); if (D2) { ellipse(target.x, target.y, 8, 8); } else { pushStyle(); stroke(255, 0, 0); strokeWeight(10); point(target.x, target.y, target.z); popStyle(); } popStyle(); } } //------------------------------------------------------------------------------------- //Gets the normal point of each path--------------------------------------------------- //Paths are comprised of multiple segments per path------------------------------------ PVector getNormalPoint(PVector p, PVector a, PVector b) { PVector ap = PVector.sub(p, a); PVector ab = PVector.sub(b, a); ab.normalize(); ab.mult(PVector.dot(ap, ab)); //Using the dot product for scalar projection PVector normalPoint = PVector.add(a, ab);// Finding the normal point along the line segment return normalPoint; } //------------------------------------------------------------------------------------- //Created the steering vector towards the target position------------------------------ //------------------------------------------------------------------------------------- void seek(PVector target) { PVector desired = PVector.sub(target, this.loc); desired.normalize(); desired.mult(this.max); PVector steer = desired.sub(this.speed); // Limit the magnitude of the steering force. steer.limit(this.maxforce); //acc.addSelf(steer); steer.mult(3); applyForce(steer); } //------------------------------------------------------------------------------------- //Apply Force to the acceleration------------------------------------------------------ //------------------------------------------------------------------------------------- void applyForce(PVector force) { acc.add(force); } //------------------------------------------------------------------------------------- //Move creeper to the next location---------------------------------------------------- //------------------------------------------------------------------------------------- void move() { if (!mathBehavior) { this.speed.add(this.acc); this.speed.limit(this.max); this.loc.add(this.speed); this.acc = new PVector(); } else { this.speed.add(this.acc); this.speed.normalize(); this.speed.mult(this.vel); this.speed.limit(this.max); this.loc.add(this.speed); this.acc = new PVector(); } } //------------------------------------------------------------------------------------- //Draw the heads and set values based on type------------------------------------------ //------------------------------------------------------------------------------------- void viz() { if (this.type == "parent" && headWidth != 0.0f) { stroke(191, 255, 0); strokeWeight(headWidth); point(this.loc.x, this.loc.y, this.loc.z); } else if (this.type == "child" && headWidth != 0.0f) { if (this.babyType == "w_a") { stroke(120, 75, 255); strokeWeight(headWidth/2); point(this.loc.x, this.loc.y, this.loc.z); } else { stroke(190, 255, 115); strokeWeight(headWidth/2); point(this.loc.x, this.loc.y, this.loc.z); } } } //------------------------------------------------------------------------------------- //Separation Method steers away from nearby dudes-------------------------------------- //------------------------------------------------------------------------------------- void separate () { float desiredseparation = this.r*2; PVector steer = new PVector(0, 0, 0); int count = 0; // check if we are too close for (int i = 0; i < agentList.size(); i++) { Tracker other = (Tracker) agentList.get(i); float d = loc.dist(other.loc); if ((d > 0) && (d < desiredseparation)) { PVector diff = PVector.sub(this.loc, other.loc); diff.normalize(); diff = PVector.mult(diff, (1.00f / d)); // Weight by distance steer.add(diff); count++; } } if (count > 0) { steer.mult(1.0/(float)count); } if (steer.mag() > 0) { //Steering = Desired - Velocity steer.normalize(); steer.mult(this.max); steer.sub(this.speed); steer.limit(this.maxforce); } steer.mult(3); applyForce(steer); } //------------------------------------------------------------------------------------- //Draw Tail and decay based on trail point amount-------------------------------------- //Trail is drawn from segment to segment and colored based on a tonemap---------------- //------------------------------------------------------------------------------------- void trail() { this.currentTrailSize++; if (this.currentTrailSize > this.minTrailPtCount) { this.objectTrails.add(new PVector(this.loc.x, this.loc.y, this.loc.z)); this.currentTrailSize = 0; } if (this.type == "parent") { //if the type is a parent then set the trail decay by removing backwards from the tail after a target is met if (this.objectTrails.size() > this.seekerMT) { this.objectTrails.remove(0); } } else if (this.type == "child") { //if the type is a child then set the trail decay by removing backwards from the tail after a target is met if (this.objectTrails.size() > this.seekerChildMT) { this.objectTrails.remove(0); } } if (this.objectTrails.size() > 0) { for (int j = 0; j < this.objectTrails.size(); j++) { if (j != 0) { PVector pos = objectTrails.get(j); PVector prevpos = objectTrails.get(j - 1); if (this.type == "parent") { int a = this.toneMapA.getARGBToneFor(j / (1.0f * this.objectTrails.size())); if (toggleColor) { stroke(a, map(j, 0, objectTrails.size(), 0, tranparency)); strokeWeight(map(j, 0, this.objectTrails.size(), 0.45, strokeWidth)); } else { stroke(255, 0, 0, map(j, 0, this.objectTrails.size(), 0, 200)); strokeWeight(map(j, 0, this.objectTrails.size(), 0.45, 1.5)); } } else if (this.babyType == "w_a") { int a = this.toneMapB.getARGBToneFor(j / (1.0f * this.objectTrails.size())); if (toggleColor) { stroke(a, map(j, 0, objectTrails.size(), 0, tranparency)); strokeWeight(map(j, 0, this.objectTrails.size(), 0.45, strokeWidth)); } else { stroke(0, 0, 255, map(j, 0, this.objectTrails.size(), 0, 200)); strokeWeight(map(j, 0, this.objectTrails.size(), 0.45, 1.0)); } } else { int a = this.toneMapC.getARGBToneFor(j / (1.0f * this.objectTrails.size())); if (toggleColor) { stroke(a, map(j, 0, objectTrails.size(), 0, tranparency)); strokeWeight(map(j, 0, this.objectTrails.size(), 0.45, strokeWidth)); } else { stroke(0, 255, 255, map(j, 0, this.objectTrails.size(), 0, 200)); strokeWeight(map(j, 0, this.objectTrails.size(), 0.45, 1.0)); } } line(pos.x, pos.y, pos.z, prevpos.x, prevpos.y, prevpos.z); } } } } void drawConnectivity(PVector conv) { pushStyle(); stroke(255, 255, 255, 150); strokeWeight(0.5); line(loc.x, loc.y, loc.z, conv.x, conv.y, conv.z); popStyle(); } void flock() { this.otherPtsList = new ArrayList<PVector>(); this.otherMoveValues = new ArrayList<PVector>(); this.allDist = new ArrayList<Float>(); Sphere bs = new Sphere(new Vec3D(this.loc.x, this.loc.y, this.loc.z), this.searchRad); occTreeList = octree.getPointsWithinSphere(bs); if (occTreeList!=null) { if (occTreeList.size()!=50402030) { for (int i = 0; i < occTreeList.size(); i++) { int index = vec3DList.indexOf((Vec3D)occTreeList.get(i)); if (drawConn) { Vec3D tconv = new Vec3D((Vec3D)occTreeList.get(i)); PVector conv = new PVector(tconv.x, tconv.y, tconv.z); drawConnectivity(conv); } Tracker other = (Tracker) creeperCollection.get(index); float distance = this.loc.dist(other.loc); if (distance != 0) { this.otherPtsList.add(other.loc); this.allDist.add(distance); if (index != -1) { this.otherMoveValues.add(other.speed); } } } } } if (this.otherPtsList.size() > 0) { this.cummVec = new PVector(); // ----------Align----------------- alignMethod(); if (this.alignVector.mag() > 0) { this.alignVector.normalize(); } this.alignVector.mult(this.av); // ----------Separate----------------- separateMethod(); if (this.separateVector.mag() > 0) { this.separateVector.normalize(); } this.separateVector.mult(this.sv); // ----------Cohesion----------------- cohesionMethod(); if (this.cohesionVector.mag() > 0) { this.cohesionVector.normalize(); } this.cohesionVector.mult(this.cv); // ----------------------------------- this.cummVec.add(this.alignVector); this.cummVec.add(this.separateVector); this.cummVec.add(this.cohesionVector); this.acc.add(this.cummVec); } } void separate(float searchRadius, float separateValue, List<Tracker> collection) { this.creeperCollection = collection; this.searchRad = searchRadius; this.sv = separateValue; this.otherPtsList = new ArrayList<PVector>(); this.otherMoveValues = new ArrayList<PVector>(); this.allDist = new ArrayList<Float>(); Sphere bs = new Sphere(new Vec3D(this.loc.x, this.loc.y, this.loc.z), this.searchRad); occTreeList = octree.getPointsWithinSphere(bs); if (occTreeList!=null) { if (occTreeList.size()!=50402030) { for (int i = 0; i < occTreeList.size(); i++) { int index = vec3DList.indexOf((Vec3D)occTreeList.get(i)); if (drawConn) { Vec3D tconv = new Vec3D((Vec3D)occTreeList.get(i)); PVector conv = new PVector(tconv.x, tconv.y, tconv.z); drawConnectivity(conv); } Tracker other = (Tracker) creeperCollection.get(index); float distance = this.loc.dist(other.loc); if (distance != 0) { this.otherPtsList.add(other.loc); this.allDist.add(distance); if (index != -1) { this.otherMoveValues.add(other.speed); } } } } } if (this.otherPtsList.size() > 0) { this.cummVec = new PVector(); // ----------Separate----------------- separateMethod(); if (this.separateVector.mag() > 0) { this.separateVector.normalize(); } this.separateVector.mult(this.sv); this.cummVec.add(this.separateVector); this.speed.add(this.cummVec); this.speed.normalize(); this.speed.mult(1.5f); } } void align(float searchRadius, float alignThreshold, List<Tracker> collection) { this.creeperCollection = collection; this.searchRad = searchRadius; this.av = alignThreshold; this.otherPtsList = new ArrayList<PVector>(); this.otherMoveValues = new ArrayList<PVector>(); this.allDist = new ArrayList<Float>(); Sphere bs = new Sphere(new Vec3D(this.loc.x, this.loc.y, this.loc.z), this.searchRad); occTreeList = octree.getPointsWithinSphere(bs); if (occTreeList!=null) { if (occTreeList.size()!=50402030) { for (int i = 0; i < occTreeList.size(); i++) { int index = vec3DList.indexOf((Vec3D)occTreeList.get(i)); if (drawConn) { Vec3D tconv = new Vec3D((Vec3D)occTreeList.get(i)); PVector conv = new PVector(tconv.x, tconv.y, tconv.z); drawConnectivity(conv); } Tracker other = (Tracker) creeperCollection.get(index); float distance = this.loc.dist(other.loc); if (distance != 0) { this.otherPtsList.add(other.loc); this.allDist.add(distance); if (index != -1) { this.otherMoveValues.add(other.speed); } } } } } if (this.otherPtsList.size() > 0) { this.cummVec = new PVector(); // ----------Align----------------- alignMethod(); if (this.alignVector.mag() > 0) { this.alignVector.normalize(); } this.alignVector.mult(this.av); // ----------------------------------- this.cummVec.add(this.alignVector); this.speed.add(this.cummVec); this.speed.normalize(); this.speed.mult(1.5f); } } void cohesion(float searchRadius, float cohesionValue, List<Tracker> collection) { this.creeperCollection = collection; this.searchRad = searchRadius; this.cv = cohesionValue; this.otherPtsList = new ArrayList<PVector>(); this.otherMoveValues = new ArrayList<PVector>(); this.allDist = new ArrayList<Float>(); Sphere bs = new Sphere(new Vec3D(this.loc.x, this.loc.y, this.loc.z), this.searchRad); occTreeList = octree.getPointsWithinSphere(bs); if (occTreeList!=null) { if (occTreeList.size()!=50402030) { for (int i = 0; i < occTreeList.size(); i++) { int index = vec3DList.indexOf((Vec3D)occTreeList.get(i)); if (drawConn) { Vec3D tconv = new Vec3D((Vec3D)occTreeList.get(i)); PVector conv = new PVector(tconv.x, tconv.y, tconv.z); drawConnectivity(conv); } Tracker other = (Tracker) creeperCollection.get(index); float distance = this.loc.dist(other.loc); if (distance != 0) { this.otherPtsList.add(other.loc); this.allDist.add(distance); if (index != -1) { this.otherMoveValues.add(other.speed); } } } } } if (this.otherPtsList.size() > 0) { this.cummVec = new PVector(); // ----------Cohesion----------------- cohesionMethod(); if (this.cohesionVector.mag() > 0) { this.cohesionVector.normalize(); } this.cohesionVector.mult(this.cv); // ----------------------------------- this.cummVec.add(this.cohesionVector); this.speed.add(this.cummVec); this.speed.normalize(); this.speed.mult(1.5f); } } void separateMethod() { this.separateVector = new PVector(); for (int i = 0; i < this.otherPtsList.size(); i++) { this.separateVector.add(PVector.mult(PVector.sub(this.loc, this.otherPtsList.get(i)), this.searchRad / this.allDist.get(i))); } } void alignMethod() { this.alignVector = new PVector(); for (int i = 0; i < this.otherPtsList.size(); i++) { this.alignVector.add(PVector.mult(this.otherMoveValues.get(i), this.searchRad / this.allDist.get(i))); } } void cohesionMethod() { this.cohesionVector = new PVector(); for (int i = 0; i < this.otherPtsList.size(); i++) { this.cohesionVector.add(this.otherPtsList.get(i)); } PVector scaleVec = PVector.mult(this.cohesionVector, (1.00f / this.otherPtsList.size())); float dist = this.loc.dist(scaleVec); this.cohesionVector = PVector.mult(PVector.sub(scaleVec, this.loc), this.searchRad / dist); } }