Make ArenaAI use only new graph interface

This commit is contained in:
Benau 2016-09-16 09:22:57 +08:00
parent 1491236e84
commit 05d2d05f2a
7 changed files with 114 additions and 112 deletions

View File

@ -25,6 +25,7 @@
#include "modes/easter_egg_hunt.hpp" #include "modes/easter_egg_hunt.hpp"
#include "modes/three_strikes_battle.hpp" #include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "tracks/arena_graph.hpp"
#include "tracks/graph_node.hpp" #include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/quad_graph.hpp"
#include "tracks/track.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 // Now determine in which quad this item is, and its distance
// from the center within this quad. // from the center within this quad.
m_graph_node = QuadGraph::UNKNOWN_SECTOR; m_graph_node = Graph::UNKNOWN_SECTOR;
QuadGraph* currentQuadGraph = QuadGraph::get(); 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) // Check that Graph exist (it might not in battle mode without navmesh)
if (currentQuadGraph != NULL) if (Graph::get())
{ {
QuadGraph::get()->findRoadSector(xyz, &m_graph_node); Graph::get()->findRoadSector(xyz, &m_graph_node);
} }
else if (!ArenaGraph::get()) // Todo replace with driveline graph
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
{ {
// Item is on quad graph. Pre-compute the distance from center // Item is on quad graph. Pre-compute the distance from center
// of this item, which is used by the AI (mostly for avoiding items) // of this item, which is used by the AI (mostly for avoiding items)

View File

@ -32,9 +32,10 @@
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "network/network_config.hpp" #include "network/network_config.hpp"
#include "network/race_event_manager.hpp" #include "network/race_event_manager.hpp"
#include "tracks/arena_graph.hpp"
#include "tracks/battle_graph.hpp" #include "tracks/battle_graph.hpp"
#include "tracks/graph.hpp"
#include "tracks/graph_node.hpp" #include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
@ -158,12 +159,12 @@ ItemManager::ItemManager()
m_switch_to.push_back((Item::ItemType)i); m_switch_to.push_back((Item::ItemType)i);
setSwitchItems(stk_config->m_switch_items); setSwitchItems(stk_config->m_switch_items);
if(QuadGraph::get()) if(Graph::get())
{ {
m_items_in_quads = new std::vector<AllItemTypes>; m_items_in_quads = new std::vector<AllItemTypes>;
// Entries 0 to n-1 are for the quads, entry // Entries 0 to n-1 are for the quads, entry
// n is for all items that are not on a quad. // 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 else
{ {
@ -228,8 +229,7 @@ void ItemManager::insertItem(Item *item)
// If the item is on the driveline, store it at the appropriate index // If the item is on the driveline, store it at the appropriate index
if(graph_node > -1) if(graph_node > -1)
{ {
int sector = QuadGraph::get()->getNode(graph_node)->getNodeIndex(); (*m_items_in_quads)[graph_node].push_back(item);
(*m_items_in_quads)[sector].push_back(item);
} }
else // otherwise store it in the 'outside' index else // otherwise store it in the 'outside' index
(*m_items_in_quads)[m_items_in_quads->size()-1].push_back(item); (*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) if(m_items_in_quads)
{ {
const Vec3 &xyz = item->getXYZ(); const Vec3 &xyz = item->getXYZ();
int sector = QuadGraph::UNKNOWN_SECTOR; int sector = item->getGraphNode();
QuadGraph::get()->findRoadSector(xyz, &sector); unsigned int indx = sector==Graph::UNKNOWN_SECTOR
unsigned int indx = sector==QuadGraph::UNKNOWN_SECTOR
? (unsigned int) m_items_in_quads->size()-1 ? (unsigned int) m_items_in_quads->size()-1
: sector; : sector;
AllItemTypes &items = (*m_items_in_quads)[indx]; AllItemTypes &items = (*m_items_in_quads)[indx];

View File

@ -132,6 +132,16 @@ public:
assert(n<(*m_items_in_quads).size()); assert(n<(*m_items_in_quads).size());
return (*m_items_in_quads)[n]; return (*m_items_in_quads)[n];
} // getItemsInQuads } // 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 }; // ItemManager
#endif #endif

View File

@ -26,11 +26,11 @@
#include "karts/controller/player_controller.hpp" #include "karts/controller/player_controller.hpp"
#include "karts/controller/ai_properties.hpp" #include "karts/controller/ai_properties.hpp"
#include "karts/kart_properties.hpp" #include "karts/kart_properties.hpp"
#include "tracks/battle_graph.hpp" #include "tracks/arena_graph.hpp"
#include "tracks/quad.hpp" #include "tracks/arena_node.hpp"
#include "utils/log.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<const Item*, int>& item_pair) bool isNodeWithBanana(const std::pair<const Item*, int>& item_pair)
{ {
@ -44,6 +44,8 @@ ArenaAI::ArenaAI(AbstractKart *kart)
{ {
m_debug_sphere = NULL; m_debug_sphere = NULL;
m_debug_sphere_next = NULL; m_debug_sphere_next = NULL;
m_graph = ArenaGraph::get();
assert(m_graph != NULL);
} // ArenaAI } // ArenaAI
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -51,18 +53,18 @@ ArenaAI::ArenaAI(AbstractKart *kart)
*/ */
void ArenaAI::reset() void ArenaAI::reset()
{ {
m_target_node = BattleGraph::UNKNOWN_POLY; m_target_node = Graph::UNKNOWN_SECTOR;
m_current_forward_node = BattleGraph::UNKNOWN_POLY; m_current_forward_node = Graph::UNKNOWN_SECTOR;
m_current_forward_point = Vec3(0, 0, 0); m_current_forward_point = Vec3(0, 0, 0);
m_adjusting_side = false; m_adjusting_side = false;
m_closest_kart = NULL; 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_point = Vec3(0, 0, 0);
m_closest_kart_pos_data = {0}; m_closest_kart_pos_data = {0};
m_cur_kart_pos_data = {0}; m_cur_kart_pos_data = {0};
m_is_stuck = false; m_is_stuck = false;
m_is_uturn = false; m_is_uturn = false;
m_avoiding_banana = false; m_avoiding_item = false;
m_target_point = Vec3(0, 0, 0); m_target_point = Vec3(0, 0, 0);
m_time_since_last_shot = 0.0f; m_time_since_last_shot = 0.0f;
m_time_since_driving = 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. // This is used to enable firing an item backwards.
m_controls->m_look_back = false; m_controls->m_look_back = false;
m_controls->m_nitro = 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. // Don't do anything if there is currently a kart animations shown.
if (m_kart->getKartAnimation()) if (m_kart->getKartAnimation())
@ -140,24 +142,29 @@ bool ArenaAI::updateAimingPosition()
// to compensate the time difference between steering // to compensate the time difference between steering
m_current_forward_point = m_current_forward_point =
m_kart->getTrans()(Vec3(0, 0, m_kart->getKartLength())); m_kart->getTrans()(Vec3(0, 0, m_kart->getKartLength()));
m_current_forward_node = BattleGraph::get()->pointToNode
(m_current_forward_node, m_current_forward_point, std::vector<int>* test_nodes = NULL;
false/*ignore_vertical*/); 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 // 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 || m_current_forward_node == m_target_node ||
getCurrentNode() == m_target_node ? getCurrentNode() : getCurrentNode() == m_target_node ? getCurrentNode() :
m_current_forward_node); m_current_forward_node);
if (forward == BattleGraph::UNKNOWN_POLY || if (forward == Graph::UNKNOWN_SECTOR ||
m_target_node == BattleGraph::UNKNOWN_POLY) m_target_node == Graph::UNKNOWN_SECTOR)
return false; return false;
if (forward == m_target_node) if (forward == m_target_node)
{ {
m_aiming_points.push_back(BattleGraph::get() m_aiming_points.push_back(m_graph->getNode(forward)->getCenter());
->getQuadOfNode(forward).getCenter());
m_aiming_points.push_back(m_target_point); m_aiming_points.push_back(m_target_point);
m_aiming_nodes.insert(forward); m_aiming_nodes.insert(forward);
@ -165,19 +172,16 @@ bool ArenaAI::updateAimingPosition()
return true; return true;
} }
const int next_node = BattleGraph::get() const int next_node = m_graph->getNextNode(forward, m_target_node);
->getNextShortestPathPoly(forward, m_target_node); if (next_node == Graph::UNKNOWN_SECTOR)
if (next_node == BattleGraph::UNKNOWN_POLY)
{ {
Log::error("ArenaAI", "Next node is unknown, did you forget to link" Log::error("ArenaAI", "Next node is unknown, did you forget to link"
"adjacent face in navmesh?"); "adjacent face in navmesh?");
return false; return false;
} }
m_aiming_points.push_back(BattleGraph::get() m_aiming_points.push_back(m_graph->getNode(forward)->getCenter());
->getQuadOfNode(forward).getCenter()); m_aiming_points.push_back(m_graph->getNode(next_node)->getCenter());
m_aiming_points.push_back(BattleGraph::get()
->getQuadOfNode(next_node).getCenter());
m_aiming_nodes.insert(forward); m_aiming_nodes.insert(forward);
m_aiming_nodes.insert(next_node); m_aiming_nodes.insert(next_node);
@ -194,8 +198,8 @@ void ArenaAI::handleArenaSteering(const float dt)
{ {
const int current_node = getCurrentNode(); const int current_node = getCurrentNode();
if (current_node == BattleGraph::UNKNOWN_POLY || if (current_node == Graph::UNKNOWN_SECTOR ||
m_target_node == BattleGraph::UNKNOWN_POLY) m_target_node == Graph::UNKNOWN_SECTOR)
{ {
return; return;
} }
@ -224,7 +228,7 @@ void ArenaAI::handleArenaSteering(const float dt)
} }
else if (found_position) else if (found_position)
{ {
updateBananaLocation(); updateBadItemLocation();
assert(m_aiming_points.size() == 2); assert(m_aiming_points.size() == 2);
updateTurnRadius(m_kart->getXYZ(), m_aiming_points[0], updateTurnRadius(m_kart->getXYZ(), m_aiming_points[0],
m_aiming_points[1]); m_aiming_points[1]);
@ -368,44 +372,41 @@ bool ArenaAI::handleArenaUnstuck(const float dt)
} // handleArenaUnstuck } // handleArenaUnstuck
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ArenaAI::updateBananaLocation() void ArenaAI::updateBadItemLocation()
{ {
std::vector<std::pair<const Item*, int>>& item_list = // Check if any nodes AI will cross will meet bad items
BattleGraph::get()->getItemList(); for (const int& node : m_aiming_nodes)
std::set<int>::iterator node = m_aiming_nodes.begin();
while (node != m_aiming_nodes.end())
{ {
m_test_node_for_banana = *node; assert(node != Graph::UNKNOWN_SECTOR);
std::vector<std::pair<const Item*, int>>::iterator it = Item* selected = ItemManager::get()->getFirstItemInQuad(node);
std::find_if(item_list.begin(), item_list.end(), isNodeWithBanana);
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; Vec3 bad_item_lc;
checkPosition(it->first->getXYZ(), NULL, &banana_lc, checkPosition(selected->getXYZ(), NULL, &bad_item_lc,
true/*use_front_xyz*/); true/*use_front_xyz*/);
// If satisfy the below condition, AI should not eat banana: // If satisfy the below condition, AI should not be affected by it:
// banana_lc.z() < 0.0f, behind the kart // bad_item_lc.z() < 0.0f, behind the kart
if (banana_lc.z() < 0.0f) if (bad_item_lc.z() < 0.0f)
{ {
node++;
continue; continue;
} }
// If the node AI will pass has a banana, adjust the aim position // If the node AI will pass has a bad item, adjust the aim position
banana_lc = (banana_lc.x() < 0 ? banana_lc + Vec3(5, 0, 0) : bad_item_lc = (bad_item_lc.x() < 0 ? bad_item_lc + Vec3(5, 0, 0) :
banana_lc - Vec3(5, 0, 0)); bad_item_lc - Vec3(5, 0, 0));
m_aiming_points[1] = m_kart->getTrans()(banana_lc); m_aiming_points[1] = m_kart->getTrans()(bad_item_lc);
m_avoiding_banana = true; m_avoiding_item = true;
// Handle one banana only // Handle one banana only
return; return;
} }
node++;
} }
} // updateBananaLocation } // updateBadItemLocation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** This function handles braking. It used the turn radius found by /** This function handles braking. It used the turn radius found by
@ -429,8 +430,8 @@ void ArenaAI::handleArenaBraking()
m_controls->m_brake = false; m_controls->m_brake = false;
if (getCurrentNode() == BattleGraph::UNKNOWN_POLY || if (getCurrentNode() == Graph::UNKNOWN_SECTOR ||
m_target_node == BattleGraph::UNKNOWN_POLY) return; m_target_node == Graph::UNKNOWN_SECTOR) return;
if (m_aiming_points.empty()) 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 void ArenaAI::collectItemInArena(Vec3* aim_point, int* target_node) const
{ {
float distance = 99999.9f; float distance = 999999.9f;
const std::vector< std::pair<const Item*, int> >& item_list = Item* selected = (*target_node == Graph::UNKNOWN_SECTOR ? NULL :
BattleGraph::get()->getItemList(); ItemManager::get()->getFirstItemInQuad(*target_node));
const unsigned int items_count = item_list.size();
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 *aim_point = selected->getXYZ();
// 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.");
return; return;
} }
unsigned int closest_item_num = 0; for (unsigned int i = 0; i < m_graph->getNumNodes(); i++)
for (unsigned int i = 0; i < items_count; ++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 ((cur_item->getType() == Item::ITEM_NITRO_BIG ||
cur_item->getType() == Item::ITEM_NITRO_SMALL) &&
if ((item->getType() == Item::ITEM_NITRO_BIG ||
item->getType() == Item::ITEM_NITRO_SMALL) &&
(m_kart->getEnergy() > (m_kart->getEnergy() >
m_kart->getKartProperties()->getNitroSmallContainer())) m_kart->getKartProperties()->getNitroSmallContainer()))
continue; // Ignore nitro when already has some continue; // Ignore nitro when already has some
float test_distance = BattleGraph::get() const int cur_node = cur_item->getGraphNode();
->getDistance(item_list[i].second, getCurrentNode()); assert(cur_node != Graph::UNKNOWN_SECTOR);
if (test_distance <= distance && float test_distance = m_graph->getDistance(cur_node, getCurrentNode());
(item->getType() == Item::ITEM_BONUS_BOX || if (test_distance <= distance)
item->getType() == Item::ITEM_NITRO_BIG ||
item->getType() == Item::ITEM_NITRO_SMALL))
{ {
closest_item_num = i; selected = cur_item;
distance = test_distance; distance = test_distance;
} }
} }
const Item *item_selected = item_list[closest_item_num].first; if (selected != NULL)
if (item_selected->getType() == Item::ITEM_BONUS_BOX ||
item_selected->getType() == Item::ITEM_NITRO_BIG ||
item_selected->getType() == Item::ITEM_NITRO_SMALL)
{ {
*aim_point = item_selected->getXYZ(); *aim_point = selected->getXYZ();
*target_node = item_list[closest_item_num].second; *target_node = selected->getGraphNode();
} }
else else
{ {

View File

@ -27,7 +27,7 @@
#include "graphics/irr_driver.hpp" #include "graphics/irr_driver.hpp"
#endif #endif
class Vec3; class ArenaGraph;
namespace irr namespace irr
{ {
@ -63,11 +63,13 @@ protected:
/** The target point. */ /** The target point. */
Vec3 m_target_point; Vec3 m_target_point;
bool m_avoiding_banana; bool m_avoiding_item;
void collectItemInArena(Vec3*, int*) const; void collectItemInArena(Vec3*, int*) const;
float findAngleFrom3Edges(float a, float b, float c); float findAngleFrom3Edges(float a, float b, float c);
private: private:
ArenaGraph* m_graph;
/** Used by handleArenaUTurn, it tells whether to do left or right /** Used by handleArenaUTurn, it tells whether to do left or right
* turning when steering is overridden. */ * turning when steering is overridden. */
bool m_adjusting_side; bool m_adjusting_side;
@ -115,7 +117,7 @@ private:
void handleArenaUTurn(const float dt); void handleArenaUTurn(const float dt);
bool handleArenaUnstuck(const float dt); bool handleArenaUnstuck(const float dt);
bool updateAimingPosition(); bool updateAimingPosition();
void updateBananaLocation(); void updateBadItemLocation();
void updateTurnRadius(const Vec3& p1, const Vec3& p2, void updateTurnRadius(const Vec3& p1, const Vec3& p2,
const Vec3& p3); const Vec3& p3);
virtual int getCurrentNode() const = 0; virtual int getCurrentNode() const = 0;
@ -123,7 +125,7 @@ private:
virtual void resetAfterStop() {}; virtual void resetAfterStop() {};
virtual void findClosestKart(bool use_difficulty) = 0; virtual void findClosestKart(bool use_difficulty) = 0;
virtual void findTarget() = 0; virtual void findTarget() = 0;
virtual bool forceBraking() { return m_avoiding_banana; } virtual bool forceBraking() { return m_avoiding_item; }
virtual bool ignorePathFinding() { return false; } virtual bool ignorePathFinding() { return false; }
public: public:
static int m_test_node_for_banana; static int m_test_node_for_banana;

View File

@ -67,7 +67,7 @@ private:
virtual bool isWaiting() const; virtual bool isWaiting() const;
virtual bool canSkid(float steer_fraction) { return false; } virtual bool canSkid(float steer_fraction) { return false; }
virtual bool forceBraking() OVERRIDE virtual bool forceBraking() OVERRIDE
{ return m_avoiding_banana || m_force_brake; } { return m_avoiding_item || m_force_brake; }
virtual bool ignorePathFinding() OVERRIDE virtual bool ignorePathFinding() OVERRIDE
{ return m_overtake_ball || m_chasing_ball; } { return m_overtake_ball || m_chasing_ball; }
public: public:

View File

@ -280,7 +280,7 @@ void Track::reset()
void Track::cleanup() void Track::cleanup()
{ {
QuadGraph::destroy(); QuadGraph::destroy();
BattleGraph::destroy(); Graph::destroy();
ItemManager::destroy(); ItemManager::destroy();
VAOManager::kill(); VAOManager::kill();
@ -678,7 +678,7 @@ void Track::loadBattleGraph(const XMLNode &node)
ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node); ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node);
Graph::setGraph(graph); Graph::setGraph(graph);
if(BattleGraph::get()->getNumNodes()==0) if(Graph::get()->getNumNodes()==0)
{ {
Log::warn("track", "No graph nodes defined for track '%s'\n", Log::warn("track", "No graph nodes defined for track '%s'\n",
m_filename.c_str()); m_filename.c_str());