Added first version of item avoidance to the AI.
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11537 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -35,8 +35,8 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
|
||||
{
|
||||
assert(type != ITEM_TRIGGER); // use other constructor for that
|
||||
|
||||
initItem(type, xyz);
|
||||
m_distance_2 = 0.8f;
|
||||
initItem(type, xyz);
|
||||
// Sets heading to 0, and sets pitch and roll depending on the normal. */
|
||||
m_original_hpr = Vec3(0, normal);
|
||||
m_original_mesh = mesh;
|
||||
@@ -83,6 +83,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
|
||||
*/
|
||||
Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
|
||||
{
|
||||
m_distance_2 = distance*distance;
|
||||
initItem(ITEM_TRIGGER, xyz);
|
||||
// Sets heading to 0, and sets pitch and roll depending on the normal. */
|
||||
m_original_hpr = Vec3(0, 0, 0);
|
||||
@@ -90,16 +91,16 @@ Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
|
||||
m_original_lowmesh = NULL;
|
||||
m_node = NULL;
|
||||
m_listener = trigger;
|
||||
m_distance_2 = distance*distance;
|
||||
} // Item(xyz, distance, trigger)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Initialises the item.
|
||||
/** Initialises the item. Note that m_distance_2 must be defined before calling
|
||||
* this function, since it pre-computes some values based on this.
|
||||
* \param type Type of the item.
|
||||
*/
|
||||
void Item::initItem(ItemType type, const Vec3 &xyz)
|
||||
{
|
||||
m_type = type;
|
||||
m_type = type;
|
||||
m_xyz = xyz;
|
||||
m_event_handler = NULL;
|
||||
m_item_id = -1;
|
||||
@@ -111,6 +112,34 @@ void Item::initItem(ItemType type, const Vec3 &xyz)
|
||||
m_disappear_counter = m_type==ITEM_BUBBLEGUM
|
||||
? stk_config->m_bubble_gum_counter
|
||||
: -1 ;
|
||||
// Now determine in which quad this item is, and its distance
|
||||
// from the center within this quad.
|
||||
m_graph_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
QuadGraph::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
|
||||
{
|
||||
// Item is on quad graph. Pre-compute the distance from center
|
||||
// of this item, which is used by the AI (mostly for avoiding items)
|
||||
Vec3 distances;
|
||||
QuadGraph::get()->spatialToTrack(&distances, m_xyz, m_graph_node);
|
||||
m_distance_from_center = distances.getX();
|
||||
const GraphNode &gn = QuadGraph::get()->getNode(m_graph_node);
|
||||
const Vec3 right = gn.getRightUnitVector();
|
||||
// Give it 10% more space, since the kart will not always come
|
||||
// parallel to the drive line.
|
||||
Vec3 delta = right * sqrt(m_distance_2) * 1.1f;
|
||||
m_avoidance_points[0] = new Vec3(m_xyz + delta);
|
||||
m_avoidance_points[1] = new Vec3(m_xyz - delta);
|
||||
}
|
||||
|
||||
} // initItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -186,6 +215,10 @@ Item::~Item()
|
||||
irr_driver->removeNode(m_node);
|
||||
m_node->drop();
|
||||
}
|
||||
if(m_avoidance_points[0])
|
||||
delete m_avoidance_points[0];
|
||||
if(m_avoidance_points[1])
|
||||
delete m_avoidance_points[1];
|
||||
} // ~Item
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -93,8 +93,7 @@ private:
|
||||
* case of a switch to restore the rotation of a bubble gum
|
||||
* (bubble gums don't rotate, but it will be replaced with
|
||||
* a nitro which rotates, and so overwrites the original
|
||||
* rotation).
|
||||
*/
|
||||
* rotation). */
|
||||
Vec3 m_original_hpr;
|
||||
|
||||
/** True if item was collected & is not displayed. */
|
||||
@@ -138,8 +137,21 @@ private:
|
||||
TriggerItemListener* m_listener;
|
||||
|
||||
/** square distance at which item is collected */
|
||||
float m_distance_2;
|
||||
float m_distance_2;
|
||||
|
||||
/** The graph node this item is on. */
|
||||
int m_graph_node;
|
||||
|
||||
/** Distance from the center of the quad this item is in. This value is
|
||||
* >0 if it is to the right of the center, and undefined if this quad
|
||||
* is not on any quad. */
|
||||
float m_distance_from_center;
|
||||
|
||||
/** The closest point to the left and right of this item at which it
|
||||
* would not be collected. Used by the AI to avoid items. */
|
||||
Vec3 *m_avoidance_points[2];
|
||||
|
||||
|
||||
void initItem(ItemType type, const Vec3 &xyz);
|
||||
void setType(ItemType type);
|
||||
|
||||
@@ -164,12 +176,32 @@ public:
|
||||
* \param xyz Location of kart (avoiding to use kart->getXYZ() so that
|
||||
* kart.hpp does not need to be included here).
|
||||
*/
|
||||
bool hitKart (const AbstractKart *kart, const Vec3 &xyz) const
|
||||
bool hitKart (const Vec3 &xyz, const AbstractKart *kart=NULL) const
|
||||
{
|
||||
return (m_event_handler!=kart || m_deactive_time <=0) &&
|
||||
(xyz-m_xyz).length2()<m_distance_2;
|
||||
} // hitKart
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if the Kart is close enough to hit this item, the item is
|
||||
* not deactivated anymore, and it wasn't placed by this kart (this is
|
||||
* e.g. used to avoid that a kart hits a bubble gum it just dropped).
|
||||
* This function only uses the 2d coordinates, and it used by the AI only.
|
||||
* \param kart Kart to test.
|
||||
* \param xyz Location of kart (avoiding to use kart->getXYZ() so that
|
||||
* kart.hpp does not need to be included here).
|
||||
*/
|
||||
protected:
|
||||
friend class SkiddingAI;
|
||||
bool hitKart (const core::vector2df &xyz, const AbstractKart *kart=NULL) const
|
||||
{
|
||||
if(m_event_handler==kart && m_deactive_time >0) return false;
|
||||
float d2 = (m_xyz.getX()-xyz.X)*(m_xyz.getX()-xyz.X)
|
||||
+ (m_xyz.getZ()-xyz.Y)*(m_xyz.getZ()-xyz.Y);
|
||||
return d2 < m_distance_2;
|
||||
} // hitKart
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the index of this item in the item manager list. */
|
||||
void setItemId(unsigned int n) { m_item_id = n; }
|
||||
@@ -205,6 +237,23 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the XYZ position of the item. */
|
||||
const Vec3& getXYZ() const { return m_xyz; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the index of the graph node this item is on. */
|
||||
int getGraphNode() const { return m_graph_node; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the distance from center: negative means left of center,
|
||||
* positive means right of center. */
|
||||
float getDistanceFromCenter() const { return m_distance_from_center; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a point to the left or right of the item which will not trigger
|
||||
* a collection of this item.
|
||||
* \param left If true, return a point to the left, else a point to
|
||||
* the right. */
|
||||
const Vec3 *getAvoidancePoint(bool left) const
|
||||
{
|
||||
if(left) return m_avoidance_points[0];
|
||||
return m_avoidance_points[1];
|
||||
} // getAvoidancePoint
|
||||
}; // class Item
|
||||
|
||||
#endif
|
||||
|
||||
@@ -215,13 +215,15 @@ void ItemManager::insertItem(Item *item)
|
||||
// (i.e. race mode has a quad graph).
|
||||
if(m_items_in_quads)
|
||||
{
|
||||
const Vec3 &xyz = item->getXYZ();
|
||||
int sector = QuadGraph::UNKNOWN_SECTOR;
|
||||
QuadGraph::get()->findRoadSector(xyz, §or);
|
||||
if(sector==QuadGraph::UNKNOWN_SECTOR)
|
||||
(*m_items_in_quads)[m_items_in_quads->size()-1].push_back(item);
|
||||
else
|
||||
int graph_node = item->getGraphNode();
|
||||
// If the item is on the driveline, store it at the appropriate index
|
||||
if(graph_node > -1)
|
||||
{
|
||||
int sector = QuadGraph::get()->getNode(graph_node).getQuadIndex();
|
||||
(*m_items_in_quads)[sector].push_back(item);
|
||||
}
|
||||
else // otherwise store it in the 'outside' index
|
||||
(*m_items_in_quads)[m_items_in_quads->size()-1].push_back(item);
|
||||
} // if m_items_in_quads
|
||||
} // insertItem
|
||||
|
||||
@@ -300,7 +302,7 @@ void ItemManager::checkItemHit(AbstractKart* kart)
|
||||
if((!*i) || (*i)->wasCollected()) continue;
|
||||
// To allow inlining and avoid including kart.hpp in item.hpp,
|
||||
// we pass the kart and the position separately.
|
||||
if((*i)->hitKart(kart, kart->getXYZ()))
|
||||
if((*i)->hitKart(kart->getXYZ(), kart))
|
||||
{
|
||||
collectedItem(*i, kart);
|
||||
} // if hit
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
# undef AI_DEBUG_CIRCLES
|
||||
// Show the heading of the kart
|
||||
# undef AI_DEBUG_KART_HEADING
|
||||
// Shows line from kart to its aim point
|
||||
# undef AI_DEBUG_KART_AIM
|
||||
#endif
|
||||
|
||||
#include "karts/controller/skidding_ai.hpp"
|
||||
@@ -134,7 +136,8 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
#define CURVE_KART 1
|
||||
#define CURVE_LEFT 2
|
||||
#define CURVE_RIGHT 3
|
||||
#define CURVE_QG 4
|
||||
#define CURVE_AIM 4
|
||||
#define CURVE_QG 5
|
||||
#define NUM_CURVES (CURVE_QG+1)
|
||||
|
||||
m_curve = new ShowCurve*[NUM_CURVES];
|
||||
@@ -156,6 +159,10 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
#endif
|
||||
m_curve[CURVE_QG] = new ShowCurve(0.5f, 0.5f,
|
||||
irr::video::SColor(128, 0, 128, 0));
|
||||
#ifdef AI_DEBUG_KART_AIM
|
||||
m_curve[CURVE_AIM] = new ShowCurve(0.5f, 0.5f,
|
||||
irr::video::SColor(128, 0, 0, 128));
|
||||
#endif
|
||||
#endif
|
||||
setControllerName("Skidding");
|
||||
|
||||
@@ -491,6 +498,12 @@ void SkiddingAI::handleSteering(float dt)
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(aim_point.toIrrVector());
|
||||
#endif
|
||||
#ifdef AI_DEBUG_KART_AIM
|
||||
const Vec3 eps(0,0.5f,0);
|
||||
m_curve[CURVE_AIM]->clear();
|
||||
m_curve[CURVE_AIM]->addPoint(m_kart->getXYZ()+eps);
|
||||
m_curve[CURVE_AIM]->addPoint(aim_point);
|
||||
#endif
|
||||
|
||||
// Potentially adjust the point to aim for in order to either
|
||||
// aim to collect item, or steer to avoid a bad item.
|
||||
@@ -513,6 +526,9 @@ void SkiddingAI::handleSteering(float dt)
|
||||
void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
int last_node)
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(false);
|
||||
#endif
|
||||
// Angle of line from kart to aim_point
|
||||
float kart_aim_angle = atan2(aim_point->getX()-m_kart->getXYZ().getX(),
|
||||
aim_point->getZ()-m_kart->getXYZ().getZ());
|
||||
@@ -531,6 +547,10 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
{
|
||||
// Still aim at the previsouly selected item.
|
||||
*aim_point = m_item_to_collect->getXYZ();
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(true);
|
||||
m_item_sphere->setPosition(aim_point->toIrrVector());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -548,8 +568,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
|
||||
int node = m_track_node;
|
||||
float distance = 0;
|
||||
const Item *item_to_collect = NULL;
|
||||
const Item *item_to_avoid = NULL;
|
||||
std::vector<const Item *> items_to_collect;
|
||||
std::vector<const Item *> items_to_avoid;
|
||||
|
||||
|
||||
const float max_item_lookahead_distance = 30.f;
|
||||
@@ -561,7 +581,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
for(unsigned int i=0; i<items_ahead.size(); i++)
|
||||
{
|
||||
evaluateItems(items_ahead[i], kart_aim_angle,
|
||||
&item_to_avoid, &item_to_collect);
|
||||
&items_to_avoid, &items_to_collect);
|
||||
} // for i<items_ahead;
|
||||
distance += QuadGraph::get()->getDistanceToNext(node,
|
||||
m_successor_index[node]);
|
||||
@@ -570,21 +590,34 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
if(node==last_node) break;
|
||||
} // while (distance < max_item_lookahead_distance)
|
||||
|
||||
core::line2df line_to_target(m_kart->getXYZ().getX(),
|
||||
m_kart->getXYZ().getZ(),
|
||||
aim_point->getX(), aim_point->getZ());
|
||||
core::line2df line_to_target(aim_point->getX(),
|
||||
aim_point->getZ(),
|
||||
m_kart->getXYZ().getX(),
|
||||
m_kart->getXYZ().getZ());
|
||||
|
||||
|
||||
if(item_to_collect)
|
||||
if(items_to_avoid.size()>0)
|
||||
{
|
||||
// If we need to steer to avoid an item, this takes priority,
|
||||
// ignore items to collect and return the new aim_point.
|
||||
if(steerToAvoid(items_to_avoid, line_to_target, aim_point))
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(false);
|
||||
m_item_sphere->setVisible(true);
|
||||
m_item_sphere->setPosition(aim_point->toIrrVector());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(items_to_collect.size()>0)
|
||||
{
|
||||
const Item *item_to_collect = items_to_collect[0];
|
||||
core::vector2df collect(item_to_collect->getXYZ().getX(),
|
||||
item_to_collect->getXYZ().getZ());
|
||||
core::vector2df cp = line_to_target.getClosestPoint(collect);
|
||||
Vec3 xyz(cp.X, item_to_collect->getXYZ().getY(), cp.Y);
|
||||
if(item_to_collect->hitKart(NULL, xyz))
|
||||
if(item_to_collect->hitKart(xyz, m_kart))
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(true);
|
||||
@@ -672,6 +705,149 @@ bool SkiddingAI::handleSelectedItem(float kart_aim_angle,
|
||||
return true;
|
||||
} // handleSelectedItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Decides if steering is necessary to avoid bad items. If so, it modifies
|
||||
* the aim_point and returns true.
|
||||
* \param items_to_avoid List of items to avoid.
|
||||
* \param line_to_target The 2d line from the current kart position to
|
||||
* the current aim point.
|
||||
* \param aim_point The point the AI is steering towards (not taking items
|
||||
* into account).
|
||||
* \return True if steering is necessary to avoid an item.
|
||||
*/
|
||||
bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
|
||||
const core::line2df &line_to_target,
|
||||
Vec3 *aim_point)
|
||||
{
|
||||
// First determine the left-most and right-most item.
|
||||
float left_most = items_to_avoid[0]->getDistanceFromCenter();
|
||||
float right_most = items_to_avoid[0]->getDistanceFromCenter();
|
||||
int index_left_most = 0;
|
||||
int index_right_most = 0;
|
||||
|
||||
for(unsigned int i=1; i<items_to_avoid.size(); i++)
|
||||
{
|
||||
float dist = items_to_avoid[i]->getDistanceFromCenter();
|
||||
if (dist<left_most)
|
||||
{
|
||||
left_most = dist;
|
||||
index_left_most = i;
|
||||
}
|
||||
if(dist>right_most)
|
||||
{
|
||||
right_most = dist;
|
||||
index_right_most = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we would drive left of the leftmost or right of the
|
||||
// rightmost point - if so, nothing to do.
|
||||
core::vector2df left(items_to_avoid[index_left_most]->getXYZ().getX(),
|
||||
items_to_avoid[index_left_most]->getXYZ().getZ());
|
||||
int item_index = -1;
|
||||
bool is_left = false;
|
||||
|
||||
// >=0 means the point is to the right of the line, or the line is
|
||||
// to the left of the point.
|
||||
if(line_to_target.getPointOrientation(left)>=0)
|
||||
{
|
||||
// Left of leftmost point
|
||||
item_index = index_left_most;
|
||||
is_left = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
core::vector2df right(items_to_avoid[index_right_most]->getXYZ().getX(),
|
||||
items_to_avoid[index_right_most]->getXYZ().getZ());
|
||||
if(line_to_target.getPointOrientation(right)<=0)
|
||||
{
|
||||
// Right of rightmost point
|
||||
item_index = index_right_most;
|
||||
is_left = false;
|
||||
}
|
||||
}
|
||||
if(item_index>-1)
|
||||
{
|
||||
core::vector2df point =
|
||||
items_to_avoid[item_index]->getXYZ().toIrrVector2d();
|
||||
// Even though we are on the side, we must make sure
|
||||
// that we don't hit that item
|
||||
core::vector2df close = line_to_target.getClosestPoint(point, true);
|
||||
Vec3 close3d(close.X, m_kart->getXYZ().getY(), close.Y);
|
||||
// If we don't hit the item on the side, no more tests are necessary
|
||||
if(!items_to_avoid[item_index]->hitKart(close3d, m_kart))
|
||||
return false;
|
||||
|
||||
// See if we can avoid this item by driving further to the side
|
||||
const Vec3 *avoid_point = items_to_avoid[item_index]
|
||||
->getAvoidancePoint(is_left);
|
||||
// If avoid_point is NULL, it means steering more to the sides
|
||||
// brings us off track. In this case just try to steer to the
|
||||
// other side (e.g. when hitting a left-most item and the kart can't
|
||||
// steer further left, steer a bit to the right of the left-most item
|
||||
// (without further tests if we might hit anything else).
|
||||
if(!avoid_point)
|
||||
avoid_point = items_to_avoid[item_index]
|
||||
->getAvoidancePoint(!is_left);
|
||||
*aim_point = *avoid_point;
|
||||
return true;
|
||||
}
|
||||
|
||||
// At this stage there must be at least two items - if there was
|
||||
// only a single item, the 'left of left-most' or 'right of right-most'
|
||||
// tests above are had been and an appropriate steering point was already
|
||||
// determined.
|
||||
|
||||
// Try to identify two items we are driving between (if the kart is not
|
||||
// driving between two items, one of the 'left of left-most' etc.
|
||||
// tests before applied and this point would not be reached).
|
||||
|
||||
float min_distance[2] = {99999.9f, 99999.9f};
|
||||
int index[2] = {-1, -1};
|
||||
core::vector2df closest2d[2];
|
||||
for(unsigned int i=0; i<items_to_avoid.size(); i++)
|
||||
{
|
||||
const Vec3 &xyz = items_to_avoid[i]->getXYZ();
|
||||
core::vector2df item2d = xyz.toIrrVector2d();
|
||||
core::vector2df point2d = line_to_target.getClosestPoint(item2d);
|
||||
float d = (xyz.toIrrVector2d() - point2d).getLengthSQ();
|
||||
float direction = line_to_target.getPointOrientation(item2d);
|
||||
int ind = direction<0 ? 0 : 1;
|
||||
if(d<min_distance[ind])
|
||||
{
|
||||
min_distance[ind] = d;
|
||||
index[ind] = i;
|
||||
closest2d[ind] = point2d;
|
||||
}
|
||||
}
|
||||
|
||||
assert(index[0]!= index[1]);
|
||||
assert(index[0]!=-1 );
|
||||
assert(index[1]!=-1 );
|
||||
|
||||
// We are driving between item_to_avoid[index[0]] and ...[1].
|
||||
// If we don't hit any of them, just keep on driving as normal
|
||||
bool hit_left = items_to_avoid[index[0]]->hitKart(closest2d[0], m_kart);
|
||||
bool hit_right = items_to_avoid[index[1]]->hitKart(closest2d[1], m_kart);
|
||||
if( !hit_left && !hit_right)
|
||||
return false;
|
||||
|
||||
// If we hit the left item, aim at the right avoidance point
|
||||
// of the left item. We might still hit the right item ... this might
|
||||
// still be better than going too far off track
|
||||
if(hit_left)
|
||||
{
|
||||
*aim_point =
|
||||
*(items_to_avoid[index[0]]->getAvoidancePoint(/*left*/false));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now we must be hitting the right item, so try aiming at the left
|
||||
// avoidance point of the right item.
|
||||
*aim_point = *(items_to_avoid[index[1]]->getAvoidancePoint(/*left*/true));
|
||||
return true;
|
||||
} // steerToAvoid
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This subroutine decides if the specified item should be collected,
|
||||
* avoided, or ignored (i.e. not interesting). It can use the state of the
|
||||
@@ -686,15 +862,16 @@ bool SkiddingAI::handleSelectedItem(float kart_aim_angle,
|
||||
* \param item_to_collect A pointer to a previously selected item to collect.
|
||||
*/
|
||||
void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
|
||||
const Item **item_to_avoid,
|
||||
const Item **item_to_collect)
|
||||
std::vector<const Item *> *items_to_avoid,
|
||||
std::vector<const Item *> *items_to_collect)
|
||||
{
|
||||
// Ignore items that are currently disabled
|
||||
if(item->getDisableTime()>0) return;
|
||||
|
||||
// If the item type is not handled here, ignore it
|
||||
Item::ItemType type = item->getType();
|
||||
if( type!=Item::ITEM_BANANA && type!=Item::ITEM_BONUS_BOX &&
|
||||
if( type!=Item::ITEM_BANANA && type!=Item::ITEM_BUBBLEGUM &&
|
||||
type!=Item::ITEM_BONUS_BOX &&
|
||||
type!=Item::ITEM_NITRO_BIG && type!=Item::ITEM_NITRO_SMALL )
|
||||
return;
|
||||
|
||||
@@ -729,50 +906,69 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
|
||||
} // switch
|
||||
|
||||
|
||||
// item_angle The angle of the item (relative to the forward axis,
|
||||
// so 0 means straight ahead in world coordinates!).
|
||||
const Vec3 &xyz = item->getXYZ();
|
||||
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
|
||||
xyz.getZ() - m_kart->getXYZ().getZ());
|
||||
// Ignore items to be collected that are out of our way (though all items
|
||||
// to avoid are collected).
|
||||
if(!avoid)
|
||||
{
|
||||
// item_angle The angle of the item (relative to the forward axis,
|
||||
// so 0 means straight ahead in world coordinates!).
|
||||
const Vec3 &xyz = item->getXYZ();
|
||||
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
|
||||
xyz.getZ() - m_kart->getXYZ().getZ());
|
||||
|
||||
float diff = normalizeAngle(kart_aim_angle-item_angle);
|
||||
float diff = normalizeAngle(kart_aim_angle-item_angle);
|
||||
|
||||
// The kart is driving at high speed, when the current max speed
|
||||
// is higher than the max speed of the kart (which is caused by
|
||||
// any powerups etc)
|
||||
// Otherwise check for skidding. If the kart is still collecting
|
||||
// skid bonus, currentMaxSpeed is not affected yet, but it might
|
||||
// be if the kart would need to turn sharper, therefore stops
|
||||
// skidding, and will get the bonus speed.
|
||||
bool high_speed = (m_kart->getCurrentMaxSpeed() >
|
||||
m_kart->getKartProperties()->getMaxSpeed() ) ||
|
||||
m_kart->getSkidding()->getSkidBonusReady();
|
||||
float max_angle = high_speed
|
||||
? m_ai_properties->m_max_item_angle_high_speed
|
||||
: m_ai_properties->m_max_item_angle;
|
||||
// The kart is driving at high speed, when the current max speed
|
||||
// is higher than the max speed of the kart (which is caused by
|
||||
// any powerups etc)
|
||||
// Otherwise check for skidding. If the kart is still collecting
|
||||
// skid bonus, currentMaxSpeed is not affected yet, but it might
|
||||
// be if the kart would need to turn sharper, therefore stops
|
||||
// skidding, and will get the bonus speed.
|
||||
bool high_speed = (m_kart->getCurrentMaxSpeed() >
|
||||
m_kart->getKartProperties()->getMaxSpeed() ) ||
|
||||
m_kart->getSkidding()->getSkidBonusReady();
|
||||
float max_angle = high_speed
|
||||
? m_ai_properties->m_max_item_angle_high_speed
|
||||
: m_ai_properties->m_max_item_angle;
|
||||
|
||||
if(fabsf(diff) > max_angle)
|
||||
return;
|
||||
if(fabsf(diff) > max_angle)
|
||||
return;
|
||||
|
||||
float steer_direction = normalizeAngle(m_kart->getHeading()
|
||||
- kart_aim_angle );
|
||||
float item_direction = normalizeAngle(m_kart->getHeading()
|
||||
- item_angle );
|
||||
// If we have to steer to the left, and the item is to the right
|
||||
// or vice versa, ignore the item.
|
||||
if(steer_direction * item_direction < 0)
|
||||
return;
|
||||
float steer_direction = normalizeAngle(m_kart->getHeading()
|
||||
- kart_aim_angle );
|
||||
float item_direction = normalizeAngle(m_kart->getHeading()
|
||||
- item_angle );
|
||||
// If we have to steer to the left, and the item is to the right
|
||||
// or vice versa, ignore the item.
|
||||
if(!avoid && (steer_direction * item_direction < 0) )
|
||||
return;
|
||||
} // if !avoid
|
||||
|
||||
// Now insert the item into the sorted list of items to avoid
|
||||
// (or to collect). The lists are (for now) sorted by distance
|
||||
std::vector<const Item*> *list;
|
||||
if(avoid)
|
||||
{
|
||||
if(!(*item_to_avoid))
|
||||
*item_to_avoid = item;
|
||||
}
|
||||
list = items_to_avoid;
|
||||
else
|
||||
list = items_to_collect;
|
||||
|
||||
float new_distance = (item->getXYZ() - m_kart->getXYZ()).length2_2d();
|
||||
|
||||
// This list is usually very short, so use a simple bubble sort
|
||||
list->push_back(item);
|
||||
int i;
|
||||
for(i=list->size()-2; i>=0; i--)
|
||||
{
|
||||
if(!(*item_to_collect))
|
||||
*item_to_collect = item;
|
||||
float d = ((*list)[i]->getXYZ() - m_kart->getXYZ()).length2_2d();
|
||||
if(d<=new_distance)
|
||||
{
|
||||
break;
|
||||
}
|
||||
(*list)[i+1] = (*list)[i];
|
||||
}
|
||||
(*list)[i+1] = item;
|
||||
|
||||
} // evaluateItems
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -173,9 +173,12 @@ private:
|
||||
int last_node);
|
||||
bool handleSelectedItem(float kart_aim_angle, Vec3 *aim_point,
|
||||
int last_node);
|
||||
bool steerToAvoid(const std::vector<const Item *> &items_to_avoid,
|
||||
const core::line2df &line_to_target,
|
||||
Vec3 *aim_point);
|
||||
void evaluateItems(const Item *item, float kart_aim_angle,
|
||||
const Item **item_to_avoid,
|
||||
const Item **item_to_collect);
|
||||
std::vector<const Item *> *items_to_avoid,
|
||||
std::vector<const Item *> *items_to_collect);
|
||||
|
||||
void checkCrashes(const Vec3& pos);
|
||||
void findNonCrashingPoint(Vec3 *result, int *last_node);
|
||||
|
||||
@@ -245,7 +245,7 @@ void RaceManager::computeRandomKartList()
|
||||
|
||||
if (m_ai_kart_override != "")
|
||||
{
|
||||
for (int n = 0; n < m_ai_kart_list.size(); n++)
|
||||
for (unsigned int n = 0; n < m_ai_kart_list.size(); n++)
|
||||
{
|
||||
m_ai_kart_list[n] = m_ai_kart_override;
|
||||
}
|
||||
|
||||
@@ -45,20 +45,26 @@ GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index)
|
||||
// of the quad. ATM we always assume that indices 0,1 are the lower end,
|
||||
// and 2,3 are the upper end (or the reverse if reverse mode is selected).
|
||||
// The width is the average width at the beginning and at the end.
|
||||
m_right_unit_vector = ( quad[0]-quad[1]
|
||||
+quad[3]-quad[2]) * 0.5f;
|
||||
m_right_unit_vector.normalize();
|
||||
|
||||
m_width = ( (quad[1]-quad[0]).length()
|
||||
+ (quad[3]-quad[2]).length() ) * 0.5f;
|
||||
|
||||
if(QuadGraph::get()->isReverse())
|
||||
{
|
||||
m_lower_center = (quad[2]+quad[3]) * 0.5f;
|
||||
m_upper_center = (quad[0]+quad[1]) * 0.5f;
|
||||
m_right_unit_vector *= -1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lower_center = (quad[0]+quad[1]) * 0.5f;
|
||||
m_upper_center = (quad[2]+quad[3]) * 0.5f;
|
||||
}
|
||||
m_line = core::line2df(m_lower_center.getX(), m_lower_center.getZ(),
|
||||
m_upper_center.getX(), m_upper_center.getZ() );
|
||||
m_line = core::line2df(m_upper_center.getX(), m_upper_center.getZ(),
|
||||
m_lower_center.getX(), m_lower_center.getZ() );
|
||||
// Only this 2d point is needed later
|
||||
m_lower_center_2d = core::vector2df(m_lower_center.getX(),
|
||||
m_lower_center.getZ() );
|
||||
|
||||
@@ -113,6 +113,10 @@ private:
|
||||
* left. */
|
||||
std::vector<unsigned int> m_last_index_same_direction;
|
||||
|
||||
/** A unit vector pointing from the center to the right side, orthogonal
|
||||
* to the driving direction. */
|
||||
Vec3 m_right_unit_vector;
|
||||
|
||||
/**
|
||||
* Sets of checklines you should have activated when you are driving on
|
||||
* this node (there is a possibility of more than one set because of
|
||||
@@ -226,6 +230,8 @@ public:
|
||||
*dir = m_direction[succ]; *last = m_last_index_same_direction[succ];
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a unit vector pointing to the right side of the quad. */
|
||||
const Vec3 &getRightUnitVector() const { return m_right_unit_vector; }
|
||||
}; // GraphNode
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user