Added information about which successor of a graph node to
use in order to reach a certain target graph node. This is now used by the rubber ball to follow karts even if they are on an alternatice way/shortcut. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9773 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -150,8 +150,15 @@ void RubberBall::computeTarget()
|
||||
unsigned int RubberBall::getSuccessorToHitTarget(unsigned int node_index,
|
||||
float *dist)
|
||||
{
|
||||
// For now: always pick a successor on the main driveline.
|
||||
int succ = 0;
|
||||
LinearWorld *lin_world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
// FIXME: what does the rubber ball do in case of battle mode??
|
||||
if(lin_world)
|
||||
{
|
||||
unsigned int sect =
|
||||
lin_world->getSectorForKart(m_target->getWorldKartId());
|
||||
succ = QuadGraph::get()->getNode(node_index).getSuccessorToReach(sect);
|
||||
}
|
||||
if(dist)
|
||||
*dist += QuadGraph::get()->getNode(node_index)
|
||||
.getDistanceToSuccessor(succ);
|
||||
|
||||
@@ -46,6 +46,7 @@ GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index)
|
||||
m_node_index = node_index;
|
||||
m_predecessor = -1;
|
||||
m_distance_from_start = 0;
|
||||
|
||||
const Quad &quad = m_all_quads->getQuad(m_quad_index);
|
||||
// FIXME: the following values should depend on the actual orientation
|
||||
// of the quad. ATM we always assume that indices 0,1 are the lower end,
|
||||
@@ -117,6 +118,71 @@ void GraphNode::addSuccessor(unsigned int to)
|
||||
}
|
||||
} // addSuccessor
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** If this node has more than one successor, it will set up a vector that
|
||||
* contains the direction to use when a certain graph node X should be
|
||||
* reached.
|
||||
*/
|
||||
void GraphNode::setupPathsToNode()
|
||||
{
|
||||
if(m_successor_node.size()<2) return;
|
||||
|
||||
const unsigned int num_nodes = QuadGraph::get()->getNumNodes();
|
||||
m_path_to_node.resize(num_nodes);
|
||||
|
||||
// Initialise each graph node with -1, indicating that
|
||||
// it hasn't been reached yet.
|
||||
for(unsigned int i=0; i<num_nodes; i++)
|
||||
m_path_to_node[i] = -1;
|
||||
|
||||
// Indicate that this node can be reached from this node by following
|
||||
// successor 0 - just a dummy value that might only be used during the
|
||||
// recursion below.
|
||||
m_path_to_node[m_node_index] = 0;
|
||||
|
||||
// A simple depth first search is used to determine which successor to
|
||||
// use to reach a certain graph node. Using Dijkstra's algorithm would
|
||||
// give the shortest way to reach a certain node, but the shortest way
|
||||
// might involve some shortcuts which are hidden, and should therefore
|
||||
// not be used.
|
||||
for(unsigned int i=0; i<getNumberOfSuccessors(); i++)
|
||||
{
|
||||
GraphNode &gn = QuadGraph::get()->getNode(getSuccessor(i));
|
||||
gn.markAllSuccessorsToUse(i, &m_path_to_node);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for(unsigned int i=0; i<m_path_to_node.size(); i++)
|
||||
{
|
||||
if(m_path_to_node[i]==-1)
|
||||
printf("[WARNING] No path to node %d found on graph node %d.\n",
|
||||
i, m_node_index);
|
||||
}
|
||||
#endif
|
||||
} // setupPathsToNode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function marks that the successor n should be used to reach this
|
||||
* node. It then recursively (depth first) does the same for all its
|
||||
* successors. Depth-first
|
||||
* \param n The successor which should be used in m_path_node to reach
|
||||
* this node.
|
||||
* \param path_to_node The path-to-node data structure of the node for
|
||||
* which the paths are currently determined.
|
||||
*/
|
||||
void GraphNode::markAllSuccessorsToUse(unsigned int n,
|
||||
PathToNodeVector *path_to_node)
|
||||
{
|
||||
// End recursion if the path to this node has already been found.
|
||||
if( (*path_to_node)[m_node_index] >-1) return;
|
||||
|
||||
(*path_to_node)[m_node_index] = n;
|
||||
for(unsigned int i=0; i<getNumberOfSuccessors(); i++)
|
||||
{
|
||||
GraphNode &gn = QuadGraph::get()->getNode(getSuccessor(i));
|
||||
gn.markAllSuccessorsToUse(n, path_to_node);
|
||||
}
|
||||
} // markAllSuccesorsToUse
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the distance a point has from this quad in forward and sidewards
|
||||
* direction, i.e. how far forwards the point is from the beginning of the
|
||||
|
||||
@@ -88,6 +88,16 @@ class GraphNode
|
||||
* from the center of the drivelines anyway. */
|
||||
core::line2df m_line;
|
||||
|
||||
typedef std::vector<int> PathToNodeVector;
|
||||
/** This vector is only used if the graph node has more than one
|
||||
* successor. In this case m_path_to_node[X] will contain the index
|
||||
* of the successor to use in order to reach graph node X for this
|
||||
* graph nodes. */
|
||||
PathToNodeVector m_path_to_node;
|
||||
|
||||
void markAllSuccessorsToUse(unsigned int n,
|
||||
PathToNodeVector *m_path_to_node);
|
||||
|
||||
public:
|
||||
/** Keep a shared pointer so that some asserts and tests can be
|
||||
* done without adding additional parameters. */
|
||||
@@ -100,7 +110,8 @@ public:
|
||||
void addSuccessor (unsigned int to);
|
||||
void getDistances(const Vec3 &xyz, Vec3 *result);
|
||||
float getDistance2FromPoint(const Vec3 &xyz);
|
||||
|
||||
void setupPathsToNode();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the i-th successor node. */
|
||||
unsigned int getSuccessor(unsigned int i) const
|
||||
{ return m_successor_node[i]; }
|
||||
@@ -163,6 +174,17 @@ public:
|
||||
/** Returns a predecessor for this node. */
|
||||
int getPredecessor() const {return m_predecessor; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns which successor node to use in order to be able to reach the
|
||||
* given node n.
|
||||
* \param n Index of the graph node to reach.
|
||||
*/
|
||||
int getSuccessorToReach(unsigned int n)
|
||||
{
|
||||
// If we have a path to node vector, use its information, otherwise
|
||||
// (i.e. there is only one successor anyway) use this one successor.
|
||||
return m_path_to_node.size()>0 ? m_path_to_node[n] : 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
}; // GraphNode
|
||||
|
||||
#endif
|
||||
|
||||
@@ -166,6 +166,7 @@ void QuadGraph::load(const std::string &filename)
|
||||
}
|
||||
delete xml;
|
||||
|
||||
// Define the track length
|
||||
for(unsigned int i=0; i<m_all_nodes.size(); i++)
|
||||
{
|
||||
if(m_all_nodes[i]->getSuccessor(0)==0)
|
||||
@@ -176,8 +177,31 @@ void QuadGraph::load(const std::string &filename)
|
||||
}
|
||||
}
|
||||
setDefaultSuccessors();
|
||||
|
||||
} // load
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function defines the "path-to-nodes" for each graph node that has
|
||||
* more than one successor. The path-to-nodes indicates which successor to
|
||||
* use to reach a certain node. This is e.g. used for the rubber ball to
|
||||
* determine which path it is going to use to reach its target (this allows
|
||||
* the ball to hit a target that is on a shortcut). The algorithm for the
|
||||
* path computation favours the use of successor 0, i.e. it will if possible
|
||||
* only use main driveline paths, not a shortcut (even though a shortcut
|
||||
* could result in a faster way to the target) - but since shotcuts can
|
||||
* potentially be hidden they should not be used (unless necessary).
|
||||
* Only graph nodes with more than one successor have this data structure
|
||||
* (since on other graph nodes only one path can be used anyway, this
|
||||
* saves some memory).
|
||||
*/
|
||||
void QuadGraph::setupPaths()
|
||||
{
|
||||
for(unsigned int i=0; i<getNumNodes(); i++)
|
||||
{
|
||||
m_all_nodes[i]->setupPathsToNode();
|
||||
}
|
||||
} // setupPaths
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** This function sets a default successor for all graph nodes that currently
|
||||
* don't have a successor defined. The default successor of node X is X+1.
|
||||
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
=video::SColor(127, 255, 255, 255) );
|
||||
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
||||
void updateDistancesForAllSuccessors(unsigned int indx, float delta);
|
||||
|
||||
void setupPaths();
|
||||
// ----------------------------------------------------------------------
|
||||
/** Returns the one instance of this object. It is possible that there
|
||||
* is no instance created (e.g. in battle mode, since it doesn't have
|
||||
|
||||
@@ -393,6 +393,8 @@ void Track::loadQuadGraph(unsigned int mode_id)
|
||||
{
|
||||
QuadGraph::create(m_root+"/"+m_all_modes[mode_id].m_quad_name,
|
||||
m_root+"/"+m_all_modes[mode_id].m_graph_name);
|
||||
|
||||
QuadGraph::get()->setupPaths();
|
||||
#ifdef DEBUG
|
||||
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user