float3 OpenSteer::SteerLibrary:: steerForEvasion (const AbstractVehicle& v, const AbstractVehicle& menace, const float maxPredictionTime) { // offset from this to menace, that distance, unit vector toward menace const float3 offset = float3_subtract(make_float3(menace.position()), make_float3(v.position())); const float distance = float3_length(offset); const float roughTime = distance / menace.speed(); const float predictionTime = ((roughTime > maxPredictionTime) ? maxPredictionTime : roughTime); const float3 target = menace.predictFuturePosition (predictionTime); return steerForFlee (v, target); }
OpenSteer::Vec3 CombatFighter::Steer() { static bool once = true; if (once && Stats().m_type == BOMBER && m_leader) { //m_instrument = true; once = false; } // A note about obstacle avoidance. Avoidance of static obstacles (planets, // asteroid fields, etc.) are represented in static_obstacle_avoidance. The // analogous avoidance of dynamic obstacles (ships, etc.) -- that is, an // overriding move away from an object that the fighter is about to collide // with -- is represented in dynamic_obstacle_avoidance. Another object // avoidance factor exists, nonfighter_obstacle_evasion_vec, but it works a // bit differently from the other two. It provides a distance-variable // force moving the fighter away, but does not get treated as the only // movement force if it exists (as static_obstacle_avoidance and // dynamic_obstacle_avoidance do). Instead, it is just one of the many // forces moving the fighter, along with steering towards mission objectives // and away from PD, etc. const float OBSTACLE_AVOIDANCE_TIME = 1.0; const OpenSteer::Vec3 static_obstacle_avoidance = steerToAvoidObstacles(OBSTACLE_AVOIDANCE_TIME, m_pathing_engine->Obstacles().begin(), m_pathing_engine->Obstacles().end()); if (static_obstacle_avoidance != OpenSteer::Vec3::zero) return static_obstacle_avoidance; const float SEPARATION_RADIUS = 5.0f; const float SEPARATION_ANGLE = -0.707f; const float SEPARATION_WEIGHT = 6.0f; const float ALIGNMENT_RADIUS = 7.5f; const float ALIGNMENT_ANGLE = 0.7f; const float ALIGNMENT_WEIGHT = 6.0f; const float COHESION_RADIUS = 9.0f; const float COHESION_ANGLE = -0.15f; const float COHESION_WEIGHT = 4.0f; const float FORMATION_WEIGHT = 8.0f; const float BOMBER_INTERCEPTOR_EVASION_RADIUS = Stats().m_type == BOMBER ? 25.0f : SEPARATION_RADIUS; const float BOMBER_INTERCEPTOR_EVASION_WEIGHT = 8.0f; const float NONFIGHTER_OBSTACLE_AVOIDANCE_RADIUS = 10.0; const float NONFIGHTER_OBSTACLE_AVOIDANCE_WEIGHT = 10.0; const float POINT_DEFENSE_AVOIDANCE_RADIUS = MAX_POINT_DEFENSE_RANGE * 1.5; const float POINT_DEFENSE_AVOIDANCE_WEIGHT = 8.0; // The leader (a "fake" fighter that the real fighters in a formation // follow) takes into account all other ("fake") fighters in proximity. // Followers ("real", or "normal" fighters) only consider its fellow // formation-mates its neighbors. OpenSteer::AVGroup neighbors; OpenSteer::AVGroup nonfighters; if (m_leader) { const float FIGHTER_RADIUS = std::max(SEPARATION_RADIUS, std::max(ALIGNMENT_RADIUS, COHESION_RADIUS)); const float NONFIGHTER_RADIUS = std::max(NONFIGHTER_OBSTACLE_AVOIDANCE_RADIUS, POINT_DEFENSE_AVOIDANCE_RADIUS); m_pathing_engine->GetProximityDB().FindInRadius( position(), FIGHTER_RADIUS, neighbors, FIGHTER_FLAGS, EmpireFlag(m_empire_id)); m_pathing_engine->GetProximityDB().FindInRadius( position(), NONFIGHTER_RADIUS, nonfighters, NONFIGHTER_FLAGS); } else { for (CombatFighterFormation::const_iterator it = m_formation->begin(); it != m_formation->end(); ++it) { CombatFighterPtr fighter = *it; if (fighter->m_formation_position != m_formation_position) neighbors.push_back(fighter.get()); } } // steer towards mission objectives OpenSteer::Vec3 mission_vec; if (m_leader && m_mission_weight) mission_vec = (m_mission_destination - position()).normalize(); // steer to maintain formation OpenSteer::Vec3 formation_vec; m_out_of_formation = OpenSteer::Vec3(); if (!m_leader) { m_out_of_formation = GlobalFormationPosition() - position(); formation_vec = m_out_of_formation.normalize(); } // steer to avoid interceptors (bombers only) OpenSteer::Vec3 bomber_interceptor_evasion_vec; OpenSteer::AVGroup interceptor_neighbors; if (Stats().m_type == BOMBER) { m_pathing_engine->GetProximityDB().FindInRadius( position(), BOMBER_INTERCEPTOR_EVASION_RADIUS, interceptor_neighbors, INTERCEPTOR_FLAG, EnemyOfEmpireFlags(m_empire_id)); OpenSteer::Vec3 direction; for (std::size_t i = 0; i < interceptor_neighbors.size(); ++i) { direction += steerForFlee(interceptor_neighbors[i]->position()); } bomber_interceptor_evasion_vec = direction.normalize(); } // See note at top of function for partial explanation of these variables' // meanings. OpenSteer::Vec3 nonfighter_obstacle_evasion_vec; OpenSteer::Vec3 point_defense_evasion_vec; OpenSteer::Vec3 dynamic_obstacle_avoidance; if (m_leader) { for (std::size_t i = 0; i < nonfighters.size(); ++i) { // TODO: Add code to handle non-ships as necessary. CombatShip* ship = boost::polymorphic_downcast<CombatShip*>(nonfighters[i]); // handle PD avoidance OpenSteer::Vec3 away_vec = position() - ship->position(); float away_vec_length = away_vec.length(); away_vec /= away_vec_length; point_defense_evasion_vec += away_vec * ship->AntiFighterStrength(); float collision_avoidance_scale_factor = std::max(0.0f, NONFIGHTER_OBSTACLE_AVOIDANCE_RADIUS - away_vec_length) / NONFIGHTER_OBSTACLE_AVOIDANCE_RADIUS; nonfighter_obstacle_evasion_vec += away_vec * collision_avoidance_scale_factor; if (OBSTACLE_AVOIDANCE_TIME * speed() < away_vec_length) dynamic_obstacle_avoidance += away_vec; } nonfighter_obstacle_evasion_vec = nonfighter_obstacle_evasion_vec.normalize(); point_defense_evasion_vec = point_defense_evasion_vec.normalize(); dynamic_obstacle_avoidance = dynamic_obstacle_avoidance.normalize(); } if (0.0 < dynamic_obstacle_avoidance.lengthSquared()) return dynamic_obstacle_avoidance; // flocking behaviors OpenSteer::AVGroup neighbors_to_use; if (m_leader) { neighbors_to_use.reserve(neighbors.size()); for (std::size_t i = 0; i < neighbors.size(); ++i) { CombatFighter* fighter = boost::polymorphic_downcast<CombatFighter*>(neighbors[i]); // exclude self and formation-mates from list if (fighter == this || &fighter->m_formation->Leader() == this) continue; neighbors_to_use.push_back(neighbors[i]); } } else { std::swap(neighbors, neighbors_to_use); } const OpenSteer::Vec3 separation_vec = steerForSeparation(SEPARATION_RADIUS, SEPARATION_ANGLE, neighbors_to_use); const OpenSteer::Vec3 alignment_vec = steerForAlignment(ALIGNMENT_RADIUS, ALIGNMENT_ANGLE, neighbors_to_use); const OpenSteer::Vec3 cohesion_vec = steerForCohesion(COHESION_RADIUS, COHESION_ANGLE, neighbors_to_use); return mission_vec * m_mission_weight + formation_vec * FORMATION_WEIGHT + bomber_interceptor_evasion_vec * BOMBER_INTERCEPTOR_EVASION_WEIGHT + nonfighter_obstacle_evasion_vec * NONFIGHTER_OBSTACLE_AVOIDANCE_WEIGHT + point_defense_evasion_vec * POINT_DEFENSE_AVOIDANCE_WEIGHT + separation_vec * SEPARATION_WEIGHT + alignment_vec * ALIGNMENT_WEIGHT + cohesion_vec * COHESION_WEIGHT; }
Vector3 SteeringVehicle::calcFlee(const Vector3& target) { Vector3 steering = Vec3Utils::setYtoZero(steerForFlee(target)); return steering; }