Added alternative implementation of findNoNCrashingPoint
which should be faster and 'more correct' (the old implemenation only tests discrete points for being on/off track, which means AI can cut corner and not realise that it will be off track). The new implementation uses lines and intersections to detect this condition correctly. Since the new implementation is as a result not as aggressive in cutting corner, it's not as fast as the old AI, and is for now disabled (see end of SiddingAI::handleSteering if you want to switch). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11405 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
e58377b1ca
commit
3ec6682fb4
@ -110,17 +110,23 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1);
|
||||
#define CURVE_PREDICT1 0
|
||||
#define CURVE_PREDICT2 1
|
||||
#define CURVE_QG 2
|
||||
#define CURVE_KART 1
|
||||
#define CURVE_LEFT 2
|
||||
#define CURVE_RIGHT 3
|
||||
#define CURVE_QG 4
|
||||
#define NUM_CURVES (CURVE_QG+1)
|
||||
|
||||
m_curve = new ShowCurve*[NUM_CURVES];
|
||||
m_curve[CURVE_PREDICT1] = new ShowCurve(0.05f, 0.5f,
|
||||
irr::video::SColor(128, 0, 0, 128));
|
||||
m_curve[CURVE_PREDICT2] = new ShowCurve(0.05f, 0.5f,
|
||||
irr::video::SColor(128, 0, 0, 64));
|
||||
m_curve[CURVE_PREDICT1] = new ShowCurve(0.05f, 0.5f,
|
||||
irr::video::SColor(128, 0, 0, 128));
|
||||
m_curve[CURVE_KART] = new ShowCurve(0.5f, 0.5f,
|
||||
irr::video::SColor(128, 0, 0, 128));
|
||||
m_curve[CURVE_LEFT] = new ShowCurve(0.5f, 0.5f,
|
||||
irr::video::SColor(128, 128, 0, 0));
|
||||
m_curve[CURVE_RIGHT] = new ShowCurve(0.5f, 0.5f,
|
||||
irr::video::SColor(128, 0, 128, 0));
|
||||
m_curve[CURVE_QG] = new ShowCurve(0.5f, 0.5f,
|
||||
irr::video::SColor(128, 0, 128, 0));
|
||||
irr::video::SColor(128, 0, 128, 0));
|
||||
#endif
|
||||
setControllerName("Skidding");
|
||||
} // SkiddingAI
|
||||
@ -333,9 +339,9 @@ void SkiddingAI::handleBraking()
|
||||
m_kart->getSpeed() > MIN_SPEED)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
printf("[AI] braking: %s not aligned with track.\n",
|
||||
m_kart->getIdent().c_str());
|
||||
if(m_ai_debug)
|
||||
printf("[AI] braking: %s not aligned with track.\n",
|
||||
m_kart->getIdent().c_str());
|
||||
#endif
|
||||
m_controls->m_brake = true;
|
||||
return;
|
||||
@ -434,7 +440,12 @@ void SkiddingAI::handleSteering(float dt)
|
||||
{
|
||||
m_start_kart_crash_direction = 0;
|
||||
Vec3 straight_point;
|
||||
#ifdef NEW_ALGORITHM
|
||||
findNonCrashingPoint2(straight_point);
|
||||
#else
|
||||
findNonCrashingPoint(&straight_point);
|
||||
#endif
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(straight_point.toIrrVector());
|
||||
#endif
|
||||
@ -930,6 +941,154 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
|
||||
}
|
||||
} // checkCrashes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This is a new version of findNonCrashingPoint, which at this stage is
|
||||
* slightly inferior (though faster and more correct) than the original
|
||||
* version - the original code cuts corner more aggressively than this
|
||||
* version (and in most cases cuting the corner does not end in a
|
||||
* collision, so it's actually faster).
|
||||
* This version find the point furthest ahead which can be reached by
|
||||
* travelling in a straight direction from the current location of the
|
||||
* kart. This is done by using two lines: one from the kart to the
|
||||
* lower left side of the next quad, and one from the kart to the
|
||||
* lower right side of the next quad. The area between those two lines
|
||||
* can be reached by the kart in a straight line, and will not go off
|
||||
* track (assuming that the kart is on track). Then the next quads are
|
||||
* tested: New left/right lines are computed. If the new left line is to
|
||||
* the right of the old left line, the new left line becomes the current
|
||||
* left line:
|
||||
*
|
||||
* X The new left line connecting kart to X will be to the right
|
||||
* of the old left line, so the available space for the kart
|
||||
* \ / (
|
||||
* \ /
|
||||
* kart
|
||||
* Similarly for the right side. This will narrow down the available area
|
||||
* the kart can aim at, till finally the left and right line overlap.
|
||||
* All points between the connection of the two end points of the left and
|
||||
* right line can be reached without getting off track. Which point the
|
||||
* kart aims at then depends on the direction of the track: if there is
|
||||
* a left turn, the kart will aim to the left point (and vice versa for
|
||||
* right turn) - slightly offset by the width of the kart to avoid that
|
||||
* the kart is getting off track.
|
||||
* \return result The new point the kart should aim at when steering.
|
||||
*/
|
||||
void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
{
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
const core::vector2df xz = m_kart->getXYZ().toIrrVector2d();
|
||||
|
||||
const Quad &q = QuadGraph::get()->getQuadOfNode(sector);
|
||||
|
||||
// Index of the left and right end of a quad.
|
||||
const unsigned int LEFT_END_POINT = 0;
|
||||
const unsigned int RIGHT_END_POINT = 1;
|
||||
core::line2df left (xz, q[LEFT_END_POINT ].toIrrVector2d());
|
||||
core::line2df right(xz, q[RIGHT_END_POINT].toIrrVector2d());
|
||||
#ifdef AI_DEBUG
|
||||
const Vec3 eps(0,0.5f,0);
|
||||
m_curve[CURVE_LEFT]->clear();
|
||||
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps);
|
||||
m_curve[CURVE_LEFT]->addPoint(q[LEFT_END_POINT]+eps);
|
||||
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps);
|
||||
m_curve[CURVE_RIGHT]->clear();
|
||||
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps);
|
||||
m_curve[CURVE_RIGHT]->addPoint(q[RIGHT_END_POINT]+eps);
|
||||
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps);
|
||||
m_curve[CURVE_KART]->clear();
|
||||
m_curve[CURVE_KART]->addPoint(m_kart->getXYZ()+eps);
|
||||
Vec3 forw(0, 0, 50);
|
||||
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw));
|
||||
#endif
|
||||
while(1)
|
||||
{
|
||||
unsigned int next_sector = m_next_node_index[sector];
|
||||
const Quad &q_next = QuadGraph::get()->getQuadOfNode(next_sector);
|
||||
// Test if the next left point is to the right of the left
|
||||
// line. If so, a new left line is defined.
|
||||
if(left.getPointOrientation(q_next[LEFT_END_POINT].toIrrVector2d())
|
||||
< 0 )
|
||||
{
|
||||
core::vector2df p = q_next[LEFT_END_POINT].toIrrVector2d();
|
||||
// Stop if the new point is to the right of the right line
|
||||
if(right.getPointOrientation(p)<0)
|
||||
break;
|
||||
left.end = p;
|
||||
#ifdef AI_DEBUG
|
||||
Vec3 ppp(p.X, m_kart->getXYZ().getY(), p.Y);
|
||||
m_curve[CURVE_LEFT]->addPoint(ppp+eps);
|
||||
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test if new right point is to the left of the right line. If
|
||||
// so, a new right line is defined.
|
||||
if(right.getPointOrientation(q_next[RIGHT_END_POINT].toIrrVector2d())
|
||||
> 0 )
|
||||
{
|
||||
core::vector2df p = q_next[RIGHT_END_POINT].toIrrVector2d();
|
||||
// Break if new point is to the left of left line
|
||||
if(left.getPointOrientation(p)>0)
|
||||
break;
|
||||
#ifdef AI_DEBUG
|
||||
Vec3 ppp(p.X, m_kart->getXYZ().getY(), p.Y);
|
||||
m_curve[CURVE_RIGHT]->addPoint(ppp+eps);
|
||||
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps);
|
||||
#endif
|
||||
right.end = p;
|
||||
}
|
||||
sector = next_sector;
|
||||
} // while
|
||||
|
||||
// Now look for the next curve to find out to which side of the
|
||||
// track the AI should aim at
|
||||
|
||||
sector = m_track_node;
|
||||
int count = 0;
|
||||
while(1)
|
||||
{
|
||||
GraphNode::DirectionType dir;
|
||||
unsigned int last;
|
||||
unsigned int succ = m_successor_index[sector];
|
||||
const GraphNode &gn = QuadGraph::get()->getNode(sector);
|
||||
gn.getDirectionData(succ, &dir, &last);
|
||||
if(dir==GraphNode::DIR_LEFT)
|
||||
{
|
||||
core::vector2df diff = left.end - right.end;
|
||||
diff.normalize();
|
||||
diff *= m_kart->getKartWidth()*0.5f;
|
||||
*result = Vec3(left.end.X - diff.X,
|
||||
m_kart->getXYZ().getY(),
|
||||
left.end.Y - diff.Y);
|
||||
return;
|
||||
}
|
||||
else if(dir==GraphNode::DIR_RIGHT)
|
||||
{
|
||||
core::vector2df diff = right.end - left.end;
|
||||
diff.normalize();
|
||||
diff *= m_kart->getKartWidth()*0.5f;
|
||||
*result = Vec3(right.end.X-diff.X,
|
||||
m_kart->getXYZ().getY(),
|
||||
right.end.Y-diff.Y);
|
||||
return;
|
||||
}
|
||||
|
||||
// We are going straight. Determine point to aim for based on the
|
||||
// direction of the track after the straight section
|
||||
|
||||
sector = m_next_node_index[last];
|
||||
count++;
|
||||
if(count>1)
|
||||
printf("That shouldn't happen %d!!!\n", count);
|
||||
}
|
||||
|
||||
Vec3 ppp(0.5f*(left.end.X+right.end.X),
|
||||
m_kart->getXYZ().getY(),
|
||||
0.5f*(left.end.Y+right.end.Y));
|
||||
*result = QuadGraph::get()->getQuadOfNode(sector).getCenter();
|
||||
*result = ppp;
|
||||
} // findNonCrashingPoint2
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Find the sector that at the longest distance from the kart, that can be
|
||||
* driven to without crashing with the track, then find towards which of
|
||||
@ -1032,10 +1191,10 @@ void SkiddingAI::determineTrackDirection()
|
||||
&m_current_track_direction, &last);
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
m_curve[CURVE_QG]->clear();
|
||||
// m_curve[CURVE_QG]->clear();
|
||||
for(unsigned int i=m_track_node; i<=last; i++)
|
||||
{
|
||||
m_curve[CURVE_QG]->addPoint(qg->getNode(i).getCenter());
|
||||
// m_curve[CURVE_QG]->addPoint(qg->getNode(i).getCenter());
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1061,10 +1220,10 @@ void SkiddingAI::determineTrackDirection()
|
||||
determineTurnRadius(xyz, tangent, last_xyz,
|
||||
¢er, &m_current_curve_radius);
|
||||
#ifdef AI_DEBUG
|
||||
m_curve[CURVE_PREDICT1]->makeCircle(center, m_current_curve_radius);
|
||||
m_curve[CURVE_PREDICT1]->addPoint(last_xyz);
|
||||
m_curve[CURVE_PREDICT1]->addPoint(center);
|
||||
m_curve[CURVE_PREDICT1]->addPoint(xyz);
|
||||
// m_curve[CURVE_PREDICT1]->makeCircle(center, m_current_curve_radius);
|
||||
// m_curve[CURVE_PREDICT1]->addPoint(last_xyz);
|
||||
// m_curve[CURVE_PREDICT1]->addPoint(center);
|
||||
// m_curve[CURVE_PREDICT1]->addPoint(xyz);
|
||||
#endif
|
||||
|
||||
// Estimate how long it takes to finish the curve
|
||||
|
@ -150,6 +150,7 @@ private:
|
||||
|
||||
void checkCrashes(const Vec3& pos);
|
||||
void findNonCrashingPoint(Vec3 *result);
|
||||
void findNonCrashingPoint2(Vec3 *result);
|
||||
|
||||
void determineTrackDirection();
|
||||
void determineTurnRadius(const Vec3 &start,
|
||||
|
@ -254,8 +254,8 @@ Controller* World::loadAIController(AbstractKart *kart)
|
||||
#elif defined(USE_SKIDDING_AI)
|
||||
int turn = 1;
|
||||
#elif defined(USE_ALL_AIS)
|
||||
static int turn=3;
|
||||
turn=(turn+1) % 3;
|
||||
static int turn=1;
|
||||
turn=(turn+1) % 3; // %2 would switch betwen default and skidding
|
||||
#else
|
||||
int turn=0; // use default AU
|
||||
#endif
|
||||
|
@ -649,7 +649,7 @@ void QuadGraph::updateDistancesForAllSuccessors(unsigned int indx, float delta)
|
||||
} // updateDistancesForAllSuccessors
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Computes the direction (striaght, left, right) of all graph nodes and the
|
||||
/** Computes the direction (straight, left, right) of all graph nodes and the
|
||||
* lastest graph node that is still turning in the given direction. For
|
||||
* example, if a successor to this graph node is turning left, it will compute
|
||||
* the last graph node that is still turning left. This data is used by the
|
||||
|
Loading…
Reference in New Issue
Block a user