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:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user