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,
and similarly if the kart is more than the minimum value
behind).
speed-cap: Fraction of maximum speed the kart should drive
at. Used to slow down karts that are ahead of the player.
Note that setting this to a value >1 does NOT increase
the speed the kart can drive at!
first-speed-cap: Fraction of maximum speed the first AI kart
should drive at. Used to slow down karts that are ahead of
the player. Note that setting this to a value >1 does NOT
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
trying to collect an item (if an item is selected for
collection in the first place).
@ -315,7 +317,8 @@
item-skill="1"
collect-avoid-items="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"
bad-item-closeness="6"
collect-item-probability="0:0"
@ -333,7 +336,8 @@
item-skill="2"
collect-avoid-items="true"
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"
bad-item-closeness="6"
collect-item-probability="-10:1.0 0:0"
@ -351,7 +355,8 @@
item-skill="3"
collect-avoid-items="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"
bad-item-closeness="6"
collect-item-probability="10:1.0 20:0"
@ -369,7 +374,8 @@
item-skill="4"
collect-avoid-items="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"
bad-item-closeness="6"
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("straight-length-for-zipper",&m_straight_length_for_zipper);
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("collect-avoid-items", &m_collect_avoid_items );
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.");
}
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.");
}
@ -120,4 +121,18 @@ void AIProperties::checkAllSet(const std::string &filename) const
} // 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 */

View File

@ -78,7 +78,8 @@ protected:
InterpolationArray m_skid_probability;
/** 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. */
InterpolationArray m_collect_item_probability;
@ -146,10 +147,8 @@ public:
// ------------------------------------------------------------------------
/** Returns the fraction of maximum speed the AI should drive at, depending
* on the distance from the player. */
float getSpeedCap(float distance) const
{
return m_speed_cap.get(distance);
} // getSpeedCap
float getSpeedCap(float distance, int ai_position, int num_ai) const;
// ------------------------------------------------------------------------
/** Returns the probability to collect an item depending on the distance
* 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
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_ai_properties->getSpeedCap(m_distance_to_player),
/*fade_in_time*/0);
speed_cap, /*fade_in_time*/0);
//Detect if we are going to crash with the track and/or kart
checkCrashes(m_kart->getXYZ());
determineTrackDirection();
@ -1965,23 +1972,58 @@ void SkiddingAI::computeNearestKarts()
-m_world->getOverallDistance(m_kart_behind->getWorldKartId());
}
// Compute distance to nearest player kart
float max_overall_distance = 0.0f;
// Compute distance to target player kart
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()
? 0 : race_manager->getNumPlayers();
std::vector<float> overall_distance;
// Get the players distances
for(unsigned int i=0; i<n; i++)
{
unsigned int kart_id =
m_world->getPlayerKart(i)->getWorldKartId();
if(m_world->getOverallDistance(kart_id)>max_overall_distance)
max_overall_distance = m_world->getOverallDistance(kart_id);
unsigned int kart_id = m_world->getPlayerKart(i)->getWorldKartId();
overall_distance.push_back(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.
m_distance_to_player =
m_world->getOverallDistance(m_kart->getWorldKartId())
- max_overall_distance;
m_distance_to_player = own_overall_distance - target_overall_distance;
} // computeNearestKarts
//-----------------------------------------------------------------------------

View File

@ -180,6 +180,9 @@ private:
/** Distance to the player, used for rubber-banding. */
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. */
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
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
checkCrashes(m_kart->getXYZ());
determineTrackDirection();