From 05d2d05f2a617a73dfec760c074cb027deefd365 Mon Sep 17 00:00:00 2001 From: Benau Date: Fri, 16 Sep 2016 09:22:57 +0800 Subject: [PATCH] Make ArenaAI use only new graph interface --- src/items/item.cpp | 23 ++-- src/items/item_manager.cpp | 15 ++- src/items/item_manager.hpp | 10 ++ src/karts/controller/arena_ai.cpp | 162 ++++++++++++++--------------- src/karts/controller/arena_ai.hpp | 10 +- src/karts/controller/soccer_ai.hpp | 2 +- src/tracks/track.cpp | 4 +- 7 files changed, 114 insertions(+), 112 deletions(-) diff --git a/src/items/item.cpp b/src/items/item.cpp index 01ed0d5d5..12d64d813 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -25,6 +25,7 @@ #include "modes/easter_egg_hunt.hpp" #include "modes/three_strikes_battle.hpp" #include "modes/world.hpp" +#include "tracks/arena_graph.hpp" #include "tracks/graph_node.hpp" #include "tracks/quad_graph.hpp" #include "tracks/track.hpp" @@ -134,23 +135,17 @@ void Item::initItem(ItemType type, const Vec3 &xyz) } // Now determine in which quad this item is, and its distance // from the center within this quad. - m_graph_node = QuadGraph::UNKNOWN_SECTOR; - QuadGraph* currentQuadGraph = QuadGraph::get(); + m_graph_node = Graph::UNKNOWN_SECTOR; + m_distance_from_center = 9999.9f; + m_avoidance_points[0] = NULL; + m_avoidance_points[1] = NULL; - // Check that QuadGraph exist (it might not in battle mode for eg) - if (currentQuadGraph != NULL) + // Check that Graph exist (it might not in battle mode without navmesh) + if (Graph::get()) { - QuadGraph::get()->findRoadSector(xyz, &m_graph_node); + Graph::get()->findRoadSector(xyz, &m_graph_node); } - - if(m_graph_node==QuadGraph::UNKNOWN_SECTOR) - { - m_graph_node = -1; - m_distance_from_center = 9999.9f; // is not used - m_avoidance_points[0] = NULL; - m_avoidance_points[1] = NULL; - } - else + else if (!ArenaGraph::get()) // Todo replace with driveline graph { // Item is on quad graph. Pre-compute the distance from center // of this item, which is used by the AI (mostly for avoiding items) diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index ab746ef74..3fb85525f 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -32,9 +32,10 @@ #include "modes/linear_world.hpp" #include "network/network_config.hpp" #include "network/race_event_manager.hpp" +#include "tracks/arena_graph.hpp" #include "tracks/battle_graph.hpp" +#include "tracks/graph.hpp" #include "tracks/graph_node.hpp" -#include "tracks/quad_graph.hpp" #include "tracks/track.hpp" #include "utils/string_utils.hpp" @@ -158,12 +159,12 @@ ItemManager::ItemManager() m_switch_to.push_back((Item::ItemType)i); setSwitchItems(stk_config->m_switch_items); - if(QuadGraph::get()) + if(Graph::get()) { m_items_in_quads = new std::vector; // Entries 0 to n-1 are for the quads, entry // n is for all items that are not on a quad. - m_items_in_quads->resize(QuadGraph::get()->getNumNodes()+1); + m_items_in_quads->resize(Graph::get()->getNumNodes()+1); } else { @@ -228,8 +229,7 @@ void ItemManager::insertItem(Item *item) // If the item is on the driveline, store it at the appropriate index if(graph_node > -1) { - int sector = QuadGraph::get()->getNode(graph_node)->getNodeIndex(); - (*m_items_in_quads)[sector].push_back(item); + (*m_items_in_quads)[graph_node].push_back(item); } else // otherwise store it in the 'outside' index (*m_items_in_quads)[m_items_in_quads->size()-1].push_back(item); @@ -427,9 +427,8 @@ void ItemManager::deleteItem(Item *item) if(m_items_in_quads) { const Vec3 &xyz = item->getXYZ(); - int sector = QuadGraph::UNKNOWN_SECTOR; - QuadGraph::get()->findRoadSector(xyz, §or); - unsigned int indx = sector==QuadGraph::UNKNOWN_SECTOR + int sector = item->getGraphNode(); + unsigned int indx = sector==Graph::UNKNOWN_SECTOR ? (unsigned int) m_items_in_quads->size()-1 : sector; AllItemTypes &items = (*m_items_in_quads)[indx]; diff --git a/src/items/item_manager.hpp b/src/items/item_manager.hpp index ac5f4f820..fb04308bc 100644 --- a/src/items/item_manager.hpp +++ b/src/items/item_manager.hpp @@ -132,6 +132,16 @@ public: assert(n<(*m_items_in_quads).size()); return (*m_items_in_quads)[n]; } // getItemsInQuads + // ------------------------------------------------------------------------ + /** Returns the first item (NULL if none) on the specified quad + */ + Item* getFirstItemInQuad(unsigned int n) const + { + assert(m_items_in_quads); + assert(n < m_items_in_quads->size()); + return ((*m_items_in_quads)[n]).empty() ? NULL : + (*m_items_in_quads)[n].front(); + } // getFirstItemInQuad }; // ItemManager #endif diff --git a/src/karts/controller/arena_ai.cpp b/src/karts/controller/arena_ai.cpp index 4c6fa3d7b..7bdf95192 100644 --- a/src/karts/controller/arena_ai.cpp +++ b/src/karts/controller/arena_ai.cpp @@ -26,11 +26,11 @@ #include "karts/controller/player_controller.hpp" #include "karts/controller/ai_properties.hpp" #include "karts/kart_properties.hpp" -#include "tracks/battle_graph.hpp" -#include "tracks/quad.hpp" +#include "tracks/arena_graph.hpp" +#include "tracks/arena_node.hpp" #include "utils/log.hpp" -int ArenaAI::m_test_node_for_banana = BattleGraph::UNKNOWN_POLY; +int ArenaAI::m_test_node_for_banana = Graph::UNKNOWN_SECTOR; bool isNodeWithBanana(const std::pair& item_pair) { @@ -44,6 +44,8 @@ ArenaAI::ArenaAI(AbstractKart *kart) { m_debug_sphere = NULL; m_debug_sphere_next = NULL; + m_graph = ArenaGraph::get(); + assert(m_graph != NULL); } // ArenaAI //----------------------------------------------------------------------------- @@ -51,18 +53,18 @@ ArenaAI::ArenaAI(AbstractKart *kart) */ void ArenaAI::reset() { - m_target_node = BattleGraph::UNKNOWN_POLY; - m_current_forward_node = BattleGraph::UNKNOWN_POLY; + m_target_node = Graph::UNKNOWN_SECTOR; + m_current_forward_node = Graph::UNKNOWN_SECTOR; m_current_forward_point = Vec3(0, 0, 0); m_adjusting_side = false; m_closest_kart = NULL; - m_closest_kart_node = BattleGraph::UNKNOWN_POLY; + m_closest_kart_node = Graph::UNKNOWN_SECTOR; m_closest_kart_point = Vec3(0, 0, 0); m_closest_kart_pos_data = {0}; m_cur_kart_pos_data = {0}; m_is_stuck = false; m_is_uturn = false; - m_avoiding_banana = false; + m_avoiding_item = false; m_target_point = Vec3(0, 0, 0); m_time_since_last_shot = 0.0f; m_time_since_driving = 0.0f; @@ -88,7 +90,7 @@ void ArenaAI::update(float dt) // This is used to enable firing an item backwards. m_controls->m_look_back = false; m_controls->m_nitro = false; - m_avoiding_banana = false; + m_avoiding_item = false; // Don't do anything if there is currently a kart animations shown. if (m_kart->getKartAnimation()) @@ -140,24 +142,29 @@ bool ArenaAI::updateAimingPosition() // to compensate the time difference between steering m_current_forward_point = m_kart->getTrans()(Vec3(0, 0, m_kart->getKartLength())); - m_current_forward_node = BattleGraph::get()->pointToNode - (m_current_forward_node, m_current_forward_point, - false/*ignore_vertical*/); + + std::vector* 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 == BattleGraph::UNKNOWN_POLY || + 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 == BattleGraph::UNKNOWN_POLY || - m_target_node == BattleGraph::UNKNOWN_POLY) + if (forward == Graph::UNKNOWN_SECTOR || + m_target_node == Graph::UNKNOWN_SECTOR) return false; if (forward == m_target_node) { - m_aiming_points.push_back(BattleGraph::get() - ->getQuadOfNode(forward).getCenter()); + m_aiming_points.push_back(m_graph->getNode(forward)->getCenter()); m_aiming_points.push_back(m_target_point); m_aiming_nodes.insert(forward); @@ -165,19 +172,16 @@ bool ArenaAI::updateAimingPosition() return true; } - const int next_node = BattleGraph::get() - ->getNextShortestPathPoly(forward, m_target_node); - if (next_node == BattleGraph::UNKNOWN_POLY) + const 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; } - m_aiming_points.push_back(BattleGraph::get() - ->getQuadOfNode(forward).getCenter()); - m_aiming_points.push_back(BattleGraph::get() - ->getQuadOfNode(next_node).getCenter()); + m_aiming_points.push_back(m_graph->getNode(forward)->getCenter()); + m_aiming_points.push_back(m_graph->getNode(next_node)->getCenter()); m_aiming_nodes.insert(forward); m_aiming_nodes.insert(next_node); @@ -194,8 +198,8 @@ void ArenaAI::handleArenaSteering(const float dt) { const int current_node = getCurrentNode(); - if (current_node == BattleGraph::UNKNOWN_POLY || - m_target_node == BattleGraph::UNKNOWN_POLY) + if (current_node == Graph::UNKNOWN_SECTOR || + m_target_node == Graph::UNKNOWN_SECTOR) { return; } @@ -224,7 +228,7 @@ void ArenaAI::handleArenaSteering(const float dt) } else if (found_position) { - updateBananaLocation(); + updateBadItemLocation(); assert(m_aiming_points.size() == 2); updateTurnRadius(m_kart->getXYZ(), m_aiming_points[0], m_aiming_points[1]); @@ -368,44 +372,41 @@ bool ArenaAI::handleArenaUnstuck(const float dt) } // handleArenaUnstuck //----------------------------------------------------------------------------- -void ArenaAI::updateBananaLocation() +void ArenaAI::updateBadItemLocation() { - std::vector>& item_list = - BattleGraph::get()->getItemList(); - - std::set::iterator node = m_aiming_nodes.begin(); - while (node != m_aiming_nodes.end()) + // Check if any nodes AI will cross will meet bad items + for (const int& node : m_aiming_nodes) { - m_test_node_for_banana = *node; - std::vector>::iterator it = - std::find_if(item_list.begin(), item_list.end(), isNodeWithBanana); + assert(node != Graph::UNKNOWN_SECTOR); + Item* selected = ItemManager::get()->getFirstItemInQuad(node); - if (it != item_list.end()) + if (selected && !selected->wasCollected() && + (selected->getType() == Item::ITEM_BANANA || + selected->getType() == Item::ITEM_BUBBLEGUM || + selected->getType() == Item::ITEM_BUBBLEGUM_NOLOK)) { - Vec3 banana_lc; - checkPosition(it->first->getXYZ(), NULL, &banana_lc, + Vec3 bad_item_lc; + checkPosition(selected->getXYZ(), NULL, &bad_item_lc, true/*use_front_xyz*/); - // If satisfy the below condition, AI should not eat banana: - // banana_lc.z() < 0.0f, behind the kart - if (banana_lc.z() < 0.0f) + // If satisfy the below condition, AI should not be affected by it: + // bad_item_lc.z() < 0.0f, behind the kart + if (bad_item_lc.z() < 0.0f) { - node++; continue; } - // If the node AI will pass has a banana, adjust the aim position - banana_lc = (banana_lc.x() < 0 ? banana_lc + Vec3(5, 0, 0) : - banana_lc - Vec3(5, 0, 0)); - m_aiming_points[1] = m_kart->getTrans()(banana_lc); - m_avoiding_banana = true; + // If the node AI will pass has a bad item, adjust the aim position + bad_item_lc = (bad_item_lc.x() < 0 ? bad_item_lc + Vec3(5, 0, 0) : + bad_item_lc - Vec3(5, 0, 0)); + m_aiming_points[1] = m_kart->getTrans()(bad_item_lc); + m_avoiding_item = true; // Handle one banana only return; } - node++; } -} // updateBananaLocation +} // updateBadItemLocation //----------------------------------------------------------------------------- /** This function handles braking. It used the turn radius found by @@ -429,8 +430,8 @@ void ArenaAI::handleArenaBraking() m_controls->m_brake = false; - if (getCurrentNode() == BattleGraph::UNKNOWN_POLY || - m_target_node == BattleGraph::UNKNOWN_POLY) return; + if (getCurrentNode() == Graph::UNKNOWN_SECTOR || + m_target_node == Graph::UNKNOWN_SECTOR) return; if (m_aiming_points.empty()) return; @@ -658,55 +659,50 @@ void ArenaAI::handleArenaItems(const float dt) //----------------------------------------------------------------------------- void ArenaAI::collectItemInArena(Vec3* aim_point, int* target_node) const { - float distance = 99999.9f; - const std::vector< std::pair >& item_list = - BattleGraph::get()->getItemList(); - const unsigned int items_count = item_list.size(); + float distance = 999999.9f; + Item* selected = (*target_node == Graph::UNKNOWN_SECTOR ? NULL : + ItemManager::get()->getFirstItemInQuad(*target_node)); - if (item_list.empty()) + // Don't look for a new item unless it's collected or swapped + if (selected && !(selected->wasCollected() || + selected->getType() == Item::ITEM_BANANA || + selected->getType() == Item::ITEM_BUBBLEGUM || + selected->getType() == Item::ITEM_BUBBLEGUM_NOLOK)) { - // Notice: this should not happen, as it makes no sense - // for an arean without items, if so how can attack happen? - Log::fatal ("ArenaAI", - "AI can't find any items in the arena, " - "maybe there is something wrong with the navmesh, " - "make sure it lies closely to the ground."); + *aim_point = selected->getXYZ(); return; } - unsigned int closest_item_num = 0; - - for (unsigned int i = 0; i < items_count; ++i) + for (unsigned int i = 0; i < m_graph->getNumNodes(); i++) { - const Item* item = item_list[i].first; + Item* cur_item = ItemManager::get()->getFirstItemInQuad(i); + if (cur_item == NULL) continue; + if (cur_item->wasCollected() || + cur_item->getType() == Item::ITEM_BANANA || + cur_item->getType() == Item::ITEM_BUBBLEGUM || + cur_item->getType() == Item::ITEM_BUBBLEGUM_NOLOK) + continue; - if (item->wasCollected()) continue; - - if ((item->getType() == Item::ITEM_NITRO_BIG || - item->getType() == Item::ITEM_NITRO_SMALL) && + if ((cur_item->getType() == Item::ITEM_NITRO_BIG || + cur_item->getType() == Item::ITEM_NITRO_SMALL) && (m_kart->getEnergy() > m_kart->getKartProperties()->getNitroSmallContainer())) continue; // Ignore nitro when already has some - float test_distance = BattleGraph::get() - ->getDistance(item_list[i].second, getCurrentNode()); - if (test_distance <= distance && - (item->getType() == Item::ITEM_BONUS_BOX || - item->getType() == Item::ITEM_NITRO_BIG || - item->getType() == Item::ITEM_NITRO_SMALL)) + const int cur_node = cur_item->getGraphNode(); + assert(cur_node != Graph::UNKNOWN_SECTOR); + float test_distance = m_graph->getDistance(cur_node, getCurrentNode()); + if (test_distance <= distance) { - closest_item_num = i; + selected = cur_item; distance = test_distance; } } - const Item *item_selected = item_list[closest_item_num].first; - if (item_selected->getType() == Item::ITEM_BONUS_BOX || - item_selected->getType() == Item::ITEM_NITRO_BIG || - item_selected->getType() == Item::ITEM_NITRO_SMALL) + if (selected != NULL) { - *aim_point = item_selected->getXYZ(); - *target_node = item_list[closest_item_num].second; + *aim_point = selected->getXYZ(); + *target_node = selected->getGraphNode(); } else { diff --git a/src/karts/controller/arena_ai.hpp b/src/karts/controller/arena_ai.hpp index 40122e5b6..8496fb60d 100644 --- a/src/karts/controller/arena_ai.hpp +++ b/src/karts/controller/arena_ai.hpp @@ -27,7 +27,7 @@ #include "graphics/irr_driver.hpp" #endif -class Vec3; +class ArenaGraph; namespace irr { @@ -63,11 +63,13 @@ protected: /** The target point. */ Vec3 m_target_point; - bool m_avoiding_banana; + bool m_avoiding_item; void collectItemInArena(Vec3*, int*) const; float findAngleFrom3Edges(float a, float b, float c); private: + ArenaGraph* m_graph; + /** Used by handleArenaUTurn, it tells whether to do left or right * turning when steering is overridden. */ bool m_adjusting_side; @@ -115,7 +117,7 @@ private: void handleArenaUTurn(const float dt); bool handleArenaUnstuck(const float dt); bool updateAimingPosition(); - void updateBananaLocation(); + void updateBadItemLocation(); void updateTurnRadius(const Vec3& p1, const Vec3& p2, const Vec3& p3); virtual int getCurrentNode() const = 0; @@ -123,7 +125,7 @@ private: virtual void resetAfterStop() {}; virtual void findClosestKart(bool use_difficulty) = 0; virtual void findTarget() = 0; - virtual bool forceBraking() { return m_avoiding_banana; } + virtual bool forceBraking() { return m_avoiding_item; } virtual bool ignorePathFinding() { return false; } public: static int m_test_node_for_banana; diff --git a/src/karts/controller/soccer_ai.hpp b/src/karts/controller/soccer_ai.hpp index 016088e5b..edfd52f8d 100644 --- a/src/karts/controller/soccer_ai.hpp +++ b/src/karts/controller/soccer_ai.hpp @@ -67,7 +67,7 @@ private: virtual bool isWaiting() const; virtual bool canSkid(float steer_fraction) { return false; } virtual bool forceBraking() OVERRIDE - { return m_avoiding_banana || m_force_brake; } + { return m_avoiding_item || m_force_brake; } virtual bool ignorePathFinding() OVERRIDE { return m_overtake_ball || m_chasing_ball; } public: diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index d0899d386..a224a6379 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -280,7 +280,7 @@ void Track::reset() void Track::cleanup() { QuadGraph::destroy(); - BattleGraph::destroy(); + Graph::destroy(); ItemManager::destroy(); VAOManager::kill(); @@ -678,7 +678,7 @@ void Track::loadBattleGraph(const XMLNode &node) ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node); Graph::setGraph(graph); - if(BattleGraph::get()->getNumNodes()==0) + if(Graph::get()->getNumNodes()==0) { Log::warn("track", "No graph nodes defined for track '%s'\n", m_filename.c_str());