Пример #1
0
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);
}
Пример #2
0
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;
	}
}
Пример #3
0
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();
    }
}
Пример #4
0
Vector3 SteeringBehaviour :: explore (const WorldInterface& world,
                                      double distance_new_position_min,
                                      double distance_new_position_max)
{
	assert(distance_new_position_min >= 0.0);
	assert(distance_new_position_min <= distance_new_position_max);
	assert(distance_new_position_min >  EXPLORE_DISTANCE_NEW_POSITION);

	double position_distance           = (distance_new_position_max + distance_new_position_min) * 0.5;
	double position_distance_tolerance = (distance_new_position_max - distance_new_position_min) * 0.5;

	bool is_new_position_needed = false;
	if(m_steering_behaviour         != EXPLORE ||
	   m_desired_distance           != position_distance ||
	   m_desired_distance_tolerance != position_distance_tolerance)
	{
		m_steering_behaviour         = EXPLORE;
		m_desired_distance           = position_distance;
		m_desired_distance_tolerance = position_distance_tolerance;
		is_new_position_needed       = true;
	}

	if(!world.isAlive(m_id_agent))
	{
		// the explore position doesn't matter at this point

		assert(invariant());
		return Vector3::ZERO;
	}

	Vector3 agent_position = world.getPosition(m_id_agent);
	double agent_speed_max = world.getShipSpeedMax(m_id_agent);
	assert(agent_speed_max >= 0.0);

	if(agent_position.isDistanceLessThan(m_explore_position, EXPLORE_DISTANCE_NEW_POSITION) ||
	   is_new_position_needed)
	{
		m_explore_position = calculateExplorePosition(agent_position);
	}

	return (m_explore_position - agent_position).getCopyWithNorm(agent_speed_max);
}
Пример #5
0
Vector3 SteeringBehaviour :: arrive (const WorldInterface& world,
                                     const Vector3& target_position)
{
	// no initialization needed
	m_steering_behaviour = ARRIVE;

	PhysicsObjectId id_agent = m_id_agent;

	if(!world.isAlive(id_agent))
	{
		assert(invariant());
		return Vector3::ZERO;
	}

	Vector3 agent_position = world.getPosition(id_agent);

	if(agent_position == target_position)
	{
		assert(invariant());
		return Vector3::ZERO;
	}

	double agent_speed = world.getShipSpeedMax(id_agent);
	assert(agent_speed >= 0.0);
	double agent_acceleration = world.getShipAcceleration(id_agent);
	assert(agent_acceleration >= 0.0);

	double distance       = agent_position.getDistance(target_position);
	double max_safe_speed = calculateMaxSafeSpeed(distance, agent_acceleration);
	if(max_safe_speed < agent_speed)
		agent_speed = max_safe_speed;
	assert(agent_speed >= 0.0);
	assert(agent_speed <= max_safe_speed);

	assert(invariant());
	return (target_position - agent_position).getCopyWithNorm(agent_speed);
}
Пример #6
0
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;
}
Пример #7
0
Vector3 SteeringBehaviour :: flee (const WorldInterface& world,
                                   const Vector3& target_position)
{
	// no initialization needed
	m_steering_behaviour = FLEE;

	if(!world.isAlive(m_id_agent))
	{
		assert(invariant());
		return Vector3::ZERO;
	}

	Vector3 agent_position = world.getPosition(m_id_agent);

	if(agent_position == target_position)
	{
		assert(invariant());
		return Vector3::ZERO;
	}

	double agent_speed_max = world.getShipSpeedMax(m_id_agent);
	assert(agent_speed_max >= 0.0);
	return (agent_position - target_position).getCopyWithNorm(agent_speed_max);
}
Пример #8
0
// 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);
	}
}
Пример #9
0
Vector3 SteeringBehaviour :: patrolSphere (const WorldInterface& world,
                                           const Vector3& sphere_center,
                                           double patrol_radius,
                                           double patrol_radius_tolerance)
{
	assert(patrol_radius >= 0.0);
	assert(patrol_radius_tolerance >= 0.0);

	bool is_new_position_needed = false;
	if(m_steering_behaviour         != PATROL_SPHERE ||
	   m_sphere_center              != sphere_center ||
	   m_desired_distance           != patrol_radius ||
	   m_desired_distance_tolerance != patrol_radius_tolerance)
	{
		m_steering_behaviour         = PATROL_SPHERE;
		m_sphere_center              = sphere_center;
		m_desired_distance           = patrol_radius;
		m_desired_distance_tolerance = patrol_radius_tolerance;
		is_new_position_needed       = true;
	}

	if(!world.isAlive(m_id_agent))
	{
		// the explore position doesn't matter at this point

		assert(invariant());
		return Vector3::ZERO;
	}

	Vector3 agent_position = world.getPosition(m_id_agent);

	if(isNearEnoughPatrolSpherePoint(agent_position) ||
	   is_new_position_needed)
	{
		m_explore_position = calculatePatrolSpherePosition(agent_position);
	}

	double agent_speed_max = world.getShipSpeedMax(m_id_agent);
	assert(agent_speed_max >= 0.0);

	if(DEBUGGING_PATROL_SPHERE)
	{
		cout << "Explore:" << endl;
		cout << "\tAgent position:   " << agent_position << endl;
		cout << "\tSphere position:  " << m_sphere_center << endl;
		cout << "\tExplore position: " << m_explore_position << endl;
	}

	double distance_from_sphere = agent_position.getDistance(m_sphere_center);

	double weight_parallel = 1.0;
	if(m_desired_distance_tolerance > 0.0)
	{
		double distance_outside_optimum = distance_from_sphere - m_desired_distance;

		weight_parallel = distance_outside_optimum / m_desired_distance_tolerance;
		if(weight_parallel > 1.0)
			weight_parallel = 1.0;
		if(weight_parallel < -1.0)
			weight_parallel = -1.0;

		if(DEBUGGING_PATROL_SPHERE)
		{
				cout << "\tSphere distance:  " << distance_from_sphere << endl;
				cout << "\tDesired distance: " << m_desired_distance << endl;
				cout << "\tTolerance:        " << m_desired_distance_tolerance << endl;
				cout << "\tweight_parallel:      " << weight_parallel << endl;
		}

		if(weight_parallel >= 0.0)
			weight_parallel =   weight_parallel * weight_parallel;
		else
			weight_parallel = -(weight_parallel * weight_parallel);

		if(DEBUGGING_PATROL_SPHERE)
				cout << "\t                   => " << weight_parallel << endl;

		assert(weight_parallel <=  1.0);
		assert(weight_parallel >= -1.0);
	}
	assert(weight_parallel <=  1.0);
	assert(weight_parallel >= -1.0);
	double weight_perpendicular = 1.0 - fabs(weight_parallel);
	assert(weight_perpendicular <=  1.0);
	assert(weight_perpendicular >= -1.0);

	if(DEBUGGING_PATROL_SPHERE)
		cout << "\tweight_perpendicular: " << weight_perpendicular << endl;

	Vector3 to_sphere               = m_sphere_center    - agent_position;
	Vector3 to_destination          = m_explore_position - agent_position;
	Vector3 parallel_to_normal      = to_destination.getProjection(to_sphere);
	Vector3 perpendicular_to_normal = to_destination - parallel_to_normal;
	Vector3 desired_vector          = parallel_to_normal      * weight_parallel +
	                                  perpendicular_to_normal * weight_perpendicular;

	assert(invariant());
	return desired_vector.getCopyWithNormSafe(agent_speed_max);
}