void UnitAiMoonGuard :: run (const WorldInterface& world) { assert(world.isAlive(getShipId())); scan(world); Vector3 v = getShip().getVelocity(); if (nearestEnemyShip != PhysicsObjectId::ID_NOTHING) { v = chargeAtTarget(world, nearestEnemyShip, v); shootAtShip(world, nearestEnemyShip); } else { Vector3 moon_pos = world.getPosition(moon); double moon_radius = world.getRadius(moon); v = steeringBehaviour->patrolSphere(world, moon_pos, moon_radius, PLANETOID_AVOID_DISTANCE); //printf("Patrolling...\n"); } v = avoidShips(world, v); v = avoidRingParticles(world, v); getShipAi().setDesiredVelocity(v); }
void UnitAiMoonGuard::patrolMoon(const WorldInterface& world, const PhysicsObjectId& moonID) { Vector3 planetoid_center = world.getPosition(moonID); double planetoid_radius = world.getRadius(moonID); Vector3 desired_velocity = m_steering_behaviour.patrolSphere(world, planetoid_center, planetoid_radius + PLANETOID_CLEARANCE, planetoid_radius + Const::SHELL_THICKNESS); Vector3 avoid_velocity = avoidPlanets(world, desired_velocity); avoid_velocity = avoidParticles(world, avoid_velocity); avoid_velocity = avoidShips(world, avoid_velocity); getShipAi().setDesiredVelocity(avoid_velocity); }
Vector3 UnitAiMoonGuard::avoidPlanets(const WorldInterface& world, const Vector3& originalVelocity) { PhysicsObjectId planetoid_id = world.getNearestPlanetoidId(getShip().getPosition()); Vector3 planetoid_center = world.getPosition(planetoid_id); double planetoid_radius = world.getRadius(planetoid_id); return m_steering_behaviour.avoid(world, originalVelocity, planetoid_center, planetoid_radius, PLANETOID_CLEARANCE, PLANETOID_AVOID_DISTANCE); }
Vector3 UnitAiMoonGuard::avoidPlanetoids(const WorldInterface &world, const Vector3& orig_velocity) { Vector3 planetoid_pos = world.getPosition(nearestPlanetoid); double planetoid_radius = world.getRadius(nearestPlanetoid); Vector3 v = steeringBehaviour->avoid(world, orig_velocity, planetoid_pos, planetoid_radius, PLANETOID_CLEARANCE, PLANETOID_AVOID_DISTANCE); //printf("Avoiding Planetoid\n"); return v; }
Vector3 UnitAiMoonGuard::avoidShips(const WorldInterface &world, const Vector3& orig_velocity) { if (nearestShip == PhysicsObjectId::ID_NOTHING || !world.isAlive(nearestShip) || nearestShip == nearestEnemyShip) { return orig_velocity; } Vector3 target_pos = world.getPosition(nearestShip); double target_radius = world.getRadius(nearestShip); Vector3 v = steeringBehaviour->avoid(world, orig_velocity, target_pos, target_radius, SHIP_CLEARANCE, SHIP_AVOID_DISTANCE); //printf("\tAvoiding Ships\n"); return v; }
// 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); } }