Added a skidding probability which is dependent on the to the

first player (i.e. slightly rubber-banding the AI).


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11682 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2012-10-14 20:59:51 +00:00
parent 4d0e8c153f
commit ef2a1524c4
5 changed files with 145 additions and 3 deletions

View File

@ -232,12 +232,29 @@
direction.
straight-length-for-zipper is the minimum length a straight
section of the track should have in order to activate a zipper.
competitive when ahead of the player, or more competitive
when behind the player.
skid-probability: Since the AI is usually very good at using
skidding, this is used to implement some rubber-banding for
the AI: depending on distance to the player, the AI will
change the probability of skidding. This attributes takes
a space-separated list of "distance:probability" pairs
(negative distances meaning the kart is behind the player,
a positive number that the AI is ahead of the player).
Then list should have at least 2 entries. Depending on
the actualy distance the kart has the probability is then
linearly interpolated (if the AI is more than the largest
distance ahead, the value for the largest distance is used,
and similarly if the kart is more than the minimum value
behind).
-->
<ai max-item-angle="0.7" max-item-angle-high-speed="0.3"
time-full-steer="0.1"
bad-item-closeness="6"
straight-length-for-zipper="35"
/>
rb-skid-probability="-50:1.0 -20:0.7 20:0.2 50:0.0"/>
<!-- Slipstream: length: How far behind a kart slipstream works
collect-time: How many seconds of sstream give maximum benefit

View File

@ -19,6 +19,7 @@
#include "karts/controller/ai_properties.hpp"
#include "io/xml_node.hpp"
#include "utils/string_utils.hpp"
float AIProperties::UNDEFINED = -99.9f;
@ -45,6 +46,50 @@ void AIProperties::load(const XMLNode *ai_node)
ai_node->get("bad-item-closeness", &m_bad_item_closeness_2 );
ai_node->get("straight-length-for-zipper",&m_straight_length_for_zipper);
std::string s;
ai_node->get("rb-skid-probability", &s);
std::vector<std::string> pairs = StringUtils::split(s, ' ');
for(unsigned int i=0; i<pairs.size(); i++)
{
std::vector<std::string> pair = StringUtils::split(pairs[i],':');
if(pair.size()!=2)
{
printf("Incorrect pair '%s' in rd-skid-probability.\n",
pairs[i].c_str());
printf("Must be distance:probability.\n");
exit(-1);
}
float distance;
if(!StringUtils::fromString(pair[0], distance))
{
printf("Incorrect distance in pair '%s'.\n", pairs[i].c_str());
exit(-1);
}
float p;
if(!StringUtils::fromString(pair[1], p))
{
printf(
"Incorrect probability in pair '%s' in rb-skid-probability.\n",
pair[1].c_str());
exit(-1);
}
m_skid_distances.push_back(distance);
m_skid_probabilities.push_back(p);
} // for i
if(m_skid_distances.size()==0)
{
printf("No skid probability defined.\n");
exit(-1);
}
for(unsigned int i=0; i<m_skid_distances.size()-1; i++)
{
if(m_skid_distances[i]>=m_skid_distances[i+1])
{
printf("Skid distances must be sorted.\n");
exit(-1);
}
}
// We actually need the square of the distance later
m_bad_item_closeness_2 *= m_bad_item_closeness_2;
@ -76,6 +121,29 @@ void AIProperties::copyFrom(const AIProperties *destination)
} // copyFrom
// ----------------------------------------------------------------------------
float AIProperties::getSkiddingProbability(float distance) const
{
if(m_skid_distances.size()==1)
return m_skid_probabilities[0];
if(distance<m_skid_distances[0])
return m_skid_probabilities[0];
if(distance>m_skid_distances[m_skid_distances.size()-1])
return m_skid_probabilities[m_skid_probabilities.size()-1];
// Now distance must be between two of the distances in the
// sorted m_skid_distances array
for(unsigned int i=1; i<m_skid_distances.size(); i++)
{
if(distance >m_skid_distances[i]) continue;
float f = m_skid_probabilities[i-1] +
(m_skid_probabilities[i]-m_skid_probabilities[i-1]) *
(distance - m_skid_distances[i-1])/
(m_skid_distances[i]-m_skid_distances[i-1]);
return f;
}
assert(false);
return 0.0f;
} // getSkiddingProbability
/* EOF */

View File

@ -20,6 +20,7 @@
#define HEADER_AI_PROPERTIES_HPP
#include <string>
#include <vector>
class XMLNode;
@ -67,12 +68,19 @@ protected:
/** Minimum length of a straight in order to activate a zipper. */
float m_straight_length_for_zipper;
/** The distances at which the skid probability is specified. */
std::vector<float> m_skid_distances;
/** The skidding probability depending on distance, which is stored
* in m_skid_distances - the two fields must have the same length. */
std::vector<float> m_skid_probabilities;
public:
AIProperties();
void load(const XMLNode *skid_node);
void copyFrom(const AIProperties *destination);
void checkAllSet(const std::string &filename) const;
float getSkiddingProbability(float distance) const;
}; // AIProperties

View File

@ -69,6 +69,7 @@
#include "items/item_manager.hpp"
#include "items/powerup.hpp"
#include "modes/linear_world.hpp"
#include "modes/profile_world.hpp"
#include "network/network_manager.hpp"
#include "race/race_manager.hpp"
#include "tracks/quad_graph.hpp"
@ -2211,10 +2212,48 @@ void SkiddingAI::setSteering(float angle, float dt)
{
float steer_fraction = angle / m_kart->getMaxSteerAngle();
if(!doSkid(steer_fraction))
{
m_tried_skid_last_frame = false;
m_controls->m_skid = KartControl::SC_NONE;
}
else
m_controls->m_skid = steer_fraction > 0 ? KartControl::SC_RIGHT
: KartControl::SC_LEFT;
{
KartControl::SkidControl sc = steer_fraction > 0
? KartControl::SC_RIGHT
: KartControl::SC_LEFT;
if(!m_tried_skid_last_frame)
{
float max_distance = 0.0f;
unsigned int n = ProfileWorld::isProfileMode()
? 0 : race_manager->getNumPlayers();
for(unsigned int i=0; i<n; i++)
{
unsigned int kart_id =
m_world->getPlayerKart(i)->getWorldKartId();
if(m_world->getOverallDistance(kart_id)>max_distance)
max_distance = m_world->getOverallDistance(kart_id);
}
if(max_distance==0.0f)
max_distance = 999999.9f; // force best driving
float distance =
m_world->getOverallDistance(m_kart->getWorldKartId())
- max_distance;
int prob = (int)
(100.0f*m_ai_properties->getSkiddingProbability(distance));
if(m_random_skid.get(100)>=prob)
sc = KartControl::SC_NONE;
#undef PRINT_SKID_STATS
#ifdef PRINT_SKID_STATS
printf("%s distance %f prob %d skidding %s\n",
m_kart->getIdent().c_str(), distance, prob,
sc==0 ? "no" : sc==KartControl::SC_LEFT ? "left" : "right");
#endif
}
m_controls->m_skid = sc;
m_tried_skid_last_frame = true;
}
// Adjust steer fraction in case to be in [-1,1]
if (steer_fraction > 1.0f) steer_fraction = 1.0f;

View File

@ -24,6 +24,7 @@
#include "karts/controller/ai_base_controller.hpp"
#include "race/race_manager.hpp"
#include "tracks/graph_node.hpp"
#include "utils/random_generator.hpp"
class LinearWorld;
class QuadGraph;
@ -150,6 +151,15 @@ private:
* (which would make it more difficult to avoid items). */
bool m_avoid_item_close;
/** A random number generator to decide if the AI should skid or not. */
RandomGenerator m_random_skid;
/** True if the AI decided to skid in the previous frame. At the
* beginning of each skid it is randomly decided if the skid is
* to be done or not (to rubber-band the AI). This flag is used
* to decide if a new skid is happening. */
bool m_tried_skid_last_frame;
/** Which of the three Point Selection Algorithms (i.e.
* findNoNCrashingPoint* functions) to use:
* the default (which is actually slightly buggy, but so far best one