1) Added support for AI steering variations: AI karts will now not

steer to the same driveline point, but to points slightly to
   the left and right. The maximum variation is defined in
   stk_config.xml (and should be between 0 and 1).
   ATM THIS IS DISABLED! Since in my tests it appears that
   the AI is not driving as good as previously anymore, i.e.
   it drives more S-lines on straights etc. To enable this change
   steering_variation in stk_config.xml
2) AI now handles multi-items better by waiting a certain amount
   of time before using the next item.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@6123 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk
2010-09-23 07:21:52 +00:00
parent cbf089ce40
commit 2c7213b83e
11 changed files with 90 additions and 25 deletions

View File

@@ -268,7 +268,7 @@
Maximum value should be 1 (steer towards left/right side
of driveline), 0 means exactly towards quad center point.
Depending on kart id karts will aim at different points.-->
<ai steering-variation="0.5" />
<ai steering-variation="0.0" />
</general-kart-defaults>
</config>

View File

@@ -46,7 +46,8 @@
#include "tracks/track.hpp"
#include "utils/constants.hpp"
DefaultAIController::DefaultAIController(Kart *kart) : AIBaseController(kart)
DefaultAIController::DefaultAIController(Kart *kart, unsigned int kart_id)
: AIBaseController(kart)
{
m_next_node_index.reserve(m_quad_graph->getNumNodes());
m_successor_index.reserve(m_quad_graph->getNumNodes());
@@ -88,6 +89,23 @@ DefaultAIController::DefaultAIController(Kart *kart) : AIBaseController(kart)
// Reset must be called after m_quad_graph etc. is set up
reset();
float variation = m_kart->getKartProperties()->getAISteeringVariation();
unsigned int num_ai_karts = race_manager->getNumberOfKarts()
- race_manager->getNumPlayers();
if(num_ai_karts==1)
{
m_steering_variation = 0;
}
else
{
m_steering_variation = 2*kart_id /(num_ai_karts-1) - 1.0f;
}
// The steering varition gets further adjusted by AI level -
// higher level AI will have less variation --> more potential
// slipstreaming.
m_steering_variation *= m_kart->getKartProperties()->getAISteeringVariation();
switch( race_manager->getDifficulty())
{
case RaceManager::RD_EASY:
@@ -127,6 +145,7 @@ DefaultAIController::DefaultAIController(Kart *kart) : AIBaseController(kart)
m_min_steps = 2;
m_nitro_level = NITRO_ALL;
m_handle_bomb = true;
m_steering_variation *= 0.5f;
setSkiddingFraction(2.0f);
break;
}
@@ -498,6 +517,9 @@ void DefaultAIController::handleItems( const float DELTA, const int STEPS )
break;
case PowerupManager::POWERUP_BUBBLEGUM:
// Avoid dropping all bubble gums one after another
if( m_time_since_last_shot >3.0f) break;
// Either use the bubble gum after 10 seconds, or if the next kart
// behind is 'close' but not too close (too close likely means that the
// kart is not behind but more to the side of this kart and so won't
@@ -505,15 +527,17 @@ void DefaultAIController::handleItems( const float DELTA, const int STEPS )
// kart as well? I.e. only drop if the kart behind is faster? Otoh
// this approach helps preventing an overtaken kart to overtake us
// again.
// Don't drop bubble gums too quickly, wait at least three seconds
m_controls->m_fire = (m_distance_behind < 15.0f &&
m_distance_behind > 3.0f ) ||
m_time_since_last_shot>10.0f;
m_distance_behind > 3.0f );
break;
// All the thrown/fired items might be improved by considering the angle
// towards m_kart_ahead. And some of them can fire backwards, too - which
// isn't yet supported for AI karts.
case PowerupManager::POWERUP_CAKE:
{
// Leave some time between shots
if(m_time_since_last_shot<3.0f) break;
// Since cakes can be fired all around, just use a sane distance
// with a bit of extra for backwards, as enemy will go towards cake
bool fire_backwards = (m_kart_behind && m_kart_ahead &&
@@ -522,14 +546,17 @@ void DefaultAIController::handleItems( const float DELTA, const int STEPS )
float distance = fire_backwards ? m_distance_behind
: m_distance_ahead;
m_controls->m_fire = (fire_backwards && distance < 25.0f) ||
(!fire_backwards && distance < 20.0f) ||
m_time_since_last_shot > 10.0f;
(!fire_backwards && distance < 20.0f);
if(m_controls->m_fire)
m_controls->m_look_back = fire_backwards;
break;
}
case PowerupManager::POWERUP_BOWLING:
{
// Leave more time between bowling balls, since they are
// slower, so it should take longer to hit something which
// can result in changing our target.
if(m_time_since_last_shot < 5.0f) break;
// Bowling balls slower, so only fire on closer karts - but when
// firing backwards, the kart can be further away, since the ball
// acts a bit like a mine (and the kart is racing towards it, too)
@@ -538,15 +565,19 @@ void DefaultAIController::handleItems( const float DELTA, const int STEPS )
!m_kart_ahead;
float distance = fire_backwards ? m_distance_behind
: m_distance_ahead;
m_controls->m_fire = (fire_backwards && distance < 30.0f) ||
(!fire_backwards && distance <10.0f) ||
m_time_since_last_shot > 10.0f;
m_controls->m_fire = ( (fire_backwards && distance < 30.0f) ||
(!fire_backwards && distance <10.0f) ) &&
m_time_since_last_shot > 3.0f;
if(m_controls->m_fire)
m_controls->m_look_back = fire_backwards;
break;
}
case PowerupManager::POWERUP_PLUNGER:
{
// Leave more time after a plunger, since it will take some
// time before a plunger effect becomes obvious.
if(m_time_since_last_shot < 5.0f) break;
// Plungers can be fired backwards and are faster,
// so allow more distance for shooting.
bool fire_backwards = (m_kart_behind && m_kart_ahead &&
@@ -561,6 +592,9 @@ void DefaultAIController::handleItems( const float DELTA, const int STEPS )
break;
}
case PowerupManager::POWERUP_ANVIL:
// Wait one second more than a previous anvil ... just in case
if(m_time_since_last_shot < stk_config->m_anvil_time+1.0f) break;
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
{
m_controls->m_fire = m_world->getTime()<1.0f &&
@@ -889,7 +923,8 @@ void DefaultAIController::findNonCrashingPoint(Vec3 *result)
target_sector = m_next_node_index[sector];
//direction is a vector from our kart to the sectors we are testing
direction = m_quad_graph->getQuad(target_sector).getCenter()
direction = m_quad_graph->getSideOfCenter(target_sector,
m_steering_variation);
- m_kart->getXYZ();
float len=direction.length_2d();
@@ -916,7 +951,8 @@ void DefaultAIController::findNonCrashingPoint(Vec3 *result)
if ( distance + m_kart_width * 0.5f
> m_quad_graph->getNode(sector).getPathWidth() )
{
*result = m_quad_graph->getQuad(sector).getCenter();
*result=m_quad_graph->getSideOfCenter(sector,
m_steering_variation);
return;
}
}

View File

@@ -109,6 +109,10 @@ private:
float m_curve_target_speed;
float m_curve_angle;
/** Indicates how much to the left/right of the center driveline point
* the AI should aim at in order to avoid AIs creating trains. */
float m_steering_variation;
/** The current node the kart is on. This can be different from the value
* in LinearWorld, since it takes the chosen path of the AI into account
* (e.g. the closest point in LinearWorld might be on a branch not
@@ -158,7 +162,7 @@ protected:
virtual unsigned int getNextSector(unsigned int index);
public:
DefaultAIController(Kart *kart);
DefaultAIController(Kart *kart, unsigned kart_id);
~DefaultAIController();
virtual void update (float delta) ;
virtual void reset ();

View File

@@ -46,7 +46,8 @@
#include "tracks/track.hpp"
#include "utils/constants.hpp"
NewAIController::NewAIController(Kart *kart) : AIBaseController(kart)
NewAIController::NewAIController(Kart *kart, unsigned int kart_id)
: AIBaseController(kart)
{
m_next_node_index.reserve(m_quad_graph->getNumNodes());
m_successor_index.reserve(m_quad_graph->getNumNodes());

View File

@@ -161,7 +161,7 @@ protected:
virtual unsigned int getNextSector(unsigned int index);
public:
NewAIController(Kart *kart);
NewAIController(Kart *kart, unsigned int kart_id);
virtual ~NewAIController();
virtual void update (float delta) ;
virtual void reset ();

View File

@@ -92,7 +92,7 @@ Kart *ProfileWorld::createKart(const std::string &kart_ident, int index,
race_manager->getNumberOfKarts()-1);
Kart *new_kart = new Kart(prof_kart_id, index+1, init_pos);
Controller *controller = loadAIController(new_kart);
Controller *controller = loadAIController(new_kart, index);
new_kart->setController(controller);
// Create a camera for the last kart (since this way more of the

View File

@@ -171,14 +171,14 @@ void World::init()
* this player globally (i.e. including network players).
* \param init_pos The start transform (xyz and hpr).
*/
Kart *World::createKart(const std::string &kart_ident, int index,
Kart *World::createKart(const std::string &kart_ident, int kart_id,
int local_player_id, int global_player_id,
const btTransform &init_pos)
{
int position = index+1;
int position = kart_id+1;
Kart *new_kart = new Kart(kart_ident, position, init_pos);
Controller *controller = NULL;
switch(race_manager->getKartType(index))
switch(race_manager->getKartType(kart_id))
{
case RaceManager::KT_PLAYER:
controller = new PlayerController(new_kart,
@@ -193,7 +193,7 @@ Kart *World::createKart(const std::string &kart_ident, int index,
//m_num_players++;
//break;
case RaceManager::KT_AI:
controller = loadAIController(new_kart);
controller = loadAIController(new_kart, kart_id);
break;
case RaceManager::KT_GHOST:
break;
@@ -208,7 +208,7 @@ Kart *World::createKart(const std::string &kart_ident, int index,
/** Creates an AI controller for the kart.
* \param kart The kart to be controlled by an AI.
*/
Controller* World::loadAIController(Kart *kart)
Controller* World::loadAIController(Kart *kart, unsigned int kart_id)
{
Controller *controller;
// const int NUM_ROBOTS = 1;
@@ -222,14 +222,14 @@ Controller* World::loadAIController(Kart *kart)
switch(turn)
{
case 0:
controller = new DefaultAIController(kart);
controller = new DefaultAIController(kart, kart_id);
break;
case 1:
controller = new NewAIController(kart);
controller = new NewAIController(kart, kart_id);
break;
default:
std::cerr << "Warning: Unknown robot, using default." << std::endl;
controller = new DefaultAIController(kart);
controller = new DefaultAIController(kart, kart_id);
break;
}

View File

@@ -112,9 +112,9 @@ protected:
void resetAllKarts ();
void removeKart (int kart_number, bool notifyOfElimination=true);
Controller*
loadAIController (Kart *kart);
loadAIController (Kart *kart, unsigned int kart_id);
virtual Kart *createKart(const std::string &kart_ident, int index,
virtual Kart *createKart(const std::string &kart_ident, int kart_id,
int local_player_id, int global_player_id,
const btTransform &init_pos);
/** Pointer to the track. The track is managed by world. */

View File

@@ -56,6 +56,8 @@ GraphNode::GraphNode(unsigned int index)
upper.getX(), upper.getZ() );
// Only this 2d point is needed later
m_lower_center = core::vector2df(lower.getX(), lower.getZ());
m_center_to_right = (quad[1]+quad[2])*0.5f-quad.getCenter();
} // GraphNode
// ----------------------------------------------------------------------------
@@ -129,3 +131,13 @@ float GraphNode::getDistance2FromPoint(const Vec3 &xyz)
core::vector2df closest = m_line.getClosestPoint(xyz2d);
return (closest-xyz2d).getLengthSQ();
} // getDistance2FromPoint
// ----------------------------------------------------------------------------
/** Returns a point to the right (f>0) or left (f<0) of the center
* of a node. |f| <=1, with f=0 returning exactly the center point,
* and f=+-1 returning the point on the right/left edge of the node.
*/
Vec3 GraphNode::getSideOfCenter(float f) const
{
return m_all_quads->getCenterOfQuad(m_index)+f*m_center_to_right;
} // getSideOfCenter

View File

@@ -71,6 +71,10 @@ class GraphNode
* saves computation, and it is only needed to determine the distance
* from the center of the drivelines anyway. */
core::line2df m_line;
/** A vector from the center of the quad to the center of the right
* side. This is used in getSideOfCenter. */
Vec3 m_center_to_right;
public:
/** Keep a shared pointer so that some asserts and tests can be
* done without adding additional parameters. */
@@ -83,6 +87,7 @@ public:
void addSuccessor (unsigned int to);
void getDistances(const Vec3 &xyz, Vec3 *result);
float getDistance2FromPoint(const Vec3 &xyz);
Vec3 getSideOfCenter(float f) const;
/** Returns the i-th successor. */
unsigned int getSuccessor(unsigned int i) const
@@ -111,6 +116,7 @@ public:
// -------------------------------------------------------------------
/** Returns the width of the part for this quad. */
float getPathWidth() const { return m_width; }
// -------------------------------------------------------------------
/** Returns the center point of the lower edge of this graph node. */
const core::vector2df& getLowerCenter() const {return m_lower_center;}

View File

@@ -117,6 +117,12 @@ public:
/** Returns the length of the main driveline. */
float getLapLength() const {return m_lap_length; }
// ----------------------------------------------------------------------
/** Returns a point to the right (f>0) or left (f<0) of the center
* of a node. |f| <=1, with f=0 returning exactly the center point,
* and f=+-1 returning the point on the right/left edge of the node.
*/
Vec3 getSideOfCenter(unsigned int j, float f) const
{ return m_all_nodes[j]->getSideOfCenter(f); }
}; // QuadGraph
#endif