diff --git a/src/karts/controller/arena_ai.cpp b/src/karts/controller/arena_ai.cpp index 1ee41316f..9b1d00a8a 100644 --- a/src/karts/controller/arena_ai.cpp +++ b/src/karts/controller/arena_ai.cpp @@ -33,6 +33,7 @@ ArenaAI::ArenaAI(AbstractKart *kart) : AIBaseController(kart) { m_debug_sphere = NULL; + m_debug_sphere_next = NULL; } // ArenaAI //----------------------------------------------------------------------------- @@ -262,7 +263,18 @@ void ArenaAI::handleArenaSteering(const float dt) checkPosition(m_target_point, &m_cur_kart_pos_data); #ifdef AI_DEBUG - m_debug_sphere->setPosition(m_target_point.toIrrVector()); + if (m_path_corners.size() > 2) + { + m_debug_sphere->setVisible(true); + m_debug_sphere_next->setVisible(true); + m_debug_sphere->setPosition(m_path_corners[1].toIrrVector()); + m_debug_sphere_next->setPosition(m_path_corners[2].toIrrVector()); + } + else + { + m_debug_sphere->setVisible(false); + m_debug_sphere_next->setVisible(false); + } #endif if (m_cur_kart_pos_data.behind) { @@ -488,18 +500,9 @@ void ArenaAI::handleArenaBraking() // in tight curves. const float MIN_SPEED = 5.0f; - std::vector points; - - points.push_back(m_kart->getXYZ()); - points.push_back(m_path_corners[0]); - points.push_back((m_path_corners.size()>=2) ? m_path_corners[1] : m_path_corners[0]); - - float current_curve_radius = determineTurnRadius(points); - - Vec3 d1 = m_kart->getXYZ() - m_target_point; - Vec3 d2 = m_kart->getXYZ() - m_path_corners[0]; - if (d1.length2_2d() < d2.length2_2d()) - current_curve_radius = d1.length_2d(); + float current_curve_radius = determineTurnRadius(m_kart->getXYZ(), + m_path_corners[0], (m_path_corners.size() >= 2 ? m_path_corners[1] : + m_path_corners[0])); float max_turn_speed = m_kart->getSpeedForTurnRadius(current_curve_radius); @@ -516,55 +519,44 @@ void ArenaAI::handleArenaBraking() * location of AI, first corner and the second corner. Once the constants are * computed, a formula is used to find the radius of curvature at the kart's * current location. - * NOTE: This method does not apply enough braking, should think of something - * else. */ -float ArenaAI::determineTurnRadius( std::vector& points ) +float ArenaAI::determineTurnRadius(const Vec3& p1, const Vec3& p2, + const Vec3& p3) { - // Declaring variables - float a, b; - irr::core::CMatrix4 A; - irr::core::CMatrix4 X; - irr::core::CMatrix4 B; + // The parabola function is as following: y=ax2+bx+c + // No need to calculate c as after differentiating c will be zero + const float eps = 0.01f; + const float denominator = (p1.x() - p2.x()) * (p1.x() - p3.x()) * + (p2.x() - p3.x()); - //Populating matrices - for (unsigned int i = 0; i < 3; i++) - { - A(i, 0) = points[i].x()*points[i].x(); - A(i, 1) = points[i].x(); - A(i, 2) = 1.0f; - A(i, 3) = 0.0f; - } - A(3, 0) = A(3, 1) = A(3, 2) = 0.0f; - A(3, 3) = 1.0f; + // Avoid nan, this will happen if three values of coordinates x are too + // close together, ie a straight line, return a large radius + // so no braking is needed + if (fabsf(denominator) < eps) return 25.0f; - for (unsigned int i = 0; i < 3; i++) - { - B(i, 0) = points[i].z(); - B(i, 1) = 0.0f; - B(i, 2) = 0.0f; - B(i, 3) = 0.0f; - } - B(3, 0) = B(3, 1) = B(3, 2) = B(3, 3) = 0.0f; + const float a = (p3.x() * (p2.z() - p1.z()) + + p2.x() * (p1.z() - p3.z()) + + p1.x() * (p3.z() - p2.z())) / denominator; - //Computing inverse : X = inv(A)*B - irr::core::CMatrix4 invA; - if (!A.getInverse(invA)) - return -1; + // Should not happen, otherwise y=c which is a straight line + if (fabsf(a) < eps) return 25.0f; - X = invA*B; - a = X(0, 0); - b = X(0, 1); - //c = X(0, 2); + const float b = (p3.x() * p3.x() * (p1.z() - p2.z()) + + p2.x() * p2.x() * (p3.z() - p1.z()) + + p1.x() * p1.x() * (p2.z() - p3.z())) / denominator; - float x = points.front().x(); - //float z = a*pow(x, 2) + b*x + c; - float dx_by_dz = 2*a*x + b; - float d2x_by_dz = 2*a; + // Differentiate the function, so y=ax2+bx+c will become y=2ax+b for dy_dx, + // y=2a for d2y_dx2 + // Use the p1 (current location of AI) as x + const float dy_dx = 2 * a * p1.x() + b; + const float d2y_dx2 = 2 * a; - float radius = pow(abs(1 + pow(dx_by_dz, 2)), 1.5f)/ abs(d2x_by_dz); + // Calculate the radius of curvature at current location of AI + const float radius = pow(1 + pow(dy_dx, 2), 1.5f) / fabsf(d2y_dx2); + assert(!std::isnan(radius)); - return radius; + // Avoid returning too large radius + return (radius > 25.0f ? 25.0f : radius); } // determineTurnRadius //----------------------------------------------------------------------------- @@ -663,7 +655,8 @@ void ArenaAI::handleArenaItems(const float dt) if (m_time_since_last_shot < 1.0f) break; if (m_closest_kart_pos_data.distance < 6.0f && - (difficulty || perfect_aim)) + (difficulty || perfect_aim) && + !m_closest_kart->isInvulnerable()) { m_controls->m_fire = true; m_controls->m_look_back = fire_behind; diff --git a/src/karts/controller/arena_ai.hpp b/src/karts/controller/arena_ai.hpp index 3caf152ba..486baf256 100644 --- a/src/karts/controller/arena_ai.hpp +++ b/src/karts/controller/arena_ai.hpp @@ -56,6 +56,7 @@ protected: /** For debugging purpose: a sphere indicating where the AI * is targeting at. */ irr::scene::ISceneNode *m_debug_sphere; + irr::scene::ISceneNode *m_debug_sphere_next; /** The node(poly) at which the target point lies in. */ int m_target_node; @@ -104,7 +105,8 @@ private: float m_time_since_uturn; void checkIfStuck(const float dt); - float determineTurnRadius(std::vector& points); + float determineTurnRadius(const Vec3& p1, const Vec3& p2, + const Vec3& p3); void findPortals(int start, int end); void handleArenaAcceleration(const float dt); void handleArenaBanana(); diff --git a/src/karts/controller/battle_ai.cpp b/src/karts/controller/battle_ai.cpp index 1b2cdc57b..ed23e37b3 100644 --- a/src/karts/controller/battle_ai.cpp +++ b/src/karts/controller/battle_ai.cpp @@ -41,8 +41,11 @@ BattleAI::BattleAI(AbstractKart *kart) #ifdef AI_DEBUG video::SColor col_debug(128, 128, 0, 0); + video::SColor col_debug_next(128, 0, 128, 128); m_debug_sphere = irr_driver->addSphere(1.0f, col_debug); m_debug_sphere->setVisible(true); + m_debug_sphere_next = irr_driver->addSphere(1.0f, col_debug_next); + m_debug_sphere_next->setVisible(true); #endif m_world = dynamic_cast(World::getWorld()); m_track = m_world->getTrack(); @@ -59,6 +62,7 @@ BattleAI::~BattleAI() { #ifdef AI_DEBUG irr_driver->removeNode(m_debug_sphere); + irr_driver->removeNode(m_debug_sphere_next); #endif } // ~BattleAI diff --git a/src/karts/controller/soccer_ai.cpp b/src/karts/controller/soccer_ai.cpp index 8c2c45f31..5b2dc5e17 100644 --- a/src/karts/controller/soccer_ai.cpp +++ b/src/karts/controller/soccer_ai.cpp @@ -41,8 +41,11 @@ SoccerAI::SoccerAI(AbstractKart *kart) #ifdef AI_DEBUG video::SColor col_debug(128, 128, 0, 0); + video::SColor col_debug_next(128, 0, 128, 128); m_debug_sphere = irr_driver->addSphere(1.0f, col_debug); m_debug_sphere->setVisible(true); + m_debug_sphere_next = irr_driver->addSphere(1.0f, col_debug_next); + m_debug_sphere_next->setVisible(true); #endif m_world = dynamic_cast(World::getWorld()); m_track = m_world->getTrack(); @@ -59,6 +62,7 @@ SoccerAI::~SoccerAI() { #ifdef AI_DEBUG irr_driver->removeNode(m_debug_sphere); + irr_driver->removeNode(m_debug_sphere_next); #endif } // ~SoccerAI