//Cohesion produces a steering force that moves a vehicle toward the center of mass of its neighbors //A sheep running after its flock is demonstrating cohesive behavior. Use this force to keep a group of vehicles together. public static Vector2 Cohesion(ref Vehicle[] allCars, Vehicle me, Vector2 currentPosition, Vector2 velocity, int max_speed, int cohesionRadius) { int j = 0; Vector2 averagePosition = Vector2.Zero; Vector2 distance = Vector2.Zero; for (int i = 0; i < allCars.Length; i++) { distance = Vector2.Subtract(currentPosition, allCars[i].CurrentPosition); if (VectorHelpers.Length(distance) < cohesionRadius && allCars[i] != me) { j++; averagePosition = Vector2.Add(averagePosition, allCars[i].CurrentPosition); } } if (j == 0) { return(Vector2.Zero); } else { averagePosition = averagePosition / j; return(Seek(ref averagePosition, ref currentPosition, ref velocity, max_speed)); } }
//Alignment attempts to keep a vehicle's heading aligned with its neighbors //The force is calculated by first iterating through all the neighbors and averaging their heading vectors. //This value is the desired heading, so we just subtract the vehicle's heading to get the steering force. public static Vector2 Alignment(ref Vehicle[] allCars, Vehicle me, ref Vector2 currentPosition, ref Vector2 velocity, int max_speed) { int j = 0; Vector2 averageDirection = new Vector2(0); Vector2 distance = new Vector2(0); for (int i = 0; i < allCars.Length; i++) { distance = Vector2.Subtract(currentPosition, allCars[i].CurrentPosition); if (VectorHelpers.Length(distance) < 100 && allCars[i] != me) { j++; averageDirection = Vector2.Add(averageDirection, allCars[i].Velocity); } } if (j == 0) { return(Vector2.Zero); } else { averageDirection = averageDirection / j; return(Vector2.Subtract(averageDirection, velocity)); } }
//Separation creates a force that steers a vehicle away from those in its neighborhood region. //When applied to a number of vehicles, they will spread out, trying to maximize their distance from every other vehicle public static Vector2 Separation(ref Vehicle[] allCars, Vehicle me, ref Vector2 currentPosition, ref Vector2 velocity, int max_speed) { int j = 0; Vector2 separationForce = new Vector2(0); Vector2 averageDirection = new Vector2(0); Vector2 distance = new Vector2(0); for (int i = 0; i < allCars.Length; i++) { distance = Vector2.Subtract(currentPosition, allCars[i].CurrentPosition); if (VectorHelpers.Length(distance) < 100 && allCars[i] != me) { j++; separationForce += Vector2.Subtract(currentPosition, allCars[i].CurrentPosition); separationForce = Vector2.Normalize(separationForce); separationForce = Vector2.Multiply(separationForce, 1 / .7f); averageDirection = Vector2.Add(averageDirection, separationForce); } } if (j == 0) { return(Vector2.Zero); } else { //averageDirection = averageDirection / j; return(averageDirection); } }
//Flee is the opposite of seek. Instead of producing a steering force to steer the agent toward a target position, flee creates a force that steers the agent away. public static Vector2 Flee(ref Vector2 targetPosition, ref Vector2 currentPosition, ref Vector2 Velocity, int max_speed, int FOV, int vehicleNo) { if (VectorHelpers.Length(Vector2.Subtract(targetPosition, currentPosition)) > FOV) { return(Vector2.Zero); } Vector2 desired_V = Vector2.Normalize(Vector2.Subtract(currentPosition, targetPosition)) * max_speed; return(Vector2.Subtract(desired_V, Velocity)); }
//=========================================================// //calculate force and update position private void UpdatePosition(ref Vector2 targetPosition) { heading = Vector2.Normalize(velocity); switch (SB) { case SB.None: steerForce = Vector2.Zero; break; case SB.Seek: steerForce = SteeringBehaviours.Seek(ref targetPosition, ref currentPosition, ref velocity, max_speed); break; case SB.Flee: steerForce = SteeringBehaviours.Flee(ref targetPosition, ref currentPosition, ref velocity, max_speed, FOV, vehicleNo); break; case SB.Arrive: steerForce = SteeringBehaviours.Arrive(ref targetPosition, ref currentPosition, ref velocity, ArriveRadius, max_speed, vehicleNo); break; case SB.Pursuit: break; case SB.Evade: break; case SB.Wander: steerForce = SteeringBehaviours.Wander(ref wanderTarget, ref currentPosition, ref velocity, ref heading, WanderRadius, WanderDistance, WanderJitter); break; case SB.PathFollowing: if (!enableSpecialPath) { steerForce = SteeringBehaviours.PathFollowing(ref targetPosition, ref currentPosition, ref velocity, ref pathPoints, ref currentPathPoint, maxPathPoints, max_speed); } else { steerForce = SteeringBehaviours.PathFollowing(ref targetPosition, ref currentPosition, ref velocity, ref specialPathPoints, ref currentPathPoint, maxSpecialPathPoints, max_speed); } break; case SB.Cohesion: steerForce = SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius); break; case SB.Alignment: steerForce = SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed); break; case SB.Separation: steerForce = SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed); break; case SB.CF: steerForce = Vector2.Add(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), SteeringBehaviours.Flee(ref targetPosition, ref currentPosition, ref velocity, max_speed, FOV, vehicleNo)); break; case SB.CA: if (weightedSum) { steerForce += Vector2.Multiply(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), .2f); steerForce += Vector2.Multiply(SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed), .1f); } else { steerForce = Vector2.Add(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed)); } break; case SB.CAS: if (weightedSum) { steerForce = Vector2.Add(SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed), Vector2.Add(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed))); } else { steerForce = Vector2.Multiply(SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed), .3f); steerForce += Vector2.Multiply(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), .2f); steerForce += Vector2.Multiply(SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed), .5f); } break; case SB.CS: if (weightedSum) { steerForce = Vector2.Add(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed)); } else { steerForce = Vector2.Multiply(SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed), .8f); steerForce += Vector2.Multiply(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), .2f); } break; case SB.FCAS: if (weightedSum) { steerForce = Vector2.Add(SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed), Vector2.Add(SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed), Vector2.Add(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), SteeringBehaviours.Flee(ref targetPosition, ref currentPosition, ref velocity, max_speed, FOV, vehicleNo)))); } else { steerForce = Vector2.Multiply(SteeringBehaviours.Flee(ref targetPosition, ref currentPosition, ref velocity, max_speed, FOV, vehicleNo), .4f); steerForce += Vector2.Multiply(SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed), .3f); steerForce += Vector2.Multiply(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), .2f); steerForce += Vector2.Multiply(SteeringBehaviours.Alignment(ref allCars, this, ref currentPosition, ref velocity, max_speed), .5f); } break; case SB.FCS: steerForce = Vector2.Add(SteeringBehaviours.Separation(ref allCars, this, ref currentPosition, ref velocity, max_speed), Vector2.Add(SteeringBehaviours.Cohesion(ref allCars, this, currentPosition, velocity, max_speed, CohesionRadius), SteeringBehaviours.Flee(ref targetPosition, ref currentPosition, ref velocity, max_speed, FOV, vehicleNo))); break; default: break; } steerForce = VectorHelpers.Truncate(steerForce, max_force); acceleration = steerForce / mass; velocity = VectorHelpers.Truncate(velocity + acceleration, max_speed); currentPosition = Vector2.Add(velocity, currentPosition); var mirrored = true; if (!mirrored) { if (currentPosition.X > clientSize.Width) { currentPosition.X = 0; } if (currentPosition.Y > clientSize.Height) { currentPosition.Y = 0; } if (currentPosition.X < 0) { currentPosition.X = clientSize.Width; } if (currentPosition.Y < 0) { currentPosition.Y = clientSize.Height; } } else { if (currentPosition.X > clientSize.Width) { velocity.X *= -1; } if (currentPosition.Y > clientSize.Height) { velocity.Y *= -1; } if (currentPosition.X < 0) { velocity.X *= -1; } ; if (currentPosition.Y < 0) { velocity.Y *= -1; } ; } currentPosition = new Vector2(MathHelper.Clamp(currentPosition.X, 0, clientSize.Width), MathHelper.Clamp(currentPosition.Y, 0, clientSize.Height)); targetChanged = false; }