From 6c01c80bfa97fd5b9fb4610dc1eeaa400661f273 Mon Sep 17 00:00:00 2001 From: JH159753 Date: Tue, 27 Sep 2022 20:57:11 -0700 Subject: [PATCH 1/4] revert to my most recent change --- Boid.pde | 336 +++++++++++++++++++++++++------------------------------ 1 file changed, 155 insertions(+), 181 deletions(-) diff --git a/Boid.pde b/Boid.pde index 512e288..6bf7396 100644 --- a/Boid.pde +++ b/Boid.pde @@ -6,199 +6,173 @@ class Crumb PVector position; Crumb(PVector position) { - this.position = position; + this.position = position; } void draw() { - fill(255); - noStroke(); - circle(this.position.x, this.position.y, CRUMB_SIZE); + fill(255); + noStroke(); + circle(this.position.x, this.position.y, CRUMB_SIZE); } } class Boid { - Crumb[] crumbs = {}; - int last_crumb; - float acceleration; - float rotational_acceleration; - KinematicMovement kinematic; - PVector target; - - Boid(PVector position, float heading, float max_speed, float max_rotational_speed, float acceleration, float rotational_acceleration) - { - this.kinematic = new KinematicMovement(position, heading, max_speed, max_rotational_speed); - this.last_crumb = millis(); - this.acceleration = acceleration; - this.rotational_acceleration = rotational_acceleration; - } - - void update(float dt) - { - if (target != null) - { - // TODO: Implement seek here - - - //This makes a vector with the direction our boid needs to go to - PVector direction = PVector.sub(target, kinematic.position); - - //atan2(direction.y, direction.x) will return the direction we need to go in radians - - //print direction we need to go and the direction we are facing right now - //println(atan2(direction.y, direction.x) + " " + normalize_angle_left_right(kinematic.getHeading())); - - float directionalThreshold = .1; - float angleToTarget = normalize_angle_left_right(atan2(direction.y, direction.x) - normalize_angle_left_right(kinematic.getHeading())); - float arrivalThreshold = 60.0; - - //This just draws a circle for visual debugging purposes - circle(target.x, target.y, 3); - - //prints the angle to the target - //println(angleToTarget); - - //if the angle is larger than the threshold in the positive direction, rotate counterclockwise - if (angleToTarget >= .1) { - println("positive angle"); - kinematic.increaseSpeed(0.0, 2); - + Crumb[] crumbs = {}; + int last_crumb; + float acceleration; + float rotational_acceleration; + KinematicMovement kinematic; + PVector target; + + Boid(PVector position, float heading, float max_speed, float max_rotational_speed, float acceleration, float rotational_acceleration) + { + this.kinematic = new KinematicMovement(position, heading, max_speed, max_rotational_speed); + this.last_crumb = millis(); + this.acceleration = acceleration; + this.rotational_acceleration = rotational_acceleration; + } + void update(float dt) + { + if (target != null) + { + // TODO: Implement seek here + + + //This makes a vector with the direction our boid needs to go to + PVector direction = PVector.sub(target, kinematic.position); + + //atan2(direction.y, direction.x) will return the direction we need to go in radians + + //print direction we need to go and the direction we are facing right now + //println(atan2(direction.y, direction.x) + " " + normalize_angle_left_right(kinematic.getHeading())); + + float directionalThreshold = .1; + float angleToTarget = atan2(direction.y, direction.x) - normalize_angle_left_right(kinematic.getHeading()); + float arrivalThreshold = 60.0; + + //This just draws a circle for visual debugging purposes + circle(target.x, target.y, 3); + + //prints the angle to the target + //println(angleToTarget); + + //if the angle is larger than the threshold in the positive direction, rotate counterclockwise + //Need to rotate slower when the boid is closer to the target + + if (angleToTarget > directionalThreshold && direction.mag() > arrivalThreshold) { + kinematic.increaseSpeed(0.0, +1); + //if the angle is smaller than the threshold in the negative direction, rotate clockwise - } else if (angleToTarget < -.1) { - kinematic.increaseSpeed(0.0, -1); - - //if the angle is within our threshold, stop our rotational velocity by rotating opposite - } else if (directionalThreshold > angleToTarget) { - - if (kinematic.getRotationalVelocity() > 0) { + } else if (angleToTarget < -directionalThreshold && direction.mag() > arrivalThreshold) { kinematic.increaseSpeed(0.0, -1); - } else if (kinematic.getRotationalVelocity() < 0) { - kinematic.increaseSpeed(0.0, 1); - + + //if the angle is within our threshold, stop our rotational velocity by rotating opposite + } else if (directionalThreshold > angleToTarget) { + + if (kinematic.getRotationalVelocity() > 0) { + kinematic.increaseSpeed(0.0, -1); + } + else if (kinematic.getRotationalVelocity() < 0) { + kinematic.increaseSpeed(0.0, 1); + } } - } - - - - //Sometimes our Boid just goes and does weird things and I don't know why - - //if the target is outside its arrival threshold, accelerate. - //if the target is inside its arrival threshold, accelerate backwards until the speed is 0. - if (direction.mag() > arrivalThreshold) { - //println("main if"); - kinematic.increaseSpeed(.5, 0); - } else if (direction.mag() < arrivalThreshold) { - //Need more specific code here to handle arrivals correctly - - if (kinematic.getSpeed() < 40 && direction.mag() > 30) { - //println("if 1"); - kinematic.increaseSpeed(1, 0); - } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { - //println("if .75"); - kinematic.increaseSpeed(.75, 0); - } else if (kinematic.getSpeed() < 10 && direction.mag() > 5) { - //println("if .5"); - kinematic.increaseSpeed(.5, 0); - } else if (kinematic.getSpeed() < 5 && direction.mag() < 5) { - //println("if -kin"); - //This should ensure that the boid's speed can be dropped to exactly 0 so we don't have stuttering - - kinematic.increaseSpeed(-kinematic.getSpeed(), 0); - } else { - println("else"); - kinematic.increaseSpeed(-1, 0); + + + + //Sometimes our Boid just goes and does weird things and I don't know why + + //if the target is outside its arrival threshold, accelerate. + //if the target is inside its arrival threshold, accelerate backwards until the speed is 0. + if (direction.mag() > arrivalThreshold) { + kinematic.increaseSpeed(1,0); + } else if (direction.mag() < arrivalThreshold) { + //Need more specific code here to handle arrivals correctly + + if (kinematic.getSpeed() < 40 && direction.mag() > 30) { + kinematic.increaseSpeed(1,0); + } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { + kinematic.increaseSpeed(.75,0); + } else if (kinematic.getSpeed() < 10 && direction.mag() > 5) { + kinematic.increaseSpeed(.5,0); + } else if (kinematic.getSpeed() < 5 && direction.mag() < 5) { + //This should ensure that the boid's speed can be dropped to exactly 0 so we don't have stuttering + kinematic.increaseSpeed(-kinematic.getSpeed(),0); + } else { + kinematic.increaseSpeed(-1,0); + } + + } - } - - - - //drawing a line for testing purposes - //line(kinematic.position.x, kinematic.position.y, kinematic.position.x + direction.x, kinematic.position.y + direction.y); - } - - // place crumbs, do not change - if (LEAVE_CRUMBS && (millis() - this.last_crumb > CRUMB_INTERVAL)) - { - this.last_crumb = millis(); - this.crumbs = (Crumb[])append(this.crumbs, new Crumb(this.kinematic.position)); - if (this.crumbs.length > MAX_CRUMBS) - this.crumbs = (Crumb[])subset(this.crumbs, 1); - } - - // do not change - this.kinematic.update(dt); - - draw(); - } - - void draw() - { - for (Crumb c : this.crumbs) - { - c.draw(); - } - - fill(255); - noStroke(); - float x = kinematic.position.x; - float y = kinematic.position.y; - float r = kinematic.heading; - circle(x, y, BOID_SIZE); - // front - float xp = x + BOID_SIZE*cos(r); - float yp = y + BOID_SIZE*sin(r); - - // left - float x1p = x - (BOID_SIZE/2)*sin(r); - float y1p = y + (BOID_SIZE/2)*cos(r); - - // right - float x2p = x + (BOID_SIZE/2)*sin(r); - float y2p = y - (BOID_SIZE/2)*cos(r); - triangle(xp, yp, x1p, y1p, x2p, y2p); - } - - void seek(PVector target) - { - this.target = target; - } -int count = 0; - - //void follow(ArrayList waypoints) - //{ + + + + //drawing a line for testing purposes + //line(kinematic.position.x, kinematic.position.y, kinematic.position.x + direction.x, kinematic.position.y + direction.y); + + + + + + + + + + } - // //println("func count " + count); - // if(count > waypoints.size() - 1){ - // this.target = waypoints.get(0); - // return; - // } - // else { - // // TODO: change to follow *all* waypoints - // println("count " + count); - // this.target = waypoints.get(count); - // PVector temp = waypoints.remove(count); - // count++; - // //count--; - - // follow(waypoints); - // } - - //} - void follow(ArrayList waypoints) - { - int count = 0; - //this.target = waypoints.get(0); - do{ - - - print("in while"); - this.target = waypoints.get(count); - count++; - - }while(PVector.sub(this.target,this.kinematic.position).mag() < 40); - - - - } + // place crumbs, do not change + if (LEAVE_CRUMBS && (millis() - this.last_crumb > CRUMB_INTERVAL)) + { + this.last_crumb = millis(); + this.crumbs = (Crumb[])append(this.crumbs, new Crumb(this.kinematic.position)); + if (this.crumbs.length > MAX_CRUMBS) + this.crumbs = (Crumb[])subset(this.crumbs, 1); + } + + // do not change + this.kinematic.update(dt); + + draw(); + } + + void draw() + { + for (Crumb c : this.crumbs) + { + c.draw(); + } + + fill(255); + noStroke(); + float x = kinematic.position.x; + float y = kinematic.position.y; + float r = kinematic.heading; + circle(x, y, BOID_SIZE); + // front + float xp = x + BOID_SIZE*cos(r); + float yp = y + BOID_SIZE*sin(r); + + // left + float x1p = x - (BOID_SIZE/2)*sin(r); + float y1p = y + (BOID_SIZE/2)*cos(r); + + // right + float x2p = x + (BOID_SIZE/2)*sin(r); + float y2p = y - (BOID_SIZE/2)*cos(r); + triangle(xp, yp, x1p, y1p, x2p, y2p); + } + + void seek(PVector target) + { + this.target = target; + + } + + void follow(ArrayList waypoints) + { + // TODO: change to follow *all* waypoints + this.target = waypoints.get(0); + + } } From d5574b6cfdb6b4752aba15e6e7b25c23ffbcad06 Mon Sep 17 00:00:00 2001 From: JH159753 Date: Wed, 28 Sep 2022 01:22:40 -0700 Subject: [PATCH 2/4] add seeking multiple targets This version still slows down even if not necessary. --- Boid.pde | 59 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/Boid.pde b/Boid.pde index 6bf7396..4726d03 100644 --- a/Boid.pde +++ b/Boid.pde @@ -24,6 +24,10 @@ class Boid float rotational_acceleration; KinematicMovement kinematic; PVector target; + PVector direction; + ArrayList waypoints; + boolean stillInRadius = true; + int currentTarget = 0; Boid(PVector position, float heading, float max_speed, float max_rotational_speed, float acceleration, float rotational_acceleration) { @@ -39,7 +43,6 @@ class Boid { // TODO: Implement seek here - //This makes a vector with the direction our boid needs to go to PVector direction = PVector.sub(target, kinematic.position); @@ -49,7 +52,8 @@ class Boid //println(atan2(direction.y, direction.x) + " " + normalize_angle_left_right(kinematic.getHeading())); float directionalThreshold = .1; - float angleToTarget = atan2(direction.y, direction.x) - normalize_angle_left_right(kinematic.getHeading()); + //You have to normalize this too or the boid goes the wrong way sometimes + float angleToTarget = normalize_angle_left_right(atan2(direction.y, direction.x) - normalize_angle_left_right(kinematic.getHeading())); float arrivalThreshold = 60.0; //This just draws a circle for visual debugging purposes @@ -59,29 +63,32 @@ class Boid //println(angleToTarget); //if the angle is larger than the threshold in the positive direction, rotate counterclockwise - //Need to rotate slower when the boid is closer to the target - - if (angleToTarget > directionalThreshold && direction.mag() > arrivalThreshold) { + if (angleToTarget > directionalThreshold && direction.mag() > 30) { kinematic.increaseSpeed(0.0, +1); + } else if (angleToTarget > directionalThreshold && direction.mag() > 15) { + kinematic.increaseSpeed(0.0, +.5); + //if the angle is smaller than the threshold in the negative direction, rotate clockwise - } else if (angleToTarget < -directionalThreshold && direction.mag() > arrivalThreshold) { + } else if (angleToTarget < -directionalThreshold && direction.mag() > 30) { kinematic.increaseSpeed(0.0, -1); + } else if (angleToTarget < -directionalThreshold && direction.mag() > 15) { + kinematic.increaseSpeed(0.0, -.5); + //if the angle is within our threshold, stop our rotational velocity by rotating opposite } else if (directionalThreshold > angleToTarget) { if (kinematic.getRotationalVelocity() > 0) { - kinematic.increaseSpeed(0.0, -1); + kinematic.increaseSpeed(0.0, -kinematic.getRotationalVelocity()); } else if (kinematic.getRotationalVelocity() < 0) { - kinematic.increaseSpeed(0.0, 1); + kinematic.increaseSpeed(0.0, kinematic.getRotationalVelocity()); } } - //Sometimes our Boid just goes and does weird things and I don't know why //if the target is outside its arrival threshold, accelerate. //if the target is inside its arrival threshold, accelerate backwards until the speed is 0. @@ -111,6 +118,27 @@ class Boid //drawing a line for testing purposes //line(kinematic.position.x, kinematic.position.y, kinematic.position.x + direction.x, kinematic.position.y + direction.y); + //handling going to multiple targets + + //If within 5 units, move to next target + if (direction.mag() < 5) { + //This ensures that the same target can't trigger moving to the next target twice + if (stillInRadius == false) { + //this ensures that waypoints get cleared after finishing checking all targets + if (currentTarget < waypoints.size() - 1) { + currentTarget++; + } else { + currentTarget = 0; + waypoints = null; + } + } + stillInRadius = true; + if (waypoints != null) { + seek(waypoints.get(currentTarget)); + } + } else { + stillInRadius = false; + } @@ -166,13 +194,22 @@ class Boid void seek(PVector target) { this.target = target; - + println("seeking"); } void follow(ArrayList waypoints) { // TODO: change to follow *all* waypoints - this.target = waypoints.get(0); + + this.waypoints = waypoints; + + seek(waypoints.get(0)); + + + + + + } } From a460deb7ca94b868058a18ec80ca4368325b156d Mon Sep 17 00:00:00 2001 From: JH159753 Date: Wed, 28 Sep 2022 02:07:57 -0700 Subject: [PATCH 3/4] progress towards smoother boid movement --- Boid.pde | 115 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 29 deletions(-) diff --git a/Boid.pde b/Boid.pde index 4726d03..c4ab348 100644 --- a/Boid.pde +++ b/Boid.pde @@ -94,22 +94,74 @@ class Boid //if the target is inside its arrival threshold, accelerate backwards until the speed is 0. if (direction.mag() > arrivalThreshold) { kinematic.increaseSpeed(1,0); + } else if (direction.mag() < arrivalThreshold) { + + //Need more specific code here to handle arrivals correctly + //TODO: change this to slow down less / not at all if the angle to the next target is not large + + //This handles starting / stopping if there are more targets + + //This ensures that we don't crash because waypoints is null + if (waypoints != null) { + + //this checks if there's another target to go to + if (currentTarget + 1 < waypoints.size()) { + + //if so, change the speed depending on the angle to the next target + //This part isn't really implemented at all, and I need sleep + + if (kinematic.getSpeed() < 40 && direction.mag() > 30) { + kinematic.increaseSpeed(1,0); + } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { + kinematic.increaseSpeed(.75,0); + } else if (kinematic.getSpeed() < 10 && direction.mag() > 5) { + kinematic.increaseSpeed(.5,0); + } else if (kinematic.getSpeed() < 5 && direction.mag() < 5) { + //This should ensure that the boid's speed can be dropped to exactly 0 so we don't have stuttering + kinematic.increaseSpeed(-kinematic.getSpeed(),0); + } else { + kinematic.increaseSpeed(-1,0); + } + + } else { + + //if no more targets to check, do the normal calculation + if (kinematic.getSpeed() < 40 && direction.mag() > 30) { + kinematic.increaseSpeed(1,0); + } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { + kinematic.increaseSpeed(.75,0); + } else if (kinematic.getSpeed() < 10 && direction.mag() > 5) { + kinematic.increaseSpeed(.5,0); + } else if (kinematic.getSpeed() < 5 && direction.mag() < 5) { + //This should ensure that the boid's speed can be dropped to exactly 0 so we don't have stuttering + kinematic.increaseSpeed(-kinematic.getSpeed(),0); + } else { + kinematic.increaseSpeed(-1,0); + } + + } - if (kinematic.getSpeed() < 40 && direction.mag() > 30) { - kinematic.increaseSpeed(1,0); - } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { - kinematic.increaseSpeed(.75,0); - } else if (kinematic.getSpeed() < 10 && direction.mag() > 5) { - kinematic.increaseSpeed(.5,0); - } else if (kinematic.getSpeed() < 5 && direction.mag() < 5) { - //This should ensure that the boid's speed can be dropped to exactly 0 so we don't have stuttering - kinematic.increaseSpeed(-kinematic.getSpeed(),0); } else { - kinematic.increaseSpeed(-1,0); - } + //if waypoints is null, do normal things + println("waypoints is null"); + //This code should trigger if there's only one target left + if (kinematic.getSpeed() < 40 && direction.mag() > 30) { + kinematic.increaseSpeed(1,0); + } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { + kinematic.increaseSpeed(.75,0); + } else if (kinematic.getSpeed() < 10 && direction.mag() > 5) { + kinematic.increaseSpeed(.5,0); + } else if (kinematic.getSpeed() < 5 && direction.mag() < 5) { + //This should ensure that the boid's speed can be dropped to exactly 0 so we don't have stuttering + kinematic.increaseSpeed(-kinematic.getSpeed(),0); + } else { + kinematic.increaseSpeed(-1,0); + } + + } } @@ -120,24 +172,28 @@ class Boid //handling going to multiple targets - //If within 5 units, move to next target - if (direction.mag() < 5) { - //This ensures that the same target can't trigger moving to the next target twice - if (stillInRadius == false) { - //this ensures that waypoints get cleared after finishing checking all targets - if (currentTarget < waypoints.size() - 1) { - currentTarget++; - } else { - currentTarget = 0; - waypoints = null; + //initial check exists because waypoints will be null for a single target + if (waypoints != null) { + //If within 5 units, move to next target + if (direction.mag() < 5) { + //This ensures that the same target can't trigger moving to the next target twice + if (stillInRadius == false) { + //this ensures that waypoints get cleared after finishing checking all targets + if (currentTarget < waypoints.size() - 1) { + currentTarget++; + } else { + currentTarget = 0; + waypoints = null; + } } + stillInRadius = true; + if (waypoints != null) { + seek(waypoints.get(currentTarget)); + } + } else { + stillInRadius = false; } - stillInRadius = true; - if (waypoints != null) { - seek(waypoints.get(currentTarget)); - } - } else { - stillInRadius = false; + } @@ -147,6 +203,8 @@ class Boid + + } // place crumbs, do not change @@ -194,12 +252,11 @@ class Boid void seek(PVector target) { this.target = target; - println("seeking"); + } void follow(ArrayList waypoints) { - // TODO: change to follow *all* waypoints this.waypoints = waypoints; From 3d16b646a807cb7a2384072f4c267c5888644f96 Mon Sep 17 00:00:00 2001 From: JH159753 Date: Sat, 29 Oct 2022 03:27:49 -0700 Subject: [PATCH 4/4] add dynamic slowdown dependent on angle The boid will now slow down less if the angle created by the line from it to its target and the line from the target to the next one is nearly a straight line. --- Boid.pde | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Boid.pde b/Boid.pde index c4ab348..9c55d06 100644 --- a/Boid.pde +++ b/Boid.pde @@ -112,6 +112,36 @@ class Boid //if so, change the speed depending on the angle to the next target //This part isn't really implemented at all, and I need sleep + //We can calculate the angle to the next target with the use of two vectors: one from our location to current target, one from current target to next target + //use the dot product of those two vectors; this gives us the angle between them, and we can use that to calculate how much we should slow down + + //direction is our boid to target vector + //this is at direction + //current target to next target is here: + PVector currentTargetToNext = PVector.sub(waypoints.get(currentTarget+1), target); + + //i'm not sure this is the best way to do this, it might be simpler to calculate the angle, but this should work too + + //holds dot product of targets + float dotProductOfTargets = PVector.dot(currentTargetToNext, direction); + + //Dividing by both their magnitudes will normalize our result between -1 and 1 + dotProductOfTargets = dotProductOfTargets / (currentTargetToNext.mag() * direction.mag()); + + //Add 1, divide by 2, this will cause our result to be between 0 and 1 + //If this is closer to 0, slow down more. If it's closer to 1, slow down less. + dotProductOfTargets = (dotProductOfTargets + 1) / 2; + + //use an ideal speed for our boid, to tell it to either speed up or slow down whether it's going faster than this or not + float idealSpeed = dotProductOfTargets * 20 + 10; + + if (kinematic.getSpeed() < idealSpeed) { + kinematic.increaseSpeed(1,0); + } else if (kinematic.getSpeed() > idealSpeed) { + kinematic.increaseSpeed(-1,0); + } + + /* if (kinematic.getSpeed() < 40 && direction.mag() > 30) { kinematic.increaseSpeed(1,0); } else if (kinematic.getSpeed() < 20 && direction.mag() > 15) { @@ -124,6 +154,7 @@ class Boid } else { kinematic.increaseSpeed(-1,0); } + */ } else {