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