float3 OpenSteer::SteerLibrary:: steerForWander (const AbstractVehicle& v, float dt) { // random walk WanderSide and WanderUp between -1 and +1 const float speed = 12 * dt; // maybe this (12) should be an argument? WanderSide = scalarRandomWalk (WanderSide, speed, -1, +1); WanderUp = scalarRandomWalk (WanderUp, speed, -1, +1); // return a pure lateral steering vector: (+/-Side) + (+/-Up) return float3_add(float3_scalar_multiply(v.side(), WanderSide), float3_scalar_multiply(v.up(), WanderUp)); }
OpenSteer::Vec3 OpenSteer::Obstacle::PathIntersection:: steerToAvoidIfNeeded (const AbstractVehicle& vehicle, const float minTimeToCollision) const { // if nearby intersection found, steer away from it, otherwise no steering const float minDistanceToCollision = minTimeToCollision * vehicle.speed(); if (intersect && (distance < minDistanceToCollision)) { // compute avoidance steering force: take the component of // steerHint which is lateral (perpendicular to vehicle's // forward direction), set its length to vehicle's maxForce Vec3 lateral = steerHint.perpendicularComponent (vehicle.forward ()); if (lateral == Vec3::zero) lateral = vehicle.side (); return lateral.normalize () * vehicle.maxForce (); } else { return Vec3::zero; } }
float3 OpenSteer::SteerLibrary:: steerToAvoidNeighbors (const AbstractVehicle& v, const float minTimeToCollision, const AVGroup& others) { // first priority is to prevent immediate interpenetration const float3 separation = steerToAvoidCloseNeighbors (v, 0, others); if (!float3_equals(separation, float3_zero())) return separation; // otherwise, go on to consider potential future collisions float steer = 0; AbstractVehicle* threat = NULL; // Time (in seconds) until the most immediate collision threat found // so far. Initial value is a threshold: don't look more than this // many frames into the future. float minTime = minTimeToCollision; // xxx solely for annotation float3 xxxThreatPositionAtNearestApproach; float3 xxxOurPositionAtNearestApproach; // for each of the other vehicles, determine which (if any) // pose the most immediate threat of collision. for (AVIterator i = others.begin(); i != others.end(); i++) { AbstractVehicle& other = **i; if (&other != &v) { // avoid when future positions are this close (or less) const float collisionDangerThreshold = v.radius() * 2; // predicted time until nearest approach of "this" and "other" const float time = predictNearestApproachTime (v, other); // If the time is in the future, sooner than any other // threatened collision... if ((time >= 0) && (time < minTime)) { // if the two will be close enough to collide, // make a note of it if (computeNearestApproachPositions (v, other, time) < collisionDangerThreshold) { minTime = time; threat = &other; xxxThreatPositionAtNearestApproach = hisPositionAtNearestApproach; xxxOurPositionAtNearestApproach = ourPositionAtNearestApproach; } } } } // if a potential collision was found, compute steering to avoid if (threat != NULL) { // parallel: +1, perpendicular: 0, anti-parallel: -1 float parallelness = float3_dot(make_float3(v.forward()), make_float3(threat->forward())); float angle = 0.707f; if (parallelness < -angle) { // anti-parallel "head on" paths: // steer away from future threat position float3 offset = float3_subtract(xxxThreatPositionAtNearestApproach, make_float3(v.position())); float sideDot = float3_dot(offset, v.side()); steer = (sideDot > 0) ? -1.0f : 1.0f; } else { if (parallelness > angle) { // parallel paths: steer away from threat float3 offset = float3_subtract(make_float3(threat->position()), make_float3(v.position())); float sideDot = float3_dot(offset, v.side()); steer = (sideDot > 0) ? -1.0f : 1.0f; } else { // perpendicular paths: steer behind threat // (only the slower of the two does this) if (threat->speed() <= v.speed()) { float sideDot = float3_dot(v.side(), threat->velocity()); steer = (sideDot > 0) ? -1.0f : 1.0f; } } } annotateAvoidNeighbor (*threat, steer, xxxOurPositionAtNearestApproach, xxxThreatPositionAtNearestApproach); } return float3_scalar_multiply(v.side(), steer); }