SuperTuxKart
|
This is the actual racing AI. More...
#include <skidding_ai.hpp>
Classes | |
class | CrashTypes |
Public Member Functions | |
SkiddingAI (AbstractKart *kart) | |
~SkiddingAI () | |
Destructor, mostly to clean up debug data structures. | |
virtual void | update (int ticks) |
This is the main entry point for the AI. More... | |
virtual void | reset () |
Resets the AI when a race is restarted. | |
virtual const irr::core::stringw & | getNamePostfix () const |
Returns a name for the AI. More... | |
![]() | |
AIBaseLapController (AbstractKart *kart) | |
This is the base class for all AIs. More... | |
![]() | |
AIBaseController (AbstractKart *kart) | |
virtual bool | disableSlipstreamBonus () const OVERRIDE |
Certain AI levels will not receive a slipstream bonus in order to be not as hard. | |
virtual void | crashed (const Material *m) OVERRIDE |
This is called when the kart crashed with the terrain. More... | |
virtual void | crashed (const AbstractKart *k) OVERRIDE |
virtual void | handleZipper (bool play_sound) OVERRIDE |
virtual void | finishedRace (float time) OVERRIDE |
Called whan this controller's kart finishes the last lap. More... | |
virtual void | collectedItem (const ItemState &item, float previous_energy=0) OVERRIDE |
virtual void | setPosition (int p) OVERRIDE |
virtual bool | isPlayerController () const OVERRIDE |
This function checks if this player is not an AI, i.e. More... | |
virtual bool | isLocalPlayerController () const OVERRIDE |
This function checks if this is a local player. More... | |
virtual bool | action (PlayerAction action, int value, bool dry_run=false) OVERRIDE |
Default: ignore actions. More... | |
virtual void | skidBonusTriggered () OVERRIDE |
virtual bool | saveState (BareNetworkString *buffer) const OVERRIDE |
virtual void | rewindTo (BareNetworkString *buffer) OVERRIDE |
void | setNetworkAI (bool val) |
![]() | |
Controller (AbstractKart *kart) | |
Constructor, saves the kart pointer and a pointer to the KartControl of the kart. | |
virtual void | rumble (float strength_low, float strength_high, uint16_t duration) |
const std::string & | getControllerName () const |
Returns the name of this controller. More... | |
virtual KartControl * | getControls () |
Get a pointer on the kart controls. More... | |
void | setControls (KartControl *kc) |
virtual bool | canGetAchievements () const |
Only local players can get achievements. More... | |
virtual core::stringw | getName (bool include_handicap_string=true) const |
Display name of the controller. More... | |
AbstractKart * | getKart () const |
Returns the kart controlled by this controller. More... | |
Protected Member Functions | |
virtual unsigned int | getNextSector (unsigned int index) |
Returns the pre-computed successor of a graph node. More... | |
![]() | |
virtual void | newLap (int lap) |
Triggers a recomputation of the path to use, so that the AI does not always use the same way. | |
float | steerToAngle (const unsigned int sector, const float angle) |
This function steers towards a given angle. More... | |
void | computePath () |
Computes a path for the AI to follow. More... | |
virtual void | raceFinished () |
Nothing special to do when the race is finished. More... | |
![]() | |
void | setControllerName (const std::string &name) OVERRIDE |
In debug mode when the user specified –ai-debug on the command line set the name of the controller as on-screen text, so that the different AI controllers can be distinguished. More... | |
float | steerToPoint (const Vec3 &point) |
Computes the steering angle to reach a certain point. More... | |
float | normalizeAngle (float angle) |
Normalises an angle to be between -pi and _ pi. More... | |
bool | isStuck () const |
This can be called to detect if the kart is stuck (i.e. More... | |
void | determineTurnRadius (const Vec3 &end, Vec3 *center, float *radius) const |
Determine the center point and radius of a circle given two points on the circle and the tangent at the first point. More... | |
Private Types | |
enum | { SKID_PROBAB_NOT_YET, SKID_PROBAB_NO_SKID, SKID_PROBAB_SKID } |
This implements a simple finite state machine: it starts in NOT_YET. More... | |
enum | SkillType { ITEM_SKILL, NITRO_SKILL } |
This is used by computeSkill to know what skill is used. | |
enum | { PSA_DEFAULT, PSA_NEW } |
Determines the algorithm to use to select the point-to-aim-for There are two different Point Selection Algorithms: More... | |
Private Member Functions | |
void | handleRaceStart () |
void | handleAccelerationAndBraking (int ticks) |
Determines if the AI should accelerate or not, and if not if it should brake. More... | |
void | handleSteering (float dt) |
Decides in which direction to steer. More... | |
int | computeSkill (SkillType type) |
Returns the AI skill value used by the kart. | |
void | handleItems (const float dt, const Vec3 *aim_point, int last_node, int item_skill) |
Handle all items depending on the chosen strategy. More... | |
void | handleBubblegum (int item_skill, const std::vector< const ItemState *> &items_to_collect, const std::vector< const ItemState *> &items_to_avoid) |
Handle bubblegum depending on the chosen strategy Level 2 : Use the shield immediately after a wait time Level 3 : Use the shield against flyables except cakes. More... | |
void | handleCake (int item_skill) |
Handle cake depending on the chosen strategy Level 2 : Use the cake against any close vulnerable enemy, with priority to those ahead and close, check if the enemy is roughly ahead. More... | |
void | handleBowling (int item_skill) |
Handle the bowling ball depending on the chosen strategy Level 2 : Use the bowling ball against enemies straight ahead or straight behind, and not invulnerable, with a 5 second delay Level 3 : Only 3 seconds of delay Level 4 : Same as level 3 Level 5 : Level 4 and don't fire on a shielded kart if we're just behind (gum) More... | |
void | handleSwatter (int item_skill) |
Handle the swatter depending on the chosen strategy Level 2 : Use the swatter immediately after a wait time Level 3 : Use the swatter when enemies are close Level 4 : Level 3 and use the swatter to remove bad attachments Level 5 : Level 4 and use against bomb only when the timer ends. More... | |
void | handleSwitch (int item_skill, const std::vector< const ItemState *> &items_to_collect, const std::vector< const ItemState *> &items_to_avoid) |
Handle switch depending on the chosen strategy Level 2 : Use the switch after a wait time Level 3 : Same as level 2 but don't fire if close to a good item Level 4 : Same as level 3 and fire if very close to a bad item Level 5 : Use if it makes a better item available, or if very close to a bad item. More... | |
void | handleRescue (const float dt) |
void | handleBraking (float max_turn_speed, float min_speed) |
This function decides if the AI should brake. More... | |
void | handleNitroAndZipper (float max_safe_speed) |
Decides wether to use nitro and zipper or not. More... | |
void | computeNearestKarts () |
Determines the closest karts just behind and in front of this kart. More... | |
void | handleItemCollectionAndAvoidance (Vec3 *aim_point, int last_node) |
Decides if the currently selected aim at point (as determined by handleSteering) should be changed in order to collect/avoid an item. More... | |
bool | handleSelectedItem (Vec3 kart_aim_direction, Vec3 *aim_point) |
This function is called when the AI is trying to hit an item that is pre-selected to be collected. More... | |
bool | steerToAvoid (const std::vector< const ItemState *> &items_to_avoid, const core::line3df &line_to_target, Vec3 *aim_point) |
Decides if steering is necessary to avoid bad items. More... | |
bool | hitBadItemWhenAimAt (const ItemState *item, const std::vector< const ItemState *> &items_to_avoid) |
Returns true if the AI would hit any of the listed bad items when trying to drive towards the specified item. More... | |
void | evaluateItems (const ItemState *item, Vec3 kart_aim_direction, std::vector< const ItemState *> *items_to_avoid, std::vector< const ItemState *> *items_to_collect) |
This subroutine decides if the specified item should be collected, avoided, or ignored. More... | |
void | checkCrashes (const Vec3 &pos) |
void | findNonCrashingPointNew (Vec3 *result, int *last_node) |
This is a new version of findNonCrashingPoint, which at this stage is slightly inferior (though faster and more correct) than the original version - the original code cuts corner more aggressively than this version (and in most cases cuting the corner does not end in a collision, so it's actually faster). More... | |
void | findNonCrashingPoint (Vec3 *result, int *last_node) |
This is basically the original AI algorithm. More... | |
void | determineTrackDirection () |
Determines the direction of the track ahead of the kart: 0 indicates straight, +1 right turn, -1 left turn. | |
virtual bool | canSkid (float steer_fraction) |
Determines if the kart should skid. More... | |
virtual void | setSteering (float angle, float dt) |
Converts the steering angle to a lr steering in the range of -1 to 1. More... | |
void | handleCurve () |
If the kart is at/in a curve, determine the turn radius. | |
Private Attributes | |
class SkiddingAI::CrashTypes | m_crashes |
RaceManager::AISuperPower | m_superpower |
AbstractKart * | m_kart_ahead |
Pointer to the closest kart ahead of this kart. More... | |
float | m_distance_ahead |
Distance to the kart ahead. More... | |
AbstractKart * | m_kart_behind |
Pointer to the closest kart behind this kart. More... | |
float | m_distance_behind |
Distance to the kard behind. More... | |
float | m_distance_leader |
Distance to the leader kart (used only in FTL) If this kart is leader, contains a high value to avoid the leader slowing down. | |
int | m_start_delay |
The actual start delay used in ticks. More... | |
float | m_time_since_last_shot |
Time an item has been collected and not used. More... | |
float | m_time_since_stuck |
int | m_start_kart_crash_direction |
Direction of crash: -1 = left, 1 = right, 0 = no crash. More... | |
DriveNode::DirectionType | m_current_track_direction |
The direction of the track where the kart is on atm. More... | |
float | m_current_curve_radius |
The radius of the curve the kart is currently driving. More... | |
Vec3 | m_curve_center |
Stores the center of the curve (if the kart is in a curve, otherwise undefined). More... | |
unsigned int | m_last_direction_node |
The index of the last node with the same direction as the current node the kart is on. More... | |
const ItemState * | m_item_to_collect |
If set an item that the AI should aim for. More... | |
bool | m_avoid_item_close |
True if items to avoid are close by. More... | |
float | m_distance_to_player |
Distance to the player, used for rubber-banding. More... | |
int | m_num_players_ahead |
Number of players ahead, used for rubber-banding. More... | |
bool | m_burster |
This bool allows to make the AI use nitro by series of two bursts. | |
RandomGenerator | m_random_skid |
A random number generator to decide if the AI should skid or not. More... | |
enum SkiddingAI:: { ... } | m_skid_probability_state |
This implements a simple finite state machine: it starts in NOT_YET. More... | |
const ItemState * | m_last_item_random |
The last item selected for collection, for which a probability was determined. More... | |
bool | m_really_collect_item |
True if m_last_item_random was randomly selected to be collected. More... | |
RandomGenerator | m_random_collect_item |
A random number generator for collecting items. More... | |
enum SkiddingAI:: { ... } | m_point_selection_algorithm |
Determines the algorithm to use to select the point-to-aim-for There are two different Point Selection Algorithms: More... | |
ItemManager * | m_item_manager |
Additional Inherited Members | |
![]() | |
static void | enableDebug () |
static void | setTestAI (int n) |
static int | getTestAI () |
![]() | |
int | m_track_node |
The current node the kart is on. More... | |
LinearWorld * | m_world |
Keep a pointer to world. More... | |
std::vector< int > | m_successor_index |
Which of the successors of a node was selected by the AI. More... | |
std::vector< int > | m_next_node_index |
For each node in the graph this list contains the chosen next node. More... | |
std::vector< std::vector< int > > | m_all_look_aheads |
For each graph node this list contains a list of the next X graph nodes. More... | |
![]() | |
bool | m_enabled_network_ai |
float | m_kart_length |
Length of the kart, storing it here saves many function calls. More... | |
float | m_kart_width |
Cache width of kart. More... | |
Track * | m_track |
Keep a pointer to the track to reduce calls. | |
const AIProperties * | m_ai_properties |
A pointer to the AI properties for this kart. More... | |
![]() | |
AbstractKart * | m_kart |
Pointer to the kart that is controlled by this controller. More... | |
KartControl * | m_controls |
A pointer to the main controller, from which the kart takes it commands. More... | |
std::string | m_controller_name |
The name of the controller, mainly used for debugging purposes. More... | |
![]() | |
static bool | m_ai_debug = false |
static int | m_test_ai = 0 |
Stores the '–test-ai=n' command line parameter: It indicates which fraction of the AIs are going to be the test AI: 1 means only to use the TestAI, 2 means every second AI will be test etc. More... | |
This is the actual racing AI.
The main entry point, called once per frame for each AI, is update(). After handling some standard cases (race start, AI being rescued) the AI does the following steps:
|
private |
This implements a simple finite state machine: it starts in NOT_YET.
The first time the AI decides to skid, the state is changed randomly (depending on skid probability) to NO_SKID or SKID. As long as the AI keeps on deciding to skid, the state remains unchanged (so no new random decision is made) till it decides not to skid. In which case the state is set to NOT_YET again. This guarantees that for each 'skidable' section of the track the random decision is only done once.
|
private |
Determines the algorithm to use to select the point-to-aim-for There are two different Point Selection Algorithms:
So far the default one has by far the best performance, even though it has bugs.
|
privatevirtual |
Determines if the kart should skid.
The base implementation enables skidding
steer_fraction | The steering fraction as computed by the AIBaseLapController. |
Implements AIBaseController.
|
private |
Determines the closest karts just behind and in front of this kart.
The 'closeness' is for now simply based on the position, i.e. if a kart is more than one lap behind or ahead, it is not considered to be closest.
|
private |
This subroutine decides if the specified item should be collected, avoided, or ignored.
It can potentially use the state of the kart to make this decision, e.g. depending on what item the kart currently has, how much nitro it has etc. Though atm it picks the first good item, and tries to avoid any bad items on the track.
item | The item which is considered for picking/avoidance. |
kart_aim_angle | The angle of the line from the kart to the aim point. If aim_angle==kart_heading then the kart is driving towards the item. |
item_to_avoid | A pointer to a previously selected item to avoid (NULL if no item was avoided so far). |
item_to_collect | A pointer to a previously selected item to collect. |
|
private |
This is basically the original AI algorithm.
It is clearly buggy:
the test:
distance + m_kart_width * 0.5f > DriveGraph::get()->getNode(*last_node)->getPathWidth() )
is incorrect, it should compare with getPathWith*0.5f (since distance is the distance from the center, i.e. it is half the path width if the point is at the edge).
DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord, *last_node );in the for loop tests always against distance from the same graph node (*last_node), while de-fact the loop will test points on various graph nodes.
This results in this algorithm often picking points to aim at that would actually force the kart off track. But in reality the kart has to turn (and does not immediate in one frame change its direction) which takes some time - so it is actually mostly on track. Since this algoritm (so far) ends up with by far the best AI behaviour, it is for now the default).
aim_position | On exit contains the point the AI should aim at. |
last_node | On exit contais the graph node the AI is aiming at. |
|
private |
This is a new version of findNonCrashingPoint, which at this stage is slightly inferior (though faster and more correct) than the original version - the original code cuts corner more aggressively than this version (and in most cases cuting the corner does not end in a collision, so it's actually faster).
This version find the point furthest ahead which can be reached by travelling in a straight direction from the current location of the kart. This is done by using two lines: one from the kart to the lower left side of the next quad, and one from the kart to the lower right side of the next quad. The area between those two lines can be reached by the kart in a straight line, and will not go off track (assuming that the kart is on track). Then the next quads are tested: New left/right lines are computed. If the new left line is to the right of the old left line, the new left line becomes the current left line:
X The new left line connecting kart to X will be to the right \ / of the old left line, so the available area for the kart \ / will be dictated by the new left line. \ / kart
Similarly for the right side. This will narrow down the available area the kart can aim at, till finally the left and right line overlap. All points between the connection of the two end points of the left and right line can be reached without getting off track. Which point the kart aims at then depends on the direction of the track: if there is a left turn, the kart will aim to the left point (and vice versa for right turn) - slightly offset by the width of the kart to avoid that the kart is getting off track.
aim_position | The point to aim for, i.e. the point that can be driven to in a straight line. |
last_node | The graph node index in which the aim_position is. |
|
virtual |
Returns a name for the AI.
This is used in profile mode when comparing different AI implementations to be able to distinguish them from each other.
|
protectedvirtual |
Returns the pre-computed successor of a graph node.
index | The index of the graph node for which the successor is searched. |
Reimplemented from AIBaseLapController.
|
private |
Determines if the AI should accelerate or not, and if not if it should brake.
ticks | Time step size. //TODO : make acceleration steering aware |
|
private |
Handle the bowling ball depending on the chosen strategy Level 2 : Use the bowling ball against enemies straight ahead or straight behind, and not invulnerable, with a 5 second delay Level 3 : Only 3 seconds of delay Level 4 : Same as level 3 Level 5 : Level 4 and don't fire on a shielded kart if we're just behind (gum)
item_skill | The skill with which to use the item |
|
private |
This function decides if the AI should brake.
The decision can be based on race mode (e.g. in follow the leader the AI will brake if it is ahead of the leader). Otherwise it will depend on the direction the AI is facing (if it's not facing in the track direction it will brake in order to make it easier to re-align itself), and estimated curve radius (brake to avoid being pushed out of a curve).
|
private |
Handle bubblegum depending on the chosen strategy Level 2 : Use the shield immediately after a wait time Level 3 : Use the shield against flyables except cakes.
Use the shield against bad attachments and plunger. Use the bubble gum against an enemy close behind, except if holding a swatter. Level 4 : Level 3, and protect against cakes too, and use before hitting gum/banana Level 5 : Level 4, and use before hitting item box, and let plunger hit (can use the shield after), and use against bomb only when the timer ends
item_skill | The skill with which to use the item |
items_to_collect | The list of close good items |
items_to_avoid | The list of close bad items |
|
private |
Handle cake depending on the chosen strategy Level 2 : Use the cake against any close vulnerable enemy, with priority to those ahead and close, check if the enemy is roughly ahead.
Level 3 : Level 2 and don't fire on slower karts Level 4 : Level 3 and fire if the kart has a swatter which may hit us Level 5 : Level 4 and don't fire on a shielded kart if we're just behind (gum)
item_skill | The skill with which to use the item |
|
private |
Decides if the currently selected aim at point (as determined by handleSteering) should be changed in order to collect/avoid an item.
There are 5 potential phases:
aim_point | Currently selected point to aim at. If the AI should try to collect an item, this value will be changed. |
last_node | Index of the graph node on which the aim_point is. |
|
private |
Handle all items depending on the chosen strategy.
Level 0 "AI" : do nothing (not used by default) Level 1 "AI" : use items after a random time Level 2 to 5 AI : strategy detailed before each item Each successive level is overall stronger (5 the strongest, 2 the weakest of non-random strategies), but two levels may share a strategy for a given item.
dt | Time step size. STATE: shield on -> avoid usage of offensive items (with certain tolerance) STATE: swatter on -> avoid usage of shield |
Either (low level AI) just use an item after 10 seconds, or do a much better job on higher level AI - e.g. aiming at karts ahead/behind, wait an appropriate time before using multiple items etc.
dt | Time step size. TODO: Implications of Bubble-Shield for AI's powerup-handling |
STATE: shield on -> avoid usage of offensive items (with certain tolerance) STATE: swatter on -> avoid usage of shield
|
private |
Decides wether to use nitro and zipper or not.
Decides wether to use nitro or not.
This function is called when the AI is trying to hit an item that is pre-selected to be collected.
The AI only evaluates if it's still feasible/useful to try to collect this item, or abandon it (and then look for a new item). At item is unselected if the kart has passed it (so collecting it would require the kart to reverse).
kart_aim_angle | The angle towards the current aim_point. |
aim_point | The current aim_point. |
last_node |
|
private |
Decides in which direction to steer.
If the kart is off track, it will steer towards the center of the track. Otherwise it will call one of the findNonCrashingPoint() functions to determine a point to aim for. Then it will evaluate items to see if it should aim for any items or try to avoid item, and potentially adjust the aim-at point, before computing the steer direction to arrive at the currently aim-at point.
dt | Time step size. |
|
private |
Handle the swatter depending on the chosen strategy Level 2 : Use the swatter immediately after a wait time Level 3 : Use the swatter when enemies are close Level 4 : Level 3 and use the swatter to remove bad attachments Level 5 : Level 4 and use against bomb only when the timer ends.
item_skill | The skill with which to use the item |
|
private |
Handle switch depending on the chosen strategy Level 2 : Use the switch after a wait time Level 3 : Same as level 2 but don't fire if close to a good item Level 4 : Same as level 3 and fire if very close to a bad item Level 5 : Use if it makes a better item available, or if very close to a bad item.
Don't use it if too close of a good item.
item_skill | The skill with which to use the item |
items_to_collect | The list of close good items |
items_to_avoid | The list of close bad items |
|
private |
Returns true if the AI would hit any of the listed bad items when trying to drive towards the specified item.
item | The item the AI is evaluating for collection. |
items_to_aovid | A list of bad items close by. All of these needs to be avoided. |
|
privatevirtual |
Converts the steering angle to a lr steering in the range of -1 to 1.
If the steering angle is too great, it will also trigger skidding. This function uses a 'time till full steer' value specifying the time it takes for the wheel to reach full left/right steering similar to player karts when using a digital input device. The parameter is defined in the kart properties and helps somewhat to make AI karts more 'pushable' (since otherwise the karts counter-steer to fast). It also takes the effect of a plunger into account by restricting the actual steer angle to 50% of the maximum.
angle | Steering angle. |
dt | Time step. |
Reimplemented from AIBaseController.
|
private |
Decides if steering is necessary to avoid bad items.
If so, it modifies the aim_point and returns true.
items_to_avoid | List of items to avoid. |
line_to_target | The 2d line from the current kart position to the current aim point. |
aim_point | The point the AI is steering towards (not taking items into account). |
|
virtual |
This is the main entry point for the AI.
It is called once per frame for each AI and determines the behaviour of the AI, e.g. steering, accelerating/braking, firing.
Reimplemented from AIBaseLapController.
|
private |
True if items to avoid are close by.
Used to avoid using zippers (which would make it more difficult to avoid items).
|
private |
The radius of the curve the kart is currently driving.
Undefined when being on a straigt section.
|
private |
The direction of the track where the kart is on atm.
|
private |
Stores the center of the curve (if the kart is in a curve, otherwise undefined).
|
private |
Distance to the kart ahead.
|
private |
Distance to the kard behind.
|
private |
Distance to the player, used for rubber-banding.
|
private |
If set an item that the AI should aim for.
|
private |
Pointer to the closest kart ahead of this kart.
NULL if this kart is first.
|
private |
Pointer to the closest kart behind this kart.
NULL if this kart is last.
|
private |
The index of the last node with the same direction as the current node the kart is on.
If kart is in a left turn, this will be the last node that is still turning left etc.
|
private |
The last item selected for collection, for which a probability was determined.
|
private |
Number of players ahead, used for rubber-banding.
enum { ... } SkiddingAI::m_point_selection_algorithm |
Determines the algorithm to use to select the point-to-aim-for There are two different Point Selection Algorithms:
So far the default one has by far the best performance, even though it has bugs.
|
private |
A random number generator for collecting items.
|
private |
A random number generator to decide if the AI should skid or not.
|
private |
True if m_last_item_random was randomly selected to be collected.
enum { ... } SkiddingAI::m_skid_probability_state |
This implements a simple finite state machine: it starts in NOT_YET.
The first time the AI decides to skid, the state is changed randomly (depending on skid probability) to NO_SKID or SKID. As long as the AI keeps on deciding to skid, the state remains unchanged (so no new random decision is made) till it decides not to skid. In which case the state is set to NOT_YET again. This guarantees that for each 'skidable' section of the track the random decision is only done once.
|
private |
The actual start delay used in ticks.
|
private |
Direction of crash: -1 = left, 1 = right, 0 = no crash.
|
private |
Time an item has been collected and not used.