The AI now picks a different (random) path for each lap.

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7689 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-02-12 07:35:34 +00:00
parent f876c9d696
commit 913596663b
6 changed files with 98 additions and 85 deletions

View File

@ -40,49 +40,7 @@ AIBaseController::AIBaseController(Kart *kart,
m_world = dynamic_cast<LinearWorld*>(World::getWorld());
m_track = m_world->getTrack();
m_quad_graph = &m_track->getQuadGraph();
m_next_node_index.reserve(m_quad_graph->getNumNodes());
m_successor_index.reserve(m_quad_graph->getNumNodes());
std::vector<unsigned int> next;
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
{
next.clear();
m_quad_graph->getSuccessors(i, next);
// For now pick one part on random, which is not adjusted during the
// race. Long term statistics might be gathered to determine the
// best way, potentially depending on race position etc.
int r = rand();
int indx = (int)( r / ((float)(RAND_MAX)+1.0f) * next.size() );
// In case of rounding errors0
if(indx>=(int)next.size()) indx--;
m_successor_index.push_back(indx);
assert(indx <(int)next.size() && indx>=0);
m_next_node_index.push_back(next[indx]);
}
const unsigned int look_ahead=10;
// Now compute for each node in the graph the list of the next 'look_ahead'
// graph nodes. This is the list of node that is tested in checkCrashes.
// If the look_ahead is too big, the AI can skip loops (see
// QuadGraph::findRoadSector for details), if it's too short the AI won't
// find too good a driveline. Note that in general this list should
// be computed recursively, but since the AI for now is using only
// (randomly picked) path this is fine
m_all_look_aheads.reserve(m_quad_graph->getNumNodes());
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
{
std::vector<int> l;
int current = i;
for(unsigned int j=0; j<look_ahead; j++)
{
assert(current < (int)m_next_node_index.size());
l.push_back(m_next_node_index[current]);
current = m_next_node_index[current];
} // for j<look_ahead
m_all_look_aheads.push_back(l);
}
computePath();
}
else
{
@ -98,6 +56,65 @@ AIBaseController::AIBaseController(Kart *kart,
} // AIBaseController
//-----------------------------------------------------------------------------
/** Triggers a recomputation of the path to use, so that the AI does not
* always use the same way.
*/
void AIBaseController::newLap(int lap)
{
if(lap>0)
{
computePath();
}
} // newLap
//-----------------------------------------------------------------------------
/** Computes a path for the AI to follow.
*/
void AIBaseController::computePath()
{
m_next_node_index.resize(m_quad_graph->getNumNodes());
m_successor_index.resize(m_quad_graph->getNumNodes());
std::vector<unsigned int> next;
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
{
next.clear();
m_quad_graph->getSuccessors(i, next);
// For now pick one part on random, which is not adjusted during the
// race. Long term statistics might be gathered to determine the
// best way, potentially depending on race position etc.
int r = rand();
int indx = (int)( r / ((float)(RAND_MAX)+1.0f) * next.size() );
// In case of rounding errors0
if(indx>=(int)next.size()) indx--;
m_successor_index[i] = indx;
assert(indx <(int)next.size() && indx>=0);
m_next_node_index[i] = next[indx];
}
const unsigned int look_ahead=10;
// Now compute for each node in the graph the list of the next 'look_ahead'
// graph nodes. This is the list of node that is tested in checkCrashes.
// If the look_ahead is too big, the AI can skip loops (see
// QuadGraph::findRoadSector for details), if it's too short the AI won't
// find too good a driveline. Note that in general this list should
// be computed recursively, but since the AI for now is using only
// (randomly picked) path this is fine
m_all_look_aheads.resize(m_quad_graph->getNumNodes());
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
{
std::vector<int> l;
int current = i;
for(unsigned int j=0; j<look_ahead; j++)
{
assert(current < (int)m_next_node_index.size());
l.push_back(m_next_node_index[current]);
current = m_next_node_index[current];
} // for j<look_ahead
m_all_look_aheads[i] = l;
}
} // computePath
//-----------------------------------------------------------------------------
void AIBaseController::update(float dt)
{

View File

@ -74,12 +74,15 @@ protected:
std::vector<std::vector<int> > m_all_look_aheads;
virtual void update (float delta) ;
virtual unsigned int getNextSector(unsigned int index);
virtual void newLap (int lap);
float steerToAngle (const unsigned int sector, const float angle);
float steerToPoint (const Vec3 &point);
float normalizeAngle(float angle);
void setSteering (float angle, float dt);
void setSkiddingFraction(float f);
virtual unsigned int getNextSector(unsigned int index);
void computePath();
public:
AIBaseController(Kart *kart,
StateManager::ActivePlayer *player=NULL);

View File

@ -65,6 +65,9 @@ public:
virtual bool isNetworkController() const {return false;}
/** Default: ignore actions. Only PlayerController get them. */
virtual void action (PlayerAction action, int value) {}
/** Callback whenever a new lap is triggered. Used by the AI
* to trigger a recomputation of the way to use. */
virtual void newLap (int lap) {}
virtual const irr::core::stringw& getNamePostfix() const;
}; // Controller

View File

@ -22,7 +22,7 @@
//The AI debugging works best with just 1 AI kart, so set the number of karts
//to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
#undef AI_DEBUG
#define AI_DEBUG
#include "karts/controller/default_ai_controller.hpp"
@ -410,9 +410,6 @@ void DefaultAIController::handleSteering(float dt)
m_debug_sphere->setPosition(straight_point.toIrrVector());
#endif
steer_angle = steerToPoint(straight_point);
#ifdef AI_DEBUG
std::cout << "- Fallback." << std::endl;
#endif
}
setSteering(steer_angle, dt);

View File

@ -283,13 +283,13 @@ void LinearWorld::newLap(unsigned int kart_index)
if(kart_info.m_race_lap+1 <= lap_count)
{
assert(kart->getWorldKartId()==kart_index);
setTimeAtLapForKart(getTime(), kart_index );
kart_info.m_time_at_last_lap=getTime();
kart_info.m_race_lap++ ;
}
// Last lap message (kart_index's assert in previous block already)
if(kart_info.m_race_lap+1 == lap_count)
{
m_race_gui->addMessage(_("Final lap!"), m_karts[kart_index],
m_race_gui->addMessage(_("Final lap!"), kart,
3.0f, 40, video::SColor(255, 210, 100, 50), true);
if(!m_last_lap_sfx_played && lap_count > 1)
{
@ -307,7 +307,7 @@ void LinearWorld::newLap(unsigned int kart_index)
else if (kart_info.m_race_lap > 0 && kart_info.m_race_lap+1 < lap_count)
{
m_race_gui->addMessage(_("Lap %i", kart_info.m_race_lap+1),
m_karts[kart_index], 3.0f, 40, video::SColor(255, 210, 100, 50), true);
kart, 3.0f, 40, video::SColor(255, 210, 100, 50), true);
}
// The race positions must be updated here: consider the situation where
@ -334,7 +334,7 @@ void LinearWorld::newLap(unsigned int kart_index)
// Race finished
if(kart_info.m_race_lap >= race_manager->getNumLaps() && raceHasLaps())
{
// A client wait does not detect race finished by itself, it will
// A client does not detect race finished by itself, it will
// receive a message from the server. So a client does not do
// anything here.
if(network_manager->getMode()!=NetworkManager::NW_CLIENT)
@ -342,35 +342,35 @@ void LinearWorld::newLap(unsigned int kart_index)
kart->finishedRace(getTime());
}
}
float time_per_lap;
if (kart_info.m_race_lap == 1) // just completed first lap
{
float time_per_lap;
if (kart_info.m_race_lap == 1) // just completed first lap
{
time_per_lap=getTime();
}
else //completing subsequent laps
{
time_per_lap=getTime() - kart_info.m_lap_start_time;
}
// if new fastest lap
if(time_per_lap < getFastestLapTime() && raceHasLaps() &&
kart_info.m_race_lap>0)
{
setFastestLap(kart, time_per_lap);
m_race_gui->addMessage(_("New fastest lap"), NULL,
2.0f, 40, video::SColor(255, 100, 210, 100), true);
std::string s = StringUtils::timeToString(time_per_lap);
irr::core::stringw m_fastest_lap_message;
//I18N: as in "fastest lap: 60 seconds by Wilber"
m_fastest_lap_message += _("%s by %s", s.c_str(), core::stringw(kart->getName()));
m_race_gui->addMessage(m_fastest_lap_message, NULL,
2.0f, 40, video::SColor(255, 100, 210, 100));
} // end if new fastest lap
time_per_lap=getTime();
}
else //completing subsequent laps
{
time_per_lap=getTime() - kart_info.m_lap_start_time;
}
// if new fastest lap
if(time_per_lap < getFastestLapTime() && raceHasLaps() &&
kart_info.m_race_lap>0)
{
setFastestLap(kart, time_per_lap);
m_race_gui->addMessage(_("New fastest lap"), NULL,
2.0f, 40, video::SColor(255, 100, 210, 100), true);
std::string s = StringUtils::timeToString(time_per_lap);
irr::core::stringw m_fastest_lap_message;
//I18N: as in "fastest lap: 60 seconds by Wilber"
m_fastest_lap_message += _("%s by %s", s.c_str(), core::stringw(kart->getName()));
m_race_gui->addMessage(m_fastest_lap_message, NULL,
2.0f, 40, video::SColor(255, 100, 210, 100));
} // end if new fastest lap
kart_info.m_lap_start_time = getTime();
kart->getController()->newLap(kart_info.m_race_lap);
} // newLap
//-----------------------------------------------------------------------------
@ -405,12 +405,6 @@ int LinearWorld::getLapForKart(const int kart_id) const
return m_kart_info[kart_id].m_race_lap;
} // getLapForKart
//-----------------------------------------------------------------------------
void LinearWorld::setTimeAtLapForKart(float t, const int kart_id)
{
m_kart_info[kart_id].m_time_at_last_lap=t;
} // setTimeAtLapForKart
//-----------------------------------------------------------------------------
/** Returns the estimated finishing time. Only valid during the last lap!
* \param kart_id Id of the kart.

View File

@ -95,7 +95,6 @@ public:
float getDistanceToCenterForKart(const int kart_id) const;
float getEstimatedFinishTime(const int kart_id) const;
int getLapForKart(const int kart_id) const;
void setTimeAtLapForKart(float t, const int kart_id);
float getTimeAtLapForKart(const int kart_id) const;
virtual RaceGUIBase::KartIconDisplayInfo*