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:
hikerstk
2012-09-03 22:49:30 +00:00
parent 20382c0f15
commit 35c7cf0848
8 changed files with 363 additions and 68 deletions

View File

@@ -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
//-----------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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, &sector);
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

View File

@@ -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
//-----------------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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() );

View File

@@ -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