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:
parent
4d0e8c153f
commit
ef2a1524c4
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user