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:
parent
f876c9d696
commit
913596663b
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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*
|
||||
|
Loading…
Reference in New Issue
Block a user