1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2006-2009  Eduardo Hernandez Munoz
4 //  Copyright (C) 2009-2015  Joerg Henrichs
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 3
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 #include "karts/controller/ai_base_lap_controller.hpp"
21 
22 #include <assert.h>
23 
24 #include "karts/abstract_kart.hpp"
25 #include "karts/kart_properties.hpp"
26 #include "karts/controller/ai_properties.hpp"
27 #include "modes/linear_world.hpp"
28 #include "tracks/drive_graph.hpp"
29 #include "tracks/track.hpp"
30 #include "utils/constants.hpp"
31 
32 
33 /**
34 This is the base class for all AIs. At this stage there are two similar
35 AIs: one is the SkiddingAI, which is the AI used in lap based races
36 (including follow-the-leader mode), the other one is the end controller,
37 I.e. the controller that takes over from a player (or AI) when the race is
38 finished.
39 
40 This base class defines some basic operations:
41 - It takes care on which part of the DriveGraph the AI currently is.
42 - It determines which path the AI should take (in case of shortcuts
43   or forks in the road).
44 
45 At race start and every time a new lap is started, the AI will compute the
46 path the kart is taking this lap (computePath). At this stage the decision
47 which road in case of shortcut to take is purely random. It stores the
48 information in two arrays:
49   m_successor_index[i] stores which successor to take from node i.
50        The successor is a number between 0 and number_of_successors - 1.
51   m_next_node_index[i] stores the actual index of the graph node that
52        follows after node i.
53 Depending on operation one of the other data is more useful, so this
54 class stores both information to avoid looking it up over and over.
55 Once this is done (still in computePath), the array m_all_look_aheads is
56 computed. This array stores for each quad a list of the next (atm) 10 quads.
57 This is used when the AI is selecting where to drive next, and it will just
58 pass the list of next quads to findRoadSector.
59 
60 Note that the quad graph information is stored for every quad in the quad
61 graph, even if the quad is not on the path chosen. This is necessary since
62 it can happen that a kart ends up on a path not choses (e.g. perhaps it was
63 pushed on that part, or couldn't get a sharp corner).
64 
65 In update(), which gets called one per frame per AI, this object will
66 determine the quad the kart is currently on (which is then used to determine
67 where the kart will be driving to). This uses the m_all_look_aheads to
68 speed up this process (since the kart is likely to be either on the same
69 quad as it was before, or the next quad in the m_all_look_aheads list).
70 
71 It will also check if the kart is stuck:
72 this is done by maintaining a list of times when the kart hits the track. If
73 (atm) more than 3 collisions happen in 1.5 seconds, the kart is considered
74 stuck and will trigger a rescue (due to the pushback from the track it will
75 take some time if a kart is really stuck before it will hit the track again).
76 
77 This base class also contains some convenience functions which are useful
78 in all AIs, e.g.:
79 -  steerToPoint: determine the steering angle to use depending on the
80    current location and the point the kart is driving to.
81 -  normalizeAngle: To normalise the steering angle to be in [-PI,PI].
82 -  setSteering: Converts the steering angle into a steering fraction
83    in [-1,1].
84 
85 */
AIBaseLapController(AbstractKart * kart)86 AIBaseLapController::AIBaseLapController(AbstractKart *kart)
87                    : AIBaseController(kart)
88 {
89 
90     if (!RaceManager::get()->isBattleMode() &&
91         RaceManager::get()->getMinorMode()!=RaceManager::MINOR_MODE_SOCCER)
92     {
93         m_world     = dynamic_cast<LinearWorld*>(World::getWorld());
94         m_track     = Track::getCurrentTrack();
95         computePath();
96     }
97     else
98     {
99         // Those variables are not defined in a battle mode (m_world is
100         // a linear world, since it assumes the existance of drivelines)
101         m_world           = NULL;
102         m_track           = NULL;
103         m_next_node_index.clear();
104         m_all_look_aheads.clear();
105         m_successor_index.clear();
106     }   // if battle mode
107     // Don't call our own setControllerName, since this will add a
108     // billboard showing 'AIBaseLapController' to the kar.
109     Controller::setControllerName("AIBaseLapController");
110 }   // AIBaseLapController
111 
112 //-----------------------------------------------------------------------------
reset()113 void AIBaseLapController::reset()
114 {
115     AIBaseController::reset();
116 }   // reset
117 
118 
119 
120 //-----------------------------------------------------------------------------
121 /** Triggers a recomputation of the path to use, so that the AI does not
122  *  always use the same way.
123  */
newLap(int lap)124 void  AIBaseLapController::newLap(int lap)
125 {
126     if(lap>0)
127     {
128         computePath();
129     }
130 }   // newLap
131 
132 //-----------------------------------------------------------------------------
133 /** Computes a path for the AI to follow. This function is called at race
134  *  start and every time a new lap is started. Recomputing the path every
135  *  time will mean that the kart will not always take the same path, but
136  *  (potentially) vary from lap to lap. At this stage the decision is done
137  *  randomly. The AI could be improved by collecting more information about
138  *  each branch of a track, and selecting the 'appropriate' one (e.g. if the
139  *  AI is far ahead, chose a longer/slower path).
140  */
computePath()141 void AIBaseLapController::computePath()
142 {
143     m_next_node_index.resize(DriveGraph::get()->getNumNodes());
144     m_successor_index.resize(DriveGraph::get()->getNumNodes());
145     std::vector<unsigned int> next;
146     for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
147     {
148         next.clear();
149         // Get all successors the AI is allowed to take.
150         DriveGraph::get()->getSuccessors(i, next, /*for_ai*/true);
151         // In case of short cuts hidden for the AI it can be that a node
152         // might not have a successor (since the first and last edge of
153         // a hidden shortcut is ignored). Since in the case that the AI
154         // ends up on a short cut (e.g. by accident) and doesn't have an
155         // allowed way to drive, it should still be able to drive, so add
156         // the non-AI successors of that node in this case.
157         if(next.size()==0)
158             DriveGraph::get()->getSuccessors(i, next, /*for_ai*/false);
159         // For now pick one part on random, which is not adjusted during the
160         // race. Long term statistics might be gathered to determine the
161         // best way, potentially depending on race position etc.
162         int r = rand();
163         int indx = (int)( r / ((float)(RAND_MAX)+1.0f) * next.size() );
164         // In case of rounding errors0
165         if(indx>=(int)next.size()) indx--;
166         m_successor_index[i] = indx;
167         assert(indx <(int)next.size() && indx>=0);
168         m_next_node_index[i] = next[indx];
169     }
170 
171     const unsigned int look_ahead=10;
172     // Now compute for each node in the graph the list of the next 'look_ahead'
173     // graph nodes. This is the list of node that is tested in checkCrashes.
174     // If the look_ahead is too big, the AI can skip loops (see
175     // Graph::findRoadSector for details), if it's too short the AI won't
176     // find too good a driveline. Note that in general this list should
177     // be computed recursively, but since the AI for now is using only
178     // (randomly picked) path this is fine
179     m_all_look_aheads.resize(DriveGraph::get()->getNumNodes());
180     for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
181     {
182         std::vector<int> l;
183         int current = i;
184         for(unsigned int j=0; j<look_ahead; j++)
185         {
186             assert(current < (int)m_next_node_index.size());
187             l.push_back(m_next_node_index[current]);
188             current = m_next_node_index[current];
189         }   // for j<look_ahead
190         m_all_look_aheads[i] = l;
191     }
192 }   // computePath
193 
194 //-----------------------------------------------------------------------------
195 /** Updates the ai base controller each time step. Note that any calls to
196  *  isStuck() must be done before update is called, since update will call
197  *  AIBaseController::update() which will reset the isStuck flag!
198  *  \param ticks Number of physics time steps - should be 1.
199  */
update(int ticks)200 void AIBaseLapController::update(int ticks)
201 {
202     AIBaseController::update(ticks);
203     if(DriveGraph::get() && m_world)
204     {
205         // Update the current node:
206         int old_node = m_track_node;
207         if(m_track_node!=Graph::UNKNOWN_SECTOR)
208         {
209             DriveGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node,
210                 &m_all_look_aheads[m_track_node]);
211         }
212         // If we can't find a proper place on the track, to a broader search
213         // on off-track locations.
214         if(m_track_node==Graph::UNKNOWN_SECTOR)
215         {
216             m_track_node = DriveGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
217         }
218         // IF the AI is off track (or on a branch of the track it did not
219         // select to be on), keep the old position.
220         if(m_track_node==Graph::UNKNOWN_SECTOR ||
221             m_next_node_index[m_track_node]==-1)
222             m_track_node = old_node;
223     }
224 }   // update
225 
226 //-----------------------------------------------------------------------------
227 /** Returns the next sector of the given sector index. This is used
228  *  for branches in the quad graph to select which way the AI kart should
229  *  go. This is a very simple implementation that always returns the first
230  *  successor, but it can be overridden to allow a better selection.
231  *  \param index Index of the graph node for which the successor is searched.
232  *  \return Returns the successor of this graph node.
233  */
getNextSector(unsigned int index)234 unsigned int AIBaseLapController::getNextSector(unsigned int index)
235 {
236     std::vector<unsigned int> successors;
237     DriveGraph::get()->getSuccessors(index, successors);
238     return successors[0];
239 }   // getNextSector
240 
241 //-----------------------------------------------------------------------------
242 /** This function steers towards a given angle. It also takes a plunger
243  ** attached to this kart into account by modifying the actual steer angle
244  *  somewhat to simulate driving without seeing.
245  */
steerToAngle(const unsigned int sector,const float add_angle)246 float AIBaseLapController::steerToAngle(const unsigned int sector,
247                                      const float add_angle)
248 {
249     float angle = DriveGraph::get()->getAngleToNext(sector,
250                                                     getNextSector(sector));
251 
252     //Desired angle minus current angle equals how many angles to turn
253     float steer_angle = angle - m_kart->getHeading();
254 
255     if(m_kart->getBlockedByPlungerTicks()>0)
256         steer_angle += add_angle*0.2f;
257     else
258         steer_angle += add_angle;
259     steer_angle = normalizeAngle( steer_angle );
260 
261     return steer_angle;
262 }   // steerToAngle
263