From 3ec6682fb49530234d38bf06906bb24f84fe6e7e Mon Sep 17 00:00:00 2001 From: hikerstk Date: Thu, 19 Jul 2012 07:00:57 +0000 Subject: [PATCH] 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 --- src/karts/controller/skidding_ai.cpp | 191 ++++++++++++++++++++++++--- src/karts/controller/skidding_ai.hpp | 1 + src/modes/world.cpp | 4 +- src/tracks/quad_graph.cpp | 2 +- 4 files changed, 179 insertions(+), 19 deletions(-) diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index 52dad6d79..c974112be 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -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 diff --git a/src/karts/controller/skidding_ai.hpp b/src/karts/controller/skidding_ai.hpp index 98799f6f4..b777582a7 100644 --- a/src/karts/controller/skidding_ai.hpp +++ b/src/karts/controller/skidding_ai.hpp @@ -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, diff --git a/src/modes/world.cpp b/src/modes/world.cpp index d2e044e94..6d28dd080 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -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 diff --git a/src/tracks/quad_graph.cpp b/src/tracks/quad_graph.cpp index c1b9cea72..6bcb1496a 100644 --- a/src/tracks/quad_graph.cpp +++ b/src/tracks/quad_graph.cpp @@ -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