Make rubber-banding distances different between AI karts (#3256)

* Don't generate IRC alerts

* Differentiated rubber-banding

* Fix #3222

* Small simplification

* Use master's version

* Fix typo

* Use std::sort

* Remove useless function call

test_ai is only used for profiling without human players
This commit is contained in:
Alayan-stk-2 2018-05-27 01:09:18 +02:00 committed by auriamg
parent c4cb0201df
commit 30c1e0ca6d
6 changed files with 94 additions and 32 deletions

View File

@ -295,10 +295,12 @@
distance ahead, the value for the largest distance is used, distance ahead, the value for the largest distance is used,
and similarly if the kart is more than the minimum value and similarly if the kart is more than the minimum value
behind). behind).
speed-cap: Fraction of maximum speed the kart should drive first-speed-cap: Fraction of maximum speed the first AI kart
at. Used to slow down karts that are ahead of the player. should drive at. Used to slow down karts that are ahead of
Note that setting this to a value >1 does NOT increase the player. Note that setting this to a value >1 does NOT
the speed the kart can drive at! increase the speed the kart can drive at!
last-speed-cap: same as first-speed-cap, but for last AI kart.
AI karts in-between use an average of it with first-speed-cap.
collect-item-probability: Probability of the AI actually collect-item-probability: Probability of the AI actually
trying to collect an item (if an item is selected for trying to collect an item (if an item is selected for
collection in the first place). collection in the first place).
@ -315,7 +317,8 @@
item-skill="1" item-skill="1"
collect-avoid-items="false" collect-avoid-items="false"
handle-bomb="false" handle-bomb="false"
speed-cap="-10:1.0 -5:0.9 5:0.8 20:0.7 50:0.6" first-speed-cap="-100:1.0 -50:0.9 0:0.85 100:0.65"
last-speed-cap="-150:0.92 -50:0.75 50:0.6"
max-item-angle="0.7" max-item-angle-high-speed="0.3" max-item-angle="0.7" max-item-angle-high-speed="0.3"
bad-item-closeness="6" bad-item-closeness="6"
collect-item-probability="0:0" collect-item-probability="0:0"
@ -333,7 +336,8 @@
item-skill="2" item-skill="2"
collect-avoid-items="true" collect-avoid-items="true"
handle-bomb="false" handle-bomb="false"
speed-cap="10:1.0 50:0.8" first-speed-cap="20:1.0 60:0.9 100:0.85"
last-speed-cap="-50:0.94 0:0.85 100:0.75"
max-item-angle="0.7" max-item-angle-high-speed="0.3" max-item-angle="0.7" max-item-angle-high-speed="0.3"
bad-item-closeness="6" bad-item-closeness="6"
collect-item-probability="-10:1.0 0:0" collect-item-probability="-10:1.0 0:0"
@ -351,7 +355,8 @@
item-skill="3" item-skill="3"
collect-avoid-items="true" collect-avoid-items="true"
handle-bomb="true" handle-bomb="true"
speed-cap="20:1.0 50:0.8" first-speed-cap="50:1.0 150:0.9"
last-speed-cap="0:0.96 80:0.8"
max-item-angle="0.7" max-item-angle-high-speed="0.3" max-item-angle="0.7" max-item-angle-high-speed="0.3"
bad-item-closeness="6" bad-item-closeness="6"
collect-item-probability="10:1.0 20:0" collect-item-probability="10:1.0 20:0"
@ -369,7 +374,8 @@
item-skill="4" item-skill="4"
collect-avoid-items="true" collect-avoid-items="true"
handle-bomb="true" handle-bomb="true"
speed-cap="0:1.0" first-speed-cap="0:1.0"
last-speed-cap="0:1.0"
max-item-angle="0.7" max-item-angle-high-speed="0.3" max-item-angle="0.7" max-item-angle-high-speed="0.3"
bad-item-closeness="6" bad-item-closeness="6"
collect-item-probability="0:1.0" collect-item-probability="0:1.0"

View File

@ -64,7 +64,8 @@ void AIProperties::load(const XMLNode *ai_node)
ai_node->get("collect-item-probability", &m_collect_item_probability ); ai_node->get("collect-item-probability", &m_collect_item_probability );
ai_node->get("straight-length-for-zipper",&m_straight_length_for_zipper); ai_node->get("straight-length-for-zipper",&m_straight_length_for_zipper);
ai_node->get("rb-skid-probability", &m_skid_probability ); ai_node->get("rb-skid-probability", &m_skid_probability );
ai_node->get("speed-cap", &m_speed_cap ); ai_node->get("first-speed-cap", &m_first_speed_cap );
ai_node->get("last-speed-cap", &m_last_speed_cap );
ai_node->get("item-skill", &m_item_usage_skill ); ai_node->get("item-skill", &m_item_usage_skill );
ai_node->get("collect-avoid-items", &m_collect_avoid_items ); ai_node->get("collect-avoid-items", &m_collect_avoid_items );
ai_node->get("handle-bomb", &m_handle_bomb ); ai_node->get("handle-bomb", &m_handle_bomb );
@ -108,7 +109,7 @@ void AIProperties::checkAllSet(const std::string &filename) const
Log::fatal("AIProperties", "No skid probability defined."); Log::fatal("AIProperties", "No skid probability defined.");
} }
if(m_speed_cap.size()==0) if(m_first_speed_cap.size()==0 || m_last_speed_cap.size()==0)
{ {
Log::fatal("AIProperties", "No speed cap defined."); Log::fatal("AIProperties", "No speed cap defined.");
} }
@ -120,4 +121,18 @@ void AIProperties::checkAllSet(const std::string &filename) const
} // checkAllSet } // checkAllSet
// ------------------------------------------------------------------------
/** Returns the fraction of maximum speed the AI should drive at, depending
* on the distance from the player. */
float AIProperties::getSpeedCap(float distance, int ai_position, int num_ai) const
{
float wfirst = 1.0f;
if (num_ai >= 2)
wfirst = 1.0f - ( (float) (ai_position-1) / (float) (num_ai-1) );
return wfirst * m_first_speed_cap.get(distance)
+(1-wfirst) * m_last_speed_cap.get(distance);
} // getSpeedCap
/* EOF */ /* EOF */

View File

@ -78,7 +78,8 @@ protected:
InterpolationArray m_skid_probability; InterpolationArray m_skid_probability;
/** To cap maximum speed if the kart is ahead of the player. */ /** To cap maximum speed if the kart is ahead of the player. */
InterpolationArray m_speed_cap; InterpolationArray m_first_speed_cap;
InterpolationArray m_last_speed_cap;
/** To determine the probability of selecting an item. */ /** To determine the probability of selecting an item. */
InterpolationArray m_collect_item_probability; InterpolationArray m_collect_item_probability;
@ -146,10 +147,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the fraction of maximum speed the AI should drive at, depending /** Returns the fraction of maximum speed the AI should drive at, depending
* on the distance from the player. */ * on the distance from the player. */
float getSpeedCap(float distance) const float getSpeedCap(float distance, int ai_position, int num_ai) const;
{
return m_speed_cap.get(distance);
} // getSpeedCap
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the probability to collect an item depending on the distance /** Returns the probability to collect an item depending on the distance
* to the first player kart. */ * to the first player kart. */

View File

@ -308,9 +308,16 @@ void SkiddingAI::update(int ticks)
// Get information that is needed by more than 1 of the handling funcs // Get information that is needed by more than 1 of the handling funcs
computeNearestKarts(); computeNearestKarts();
int num_ai = m_world->getNumKarts() - race_manager->getNumPlayers();
int position_among_ai = m_kart->getPosition() - m_num_players_ahead;
float speed_cap = m_ai_properties->getSpeedCap(m_distance_to_player,
position_among_ai,
num_ai);
m_kart->setSlowdown(MaxSpeed::MS_DECREASE_AI, m_kart->setSlowdown(MaxSpeed::MS_DECREASE_AI,
m_ai_properties->getSpeedCap(m_distance_to_player), speed_cap, /*fade_in_time*/0);
/*fade_in_time*/0);
//Detect if we are going to crash with the track and/or kart //Detect if we are going to crash with the track and/or kart
checkCrashes(m_kart->getXYZ()); checkCrashes(m_kart->getXYZ());
determineTrackDirection(); determineTrackDirection();
@ -1965,23 +1972,58 @@ void SkiddingAI::computeNearestKarts()
-m_world->getOverallDistance(m_kart_behind->getWorldKartId()); -m_world->getOverallDistance(m_kart_behind->getWorldKartId());
} }
// Compute distance to nearest player kart // Compute distance to target player kart
float max_overall_distance = 0.0f;
float target_overall_distance = 0.0f;
float own_overall_distance = m_world->getOverallDistance(m_kart->getWorldKartId());
m_num_players_ahead = 0;
unsigned int n = ProfileWorld::isProfileMode() unsigned int n = ProfileWorld::isProfileMode()
? 0 : race_manager->getNumPlayers(); ? 0 : race_manager->getNumPlayers();
std::vector<float> overall_distance;
// Get the players distances
for(unsigned int i=0; i<n; i++) for(unsigned int i=0; i<n; i++)
{ {
unsigned int kart_id = unsigned int kart_id = m_world->getPlayerKart(i)->getWorldKartId();
m_world->getPlayerKart(i)->getWorldKartId(); overall_distance.push_back(m_world->getOverallDistance(kart_id));
if(m_world->getOverallDistance(kart_id)>max_overall_distance) }
max_overall_distance = m_world->getOverallDistance(kart_id);
// Sort the list
std::sort(overall_distance.begin(), overall_distance.end());
for(unsigned int i=0; i<n; i++)
{
if(overall_distance[i]>own_overall_distance)
m_num_players_ahead++;
}
if(ProfileWorld::isProfileMode())
target_overall_distance = 999999.9f; // force best driving
// In higher difficulties, rubber band towards the first player,
// if at all (SuperTux has currently no rubber banding at all)
else if (race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ||
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST)
{
target_overall_distance = overall_distance[n-1]; // Highest player distance
}
// Distribute the AIs to players
else
{
int num_ai = m_world->getNumKarts() - race_manager->getNumPlayers();
int position_among_ai = m_kart->getPosition() - m_num_players_ahead;
// Converts a position among AI to a position among players
float ideal_target = ((position_among_ai-1) / ((float) num_ai-1)
* ((float) race_manager->getNumPlayers()-1)) + 1.0f;
// Substract 1 as index start from 0 and add 0.5 to get rounding
// The cast truncate the decimals, so it won't go over n-1
// as the highest possible ideal_target is n
int target_index = (int) (ideal_target - 0.5f);
assert (target_index >= 0 && target_index <= n-1);
target_overall_distance = overall_distance[target_index];
} }
if(max_overall_distance==0.0f)
max_overall_distance = 999999.9f; // force best driving
// Now convert 'maximum overall distance' to distance to player. // Now convert 'maximum overall distance' to distance to player.
m_distance_to_player = m_distance_to_player = own_overall_distance - target_overall_distance;
m_world->getOverallDistance(m_kart->getWorldKartId())
- max_overall_distance;
} // computeNearestKarts } // computeNearestKarts
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -180,6 +180,9 @@ private:
/** Distance to the player, used for rubber-banding. */ /** Distance to the player, used for rubber-banding. */
float m_distance_to_player; float m_distance_to_player;
/** Number of players ahead, used for rubber-banding. */
int m_num_players_ahead;
/** A random number generator to decide if the AI should skid or not. */ /** A random number generator to decide if the AI should skid or not. */
RandomGenerator m_random_skid; RandomGenerator m_random_skid;

View File

@ -313,10 +313,7 @@ void SkiddingAI::update(int ticks)
// Get information that is needed by more than 1 of the handling funcs // Get information that is needed by more than 1 of the handling funcs
computeNearestKarts(); computeNearestKarts();
m_kart->setSlowdown(MaxSpeed::MS_DECREASE_AI,
m_ai_properties->getSpeedCap(m_distance_to_player),
/*fade_in_time*/0);
//Detect if we are going to crash with the track and/or kart //Detect if we are going to crash with the track and/or kart
checkCrashes(m_kart->getXYZ()); checkCrashes(m_kart->getXYZ());
determineTrackDirection(); determineTrackDirection();