Vector3 SteeringBehaviour :: escort (const WorldInterface& world, const PhysicsObjectId& id_target, const Vector3& offset) { assert(id_target != PhysicsObjectId::ID_NOTHING); // no initialization needed m_steering_behaviour = ESCORT; // // This is a variation on the arrive steering behaviour. // First we work out the desired position from the // offset. Then we arrive at that position. Finally we // add on the velocity of the target and truncate to our // maximum speed. // // A more sophisticated implementation would use a form of // arrive based on pursue instead of seek. Or maybe this // already happens; I'm not sure. In either case, // slowing down for arrival messes up time predictions. // if(!world.isAlive(m_id_agent) || !world.isAlive( id_target)) { assert(invariant()); return Vector3::ZERO; } assert(world.isAlive(m_id_agent )); assert(world.isAlive( id_target)); Vector3 agent_position = world.getPosition(m_id_agent); Vector3 target_velocity = world.getVelocity( id_target); Vector3 escort_position = calculateEscortPosition(world, id_target, offset); if(agent_position == escort_position) { // we are in the correct position, so just match speeds assert(invariant()); return target_velocity; } double agent_speed_max = world.getShipSpeedMax(m_id_agent); assert(agent_speed_max >= 0.0); double agent_acceleration = world.getShipSpeedMax(m_id_agent); assert(agent_acceleration >= 0.0); double current_distance = agent_position.getDistance(escort_position); double desired_relative_speed = calculateMaxSafeSpeed(current_distance, agent_acceleration); Vector3 desired_relative_velocity = (escort_position - agent_position).getCopyWithNorm(desired_relative_speed); Vector3 desired_agent_velocity = desired_relative_velocity + target_velocity; // limit desired velocity to maximum speed assert(invariant()); return desired_agent_velocity.getTruncated(agent_speed_max); }
void UnitAiMoonGuard::steerToTargetAndShoot(const WorldInterface& world) { assert(m_id_target != PhysicsObjectId::ID_NOTHING); assert(world.isAlive(m_id_target)); Vector3 agent = getShip().getPosition(); Vector3 agent_velocity = world.getVelocity(getShip().getId()); Vector3 target = world.getPosition(m_id_target); Vector3 target_velocity = world.getVelocity(m_id_target); Vector3 desired_velocity; double agent_max_speed = world.getShipSpeedMax(getShip().getId()); double fromAgentToTarget = agent.getAngle(target); double fromAgentToTargetFront = agent.getAngle(target + target_velocity); if (fromAgentToTargetFront < fromAgentToTarget) { desired_velocity = m_steering_behaviour.seek(world, m_id_target); } else { desired_velocity = m_steering_behaviour.getAimDirection(agent, Bullet::SPEED, target, target_velocity); if (desired_velocity == Vector3::ZERO) { desired_velocity = m_steering_behaviour.pursue(world, m_id_target); } else { desired_velocity.setNorm(agent_max_speed); } } Vector3 avoid_velocity = avoidPlanets(world, desired_velocity); avoid_velocity = avoidParticles(world, avoid_velocity); avoid_velocity = avoidShips(world, avoid_velocity); getShipAi().setDesiredVelocity(avoid_velocity); double angle = agent_velocity.getAngle(desired_velocity); double distance = target.getDistanceSquared(agent); if (angle <= SHOOT_ANGLE_RADIANS_MAX && distance < FIRE_RANGE) { getShipAi().markFireBulletDesired(); } }
void UnitAiMoonGuard::shootAtShip(const WorldInterface& world, const PhysicsObjectId& target) { if (!world.isAlive(target)) return; Vector3 target_pos = world.getPosition(target); Vector3 target_vel = world.getVelocity(target); Vector3 aim_dir = steeringBehaviour->getAimDirection(getShip().getPosition(), Bullet::SPEED, target_pos, target_vel); double angle = getShip().getVelocity().getAngleSafe(aim_dir); if (angle <= SHOOT_ANGLE_RADIANS_MAX && getShip().isReloaded()) { getShipAi().markFireBulletDesired(); //printf("\tShooting at (%f, %f, %f)\n", target_pos.x, target_pos.y, target_pos.z); }; }
Vector3 SteeringBehaviour :: evade (const WorldInterface& world, const PhysicsObjectId& id_target) { assert(id_target != PhysicsObjectId::ID_NOTHING); // no initialization needed m_steering_behaviour = EVADE; if(!world.isAlive(m_id_agent) || !world.isAlive( id_target)) { assert(invariant()); return Vector3::ZERO; } Vector3 agent_position = world.getPosition(m_id_agent); Vector3 target_position = world.getPosition( id_target); if(agent_position == target_position) { assert(invariant()); return Vector3::ZERO; } assert(world.isAlive(m_id_agent )); assert(world.isAlive( id_target)); Vector3 target_velocity = world.getVelocity(id_target); double agent_speed_max = world.getShipSpeedMax(m_id_agent); assert(agent_speed_max >= 0.0); Vector3 aim_direction = getAimDirection(agent_position, agent_speed_max, target_position, target_velocity); if(aim_direction.isZero()) { assert(invariant()); return (agent_position - target_position).getCopyWithNorm(agent_speed_max); } else { assert(invariant()); return aim_direction * -agent_speed_max; } }
Vector3 SteeringBehaviour :: aim (const WorldInterface& world, const PhysicsObjectId& id_target, double shot_speed) { assert(id_target != PhysicsObjectId::ID_NOTHING); assert(shot_speed >= 0.0); // no initialization needed m_steering_behaviour = AIM; if(!world.isAlive(m_id_agent) || !world.isAlive( id_target)) { assert(invariant()); return Vector3::ZERO; } Vector3 agent_position = world.getPosition(m_id_agent); Vector3 target_position = world.getPosition( id_target); if(agent_position == target_position) { assert(invariant()); return Vector3::ZERO; } assert(world.isAlive(m_id_agent )); assert(world.isAlive( id_target)); double agent_speed_max = world.getShipSpeedMax(m_id_agent); assert(agent_speed_max >= 0.0); Vector3 target_velocity = world.getVelocity(id_target); Vector3 aim_direction = getAimDirection(agent_position, shot_speed, target_position, target_velocity); assert(invariant()); return aim_direction * agent_speed_max; }