/** This function handles braking. It calls determineTurnRadius() to find out * the curve radius. Depending on the turn radius, it finds out the maximum * speed. If the current speed is greater than the max speed and a set minimum * speed, brakes are applied. */ void ArenaAI::handleArenaBraking() { m_controls->m_brake = false; if (getCurrentNode() == BattleGraph::UNKNOWN_POLY || m_target_node == BattleGraph::UNKNOWN_POLY) return; // A kart will not brake when the speed is already slower than this // value. This prevents a kart from going too slow (or even backwards) // in tight curves. const float MIN_SPEED = 5.0f; std::vector<Vec3> 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 max_turn_speed = m_kart->getSpeedForTurnRadius(current_curve_radius); if (m_kart->getSpeed() > max_turn_speed && m_kart->getSpeed() > MIN_SPEED) { m_controls->m_brake = true; } } // handleArenaBraking
/** Determine if the path to target needs to be changed to avoid bad items, it * will also set the turn radius based on the new path if necessary. * \param forward Forward node of current AI position. * \param[in,out] path Default path to follow, will be changed if needed. */ void ArenaAI::determinePath(int forward, std::vector<int>* path) { std::vector<int> bad_item_nodes; // First, test if the nodes AI will cross contain bad item for (unsigned int i = 0; i < path->size(); i++) { // Only test few nodes ahead if (i == 6) break; const int node = (*path)[i]; Item* selected = ItemManager::get()->getFirstItemInQuad(node); if (selected && !selected->wasCollected() && (selected->getType() == Item::ITEM_BANANA || selected->getType() == Item::ITEM_BUBBLEGUM || selected->getType() == Item::ITEM_BUBBLEGUM_NOLOK)) { bad_item_nodes.push_back(node); } } // If so try to avoid if (!bad_item_nodes.empty()) { bool failed_avoid = false; for (unsigned int i = 0; i < path->size(); i++) { if (failed_avoid) break; if (i == 6) break; // Choose any adjacent node that is in front of the AI to prevent // hitting bad item ArenaNode* cur_node = m_graph->getNode(i == 0 ? forward : (*path)[i - 1]); float dist = 99999.9f; const std::vector<int>& adj_nodes = cur_node->getAdjacentNodes(); int chosen_node = Graph::UNKNOWN_SECTOR; for (const int& adjacent : adj_nodes) { if (std::find(bad_item_nodes.begin(), bad_item_nodes.end(), adjacent) != bad_item_nodes.end()) continue; Vec3 lc = m_kart->getTrans().inverse() (m_graph->getNode(adjacent)->getCenter()); const float dist_to_target = m_graph->getDistance(adjacent, m_target_node); if (lc.z() > 0 && dist > dist_to_target) { chosen_node = adjacent; dist = dist_to_target; } if (chosen_node == Graph::UNKNOWN_SECTOR) { Log::debug("ArenaAI", "Too many bad items to avoid!"); failed_avoid = true; break; } (*path)[i] = chosen_node; } } } // Now find the first turning corner to determine turn radius for (unsigned int i = 0; i < path->size() - 1; i++) { const Vec3& p1 = m_kart->getXYZ(); const Vec3& p2 = m_graph->getNode((*path)[i])->getCenter(); const Vec3& p3 = m_graph->getNode((*path)[i + 1])->getCenter(); float edge1 = (p1 - p2).length(); float edge2 = (p2 - p3).length(); float to_target = (p1 - p3).length(); // Triangle test if (fabsf(edge1 + edge2 - to_target) > 0.1f) { determineTurnRadius(p3, NULL, &m_turn_radius); #ifdef AI_DEBUG m_debug_sphere_next->setVisible(true); m_debug_sphere_next->setPosition(p3.toIrrVector()); #endif return; } } // Fallback calculation determineTurnRadius(m_target_point, NULL, &m_turn_radius); } // determinePath
/** Update aiming position, use path finding if necessary. * \param[out] target_point Suitable target point. * \return True if found a suitable target point. */ bool ArenaAI::updateAimingPosition(Vec3* target_point) { #ifdef AI_DEBUG m_debug_sphere_next->setVisible(false); #endif m_current_forward_point = m_kart->getTrans()(Vec3(0, 0, m_kart_length)); m_turn_radius = 0.0f; std::vector<int>* test_nodes = NULL; if (m_current_forward_node != Graph::UNKNOWN_SECTOR) { test_nodes = m_graph->getNode(m_current_forward_node)->getNearbyNodes(); } m_graph->findRoadSector(m_current_forward_point, &m_current_forward_node, test_nodes); // Use current node if forward node is unknown, or near the target const int forward = m_current_forward_node == Graph::UNKNOWN_SECTOR || m_current_forward_node == m_target_node || getCurrentNode() == m_target_node ? getCurrentNode() : m_current_forward_node; if (forward == Graph::UNKNOWN_SECTOR || m_target_node == Graph::UNKNOWN_SECTOR) { Log::error("ArenaAI", "Next node is unknown, path finding failed!"); return false; } if (forward == m_target_node) { determineTurnRadius(m_target_point, NULL, &m_turn_radius); *target_point = m_target_point; return true; } std::vector<int> path; int next_node = m_graph->getNextNode(forward, m_target_node); if (next_node == Graph::UNKNOWN_SECTOR) { Log::error("ArenaAI", "Next node is unknown, did you forget to link" " adjacent face in navmesh?"); return false; } path.push_back(next_node); while (m_target_node != next_node) { int previous_node = next_node; next_node = m_graph->getNextNode(previous_node, m_target_node); if (next_node == Graph::UNKNOWN_SECTOR) { Log::error("ArenaAI", "Next node is unknown, did you forget to" " link adjacent face in navmesh?"); return false; } path.push_back(next_node); } determinePath(forward, &path); *target_point = m_graph->getNode(path.front())->getCenter(); return true; } // updateAimingPosition