Vector3 UnitAiMoonGuard::chargeAtTarget(const WorldInterface& world, const PhysicsObjectId& target, const Vector3& orig_velocity) { if (!world.isAlive(target)) { return orig_velocity; } Vector3 unit_pos = getShip().getPosition(); Vector3 target_pos = world.getPosition(target); Vector3 target_forward = world.getForward(target); //Vector3 desired_velocity = steeringBehaviour->seek(world, target); Vector3 desired_velocity = steeringBehaviour->aim(world, target, Bullet::SPEED); //Vector3 desired_velocity = steeringBehaviour->escort(world, target, -target_forward * 50); Vector3 v = avoidPlanetoids(world, desired_velocity); //printf("\tRamming\n"); return v; }
Vector3 SteeringBehaviour :: calculateEscortPosition (const WorldInterface& world, const PhysicsObjectId& id_target, const Vector3& offset) const { assert(m_steering_behaviour == ESCORT); assert(id_target != PhysicsObjectId::ID_NOTHING); if(!world.isAlive(id_target)) return Vector3::ZERO; Vector3 target_position = world.getPosition(id_target); Vector3 target_forward = world.getForward (id_target); Vector3 target_up = world.getUp (id_target); Vector3 target_right = world.getRight (id_target); return target_position + target_forward * offset.x + target_up * offset.y + target_right * offset.z; }
// avoid only when going to collide Vector3 SteeringBehaviour :: avoid (const WorldInterface& world, const Vector3& original_velocity, const Vector3& sphere_center, double sphere_radius, double clearance, double avoid_distance) const { assert(sphere_radius >= 0.0); assert(clearance > 0.0); assert(clearance <= avoid_distance); if(!world.isAlive(m_id_agent) || original_velocity.isZero()) { assert(invariant()); return Vector3::ZERO; } Vector3 agent_position = world.getPosition(m_id_agent); double agent_radius = world.getRadius(m_id_agent); double desired_speed = world.getShipSpeedMax(m_id_agent); Vector3 relative_position = sphere_center - agent_position; double radius_sum = sphere_radius + agent_radius; if(relative_position.isNormGreaterThan(radius_sum + avoid_distance)) { if(DEBUGGING_AVOID) cout << "Avoid: Outside avoid distance" << endl; assert(invariant()); return original_velocity.getTruncated(desired_speed); // too far away to worry about } Vector3 agent_forward = world.getForward(m_id_agent); if(relative_position.dotProduct(agent_forward) < 0.0) { // past center of object; no cylinder if(DEBUGGING_AVOID) cout << "Avoid: Departing from object" << endl; if(relative_position.isNormLessThan(radius_sum + clearance)) { // we are too close, so flee and slow down double distance_fraction = (relative_position.getNorm() - radius_sum) / clearance; if(DEBUGGING_AVOID) cout << "\tInside panic distance: fraction = " << distance_fraction << endl; if(distance_fraction < 0.0) distance_fraction = 0.0; Vector3 interpolated = original_velocity.getNormalized() * distance_fraction + -relative_position.getNormalized() * (1.0 - distance_fraction); if(distance_fraction > AVOID_SPEED_FACTOR_MIN) desired_speed *= distance_fraction; else desired_speed *= AVOID_SPEED_FACTOR_MIN; if(original_velocity.isNormLessThan(desired_speed)) desired_speed = original_velocity.getNorm(); assert(invariant()); return interpolated.getCopyWithNorm(desired_speed); } else { if(DEBUGGING_AVOID) cout << "\tPast object" << endl; assert(invariant()); return original_velocity.getTruncated(desired_speed); // far enough past object } } else { // have not reached center of object; check against cylinder if(DEBUGGING_AVOID) cout << "Avoid: Approaching object" << endl; double distance_from_cylinder_center = relative_position.getAntiProjection(agent_forward).getNorm(); double clearance_fraction = (distance_from_cylinder_center - radius_sum) / clearance; if(DEBUGGING_AVOID) { cout << "\tTo sphere: " << relative_position << endl; cout << "\tDistance_from_cylinder_center: " << distance_from_cylinder_center << endl; cout << "\tRadius_sum: " << radius_sum << endl; cout << "\tClearance: " << clearance << endl; cout << "\tFraction: " << clearance_fraction << endl; } if(clearance_fraction < 0.0) { clearance_fraction = 0.0; if(DEBUGGING_AVOID) cout << "\tLined up at sphere" << endl; } if(clearance_fraction > 1.0) { if(DEBUGGING_AVOID) cout << "\tOutside cylinder" << endl; assert(invariant()); return original_velocity; // outside of danger cylinder } if(DEBUGGING_AVOID) cout << "\tModified fraction: " << clearance_fraction << endl; assert(!original_velocity.isZero()); assert(!agent_forward.isZero()); Vector3 sideways_vector = -relative_position.getAntiProjection(agent_forward); while(sideways_vector.isNormLessThan(AVOID_SIDEWAYS_NORM_MIN)) { // we have almost no sideways, so use a random value sideways_vector = Vector3::getRandomUnitVector().getAntiProjection(agent_forward); // keep trying until we get a good one } assert(!original_velocity.isZero()); assert(!sideways_vector.isZero()); assert(sideways_vector.isOrthogonal(agent_forward)); if(DEBUGGING_AVOID) cout << "\tSideways: " << sideways_vector << endl; Vector3 interpolated = original_velocity.getNormalized() * clearance_fraction + sideways_vector .getNormalized() * (1.0 - clearance_fraction); if(original_velocity.isNormLessThan(desired_speed)) desired_speed = original_velocity.getNorm(); if(DEBUGGING_AVOID) cout << "\tDodging out of cylinder: " << interpolated.getCopyWithNorm(desired_speed) << endl; assert(invariant()); return interpolated.getCopyWithNorm(desired_speed); } }