Change the whole path to avoid bad items

This commit is contained in:
Benau
2016-10-02 15:03:09 +08:00
parent d3301ff006
commit fc94c5e4c4
3 changed files with 111 additions and 75 deletions

View File

@@ -29,6 +29,8 @@
#include "tracks/arena_graph.hpp"
#include "tracks/arena_node.hpp"
#include <algorithm>
ArenaAI::ArenaAI(AbstractKart *kart)
: AIBaseController(kart)
{
@@ -52,7 +54,6 @@ void ArenaAI::reset()
m_closest_kart_point = Vec3(0, 0, 0);
m_is_stuck = false;
m_is_uturn = false;
m_avoiding_item = false;
m_mini_skid = false;
m_target_point = Vec3(0, 0, 0);
m_target_point_lc = Vec3(0, 0, 0);
@@ -79,7 +80,6 @@ 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_item = false;
// Don't do anything if there is currently a kart animations shown.
if (m_kart->getKartAnimation())
@@ -149,10 +149,9 @@ void ArenaAI::update(float dt)
} // update
//-----------------------------------------------------------------------------
/** Update aiming position, use path finding if necessary, it will set the turn
* radius too.
* \param[out] suitable target point.
* \return true if found a suitable target point.
/** 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)
{
@@ -165,6 +164,7 @@ bool ArenaAI::updateAimingPosition(Vec3* target_point)
m_current_forward_point =
m_kart->getTrans()(Vec3(0, 0, m_kart->getKartLength()));
m_turn_radius = 0.0f;
std::vector<int>* test_nodes = NULL;
if (m_current_forward_node != Graph::UNKNOWN_SECTOR)
{
@@ -185,35 +185,27 @@ bool ArenaAI::updateAimingPosition(Vec3* target_point)
m_target_node == Graph::UNKNOWN_SECTOR)
{
Log::error("ArenaAI", "Next node is unknown, path finding failed!");
m_turn_radius = 0.0f;
return false;
}
if (forward == m_target_node)
{
if (checkBadItem(&m_target_node))
m_target_point = m_graph->getNode(m_target_node)->getCenter();
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);
// Use this next node for aim point if valid
if (next_node == Graph::UNKNOWN_SECTOR)
{
Log::error("ArenaAI", "Next node is unknown, did you forget to link"
" adjacent face in navmesh?");
m_turn_radius = 0.0f;
return false;
}
checkBadItem(&next_node);
*target_point = m_graph->getNode(next_node)->getCenter();
// Then keep getting next node to find the first turning corner which is
// used to determine turn radius
path.push_back(next_node);
while (m_target_node != next_node)
{
int previous_node = next_node;
@@ -222,31 +214,14 @@ bool ArenaAI::updateAimingPosition(Vec3* target_point)
{
Log::error("ArenaAI", "Next node is unknown, did you forget to"
" link adjacent face in navmesh?");
m_turn_radius = 0.0f;
return false;
}
const Vec3& p1 = m_kart->getXYZ();
const Vec3& p2 = m_graph->getNode(previous_node)->getCenter();
const Vec3& p3 = m_graph->getNode(next_node)->getCenter();
float edge1 = (p1 - p2).length();
float edge2 = (p2 - p3).length();
float to_target = (p1 - p3).length();
if (fabsf(edge1 + edge2 - to_target) > 0.1f)
{
// Triangle test
determineTurnRadius(p3, NULL, &m_turn_radius);
#ifdef AI_DEBUG
m_debug_sphere_next->setVisible(true);
m_debug_sphere_next->setPosition(p3.toIrrVector());
#endif
return true;
}
path.push_back(next_node);
}
// Target node == next node
determineTurnRadius(m_target_point, NULL, &m_turn_radius);
determinePath(forward, &path);
*target_point = m_graph->getNode(path.front())->getCenter();
return true;
} // updateAimingPosition
@@ -397,6 +372,7 @@ void ArenaAI::doUTurn(const float dt)
// End U-turn until target point is in front of this AI
m_is_uturn = false;
m_time_since_uturn = 0.0f;
m_time_since_driving = 0.0f;
}
else
m_is_uturn = true;
@@ -429,37 +405,6 @@ bool ArenaAI::gettingUnstuck(const float dt)
} // gettingUnstuck
//-----------------------------------------------------------------------------
bool ArenaAI::checkBadItem(int* node)
{
// Check if the node AI will cross will meet bad items
assert(*node != Graph::UNKNOWN_SECTOR);
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))
{
// Choose any nearby node that is in front of the AI to prevent hitting
// bad item
ArenaNode* cur_node = m_graph->getNode(*node);
const float dist = (m_kart->getXYZ() - cur_node->getCenter()).length();
const std::vector<int>* nearby_nodes = cur_node->getNearbyNodes();
for (const int& nearby_node : *nearby_nodes)
{
Vec3 lc = m_kart->getTrans().inverse()
(m_graph->getNode(nearby_node)->getCenter());
if (lc.z() > 0 && dist > lc.length())
{
*node = nearby_node;
return true;
}
}
}
return false;
} // checkBadItem
//-----------------------------------------------------------------------------
void ArenaAI::useItems(const float dt)
{
@@ -702,3 +647,97 @@ void ArenaAI::doSkiddingTest()
}
} // doSkiddingTest
//-----------------------------------------------------------------------------
/** 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 path Default path to target.
*/
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

View File

@@ -63,8 +63,6 @@ protected:
/** The target point. */
Vec3 m_target_point;
bool m_avoiding_item;
bool m_mini_skid;
void collectItemInArena(Vec3*, int*) const;
@@ -112,8 +110,8 @@ private:
void configSpeed();
void configSteering();
bool checkBadItem(int* node);
void checkIfStuck(const float dt);
void determinePath(int forward, std::vector<int>* path);
void doSkiddingTest();
void doUTurn(const float dt);
bool gettingUnstuck(const float dt);
@@ -123,7 +121,7 @@ private:
{ return m_mini_skid; }
virtual void findClosestKart(bool use_difficulty) = 0;
virtual void findTarget() = 0;
virtual bool forceBraking() { return m_avoiding_item; }
virtual bool forceBraking() { return false; }
virtual int getCurrentNode() const = 0;
virtual float getKartDistance(const AbstractKart* kart) const = 0;
virtual bool ignorePathFinding() { return false; }

View File

@@ -67,8 +67,7 @@ private:
{ return m_mini_skid && !(m_overtake_ball || m_chasing_ball); }
virtual void findClosestKart(bool use_difficulty) OVERRIDE;
virtual void findTarget() OVERRIDE;
virtual bool forceBraking() OVERRIDE
{ return m_avoiding_item || m_force_brake; }
virtual bool forceBraking() OVERRIDE { return m_force_brake; }
virtual int getCurrentNode() const OVERRIDE;
virtual float getKartDistance(const AbstractKart* kart) const OVERRIDE;
virtual bool ignorePathFinding() OVERRIDE