Crowd: Detail API documentation for members declared in DetourPathCorridor.h.
This commit is contained in:
parent
82a5c863eb
commit
dee5f6a9bc
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "DetourNavMeshQuery.h"
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
/// Represents a dynamic polygon corridor used to plan agent movement
|
||||||
class dtPathCorridor
|
class dtPathCorridor
|
||||||
{
|
{
|
||||||
float m_pos[3];
|
float m_pos[3];
|
||||||
@ -35,17 +35,40 @@ public:
|
|||||||
dtPathCorridor();
|
dtPathCorridor();
|
||||||
~dtPathCorridor();
|
~dtPathCorridor();
|
||||||
|
|
||||||
|
/// Allocates the corridor's path buffer.
|
||||||
|
/// @param[in] maxPath The maximum path size the corridor can handle.
|
||||||
|
/// @return True if the initialization succeeded.
|
||||||
bool init(const int maxPath);
|
bool init(const int maxPath);
|
||||||
|
|
||||||
|
/// Resets the path corridor to the specified position.
|
||||||
|
/// @param[in] ref The polygon reference containing the position.
|
||||||
|
/// @param[in] pos The new position in the corridor. [(x, y, z)]
|
||||||
void reset(dtPolyRef ref, const float* pos);
|
void reset(dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
/// Finds the corners in the corridor from the position toward the target. (The straightened path.)
|
||||||
|
/// @param[out] cornerVerts The corner vertices. [(x, y, z) * cornerCount] [Size: <= maxCorners]
|
||||||
|
/// @param[out] cornerFlags The flag for each corner. [(flag) * cornerCount] [Size: <= maxCorners]
|
||||||
|
/// @param[out] cornerPolys The polygon reference for each corner. [(polyRef) * cornerCount]
|
||||||
|
/// [Size: <= @p maxCorners]
|
||||||
|
/// @param[in] maxCorners The maximum number of corners the buffers can hold.
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return The number of corners returned in the corner buffers. [0 <= value <= @p maxCorners]
|
||||||
int findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
int findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
||||||
dtPolyRef* cornerPolys, const int maxCorners,
|
dtPolyRef* cornerPolys, const int maxCorners,
|
||||||
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Attempts to optimize the path if the specified point is visible from the current position.
|
||||||
|
/// @param[in] next The point to search toward. [(x, y, z])
|
||||||
|
/// @param[in] pathOptimizationRange The maximum range to search. [Limit: > 0]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
void optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
void optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
||||||
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Attempts to optimize the path using a local area search. (Partial replanning.)
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
bool optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
bool optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
bool moveOverOffmeshConnection(dtPolyRef offMeshConRef, dtPolyRef* refs,
|
bool moveOverOffmeshConnection(dtPolyRef offMeshConRef, dtPolyRef* refs,
|
||||||
@ -55,20 +78,54 @@ public:
|
|||||||
bool trimInvalidPath(dtPolyRef safeRef, const float* safePos,
|
bool trimInvalidPath(dtPolyRef safeRef, const float* safePos,
|
||||||
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Checks the current corridor path to see if its polygon references remain valid.
|
||||||
|
/// @param[in] maxLookAhead The number of polygons from the beginning of the corridor to search.
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
bool isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
bool isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Moves the position from the current location to the desired location, adjusting the corridor
|
||||||
|
/// as needed to reflect the change.
|
||||||
|
/// @param[in] npos The desired new position. [(x, y, z)]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
void movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
void movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Moves the target from the curent location to the desired location, adjusting the corridor
|
||||||
|
/// as needed to reflect the change.
|
||||||
|
/// @param[in] npos The desired new target position. [(x, y, z)]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
void moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
void moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
void setCorridor(const float* target, const dtPolyRef* polys, const int npolys);
|
/// Loads a new path and target into the corridor.
|
||||||
|
/// @param[in] target The target location within the last polygon of the path. [(x, y, z)]
|
||||||
|
/// @param[in] path The path corridor. [(polyRef) * @p npolys]
|
||||||
|
/// @param[in] npath The number of polygons in the path.
|
||||||
|
void setCorridor(const float* target, const dtPolyRef* polys, const int npath);
|
||||||
|
|
||||||
|
/// Gets the current position within the corridor. (In the first polygon.)
|
||||||
|
/// @return The current position within the corridor.
|
||||||
inline const float* getPos() const { return m_pos; }
|
inline const float* getPos() const { return m_pos; }
|
||||||
|
|
||||||
|
/// Gets the current target within the corridor. (In the last polygon.)
|
||||||
|
/// @return The current target within the corridor.
|
||||||
inline const float* getTarget() const { return m_target; }
|
inline const float* getTarget() const { return m_target; }
|
||||||
|
|
||||||
|
/// The polygon reference id of the first polygon in the corridor, the polygon containing the position.
|
||||||
|
/// @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
|
||||||
inline dtPolyRef getFirstPoly() const { return m_npath ? m_path[0] : 0; }
|
inline dtPolyRef getFirstPoly() const { return m_npath ? m_path[0] : 0; }
|
||||||
|
|
||||||
|
/// The polygon reference id of the last polygon in the corridor, the polygon containing the target.
|
||||||
|
/// @return The polygon reference id of the last polygon in the corridor. (Or zero if there is no path.)
|
||||||
inline dtPolyRef getLastPoly() const { return m_npath ? m_path[m_npath-1] : 0; }
|
inline dtPolyRef getLastPoly() const { return m_npath ? m_path[m_npath-1] : 0; }
|
||||||
|
|
||||||
|
/// The corridor's path.
|
||||||
|
/// @return The corridor's path. [(polyRef) * #getPathCount()]
|
||||||
inline const dtPolyRef* getPath() const { return m_path; }
|
inline const dtPolyRef* getPath() const { return m_path; }
|
||||||
|
|
||||||
|
/// The number of polygons in the current corridor path.
|
||||||
|
/// @return The number of polygons in the current corridor path.
|
||||||
inline int getPathCount() const { return m_npath; }
|
inline int getPathCount() const { return m_npath; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -155,6 +155,47 @@ int dtMergeCorridorStartShortcut(dtPolyRef* path, const int npath, const int max
|
|||||||
return req+size;
|
return req+size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@class dtPathCorridor
|
||||||
|
@par
|
||||||
|
|
||||||
|
The corridor is loaded with a path, usually obtained from a #dtNavMeshQuery::findPath() query. The corridor
|
||||||
|
is then used to plan local movement, with the corridor automatically updating as needed to deal with inaccurate
|
||||||
|
agent locomotion.
|
||||||
|
|
||||||
|
Example of a common use case:
|
||||||
|
|
||||||
|
-# Construct the corridor object and call #init() to allocate its path buffer.
|
||||||
|
-# Obtain a path from a #dtNavMeshQuery object.
|
||||||
|
-# Use #reset() to set the agent's current position. (At the beginning of the path.)
|
||||||
|
-# Use #setCorridor() to load the path and target.
|
||||||
|
-# Use #findCorners() to plan movement. (This handles dynamic path straightening.)
|
||||||
|
-# Use #movePosition() to feed agent movement back into the corridor. (The corridor will automatically adjust as needed.)
|
||||||
|
-# If the target is moving, use #moveTargetPosition() to update the end of the corridor.
|
||||||
|
(The corridor will automatically adjust as needed.)
|
||||||
|
-# Repeat the previous 3 steps to continue to move the agent.
|
||||||
|
|
||||||
|
The corridor position and target are always constrained to the navigation mesh.
|
||||||
|
|
||||||
|
One of the difficulties in maintaining a path is that floating point errors, locomotion inaccuracies, and/or local
|
||||||
|
steering can result in the agent crossing the boundary of the path corridor, temporarily invalidating the path.
|
||||||
|
This class uses local mesh queries to detect and update the corridor as needed to handle these types of issues.
|
||||||
|
|
||||||
|
The fact that local mesh queries are used to move the position and target locations results in two beahviors that
|
||||||
|
need to be considered:
|
||||||
|
|
||||||
|
Every time a move function is used there is a chance that the path will become non-optimial. Basically, the further
|
||||||
|
the target is moved from its original location, and the further the position is moved outside the original corridor,
|
||||||
|
the more likely the path will become non-optimal. This issue can be addressed by periodically running the
|
||||||
|
#optimizePathTopology() and #optimizePathVisibility() methods.
|
||||||
|
|
||||||
|
All local mesh queries have distance limitations. (Review the #dtNavMeshQuery methods for details.) So the most accurate
|
||||||
|
use case is to move the position and target in small increments. If a large increment is used, then the corridor
|
||||||
|
may not be able to accurately find the new location. Because of this limiation, if a position is moved in a large
|
||||||
|
increment, then compare the desired and resulting polygon references. If the two do not match, then path replanning
|
||||||
|
may be needed. E.g. If you move the target, check #getLastPoly() to see if it is the expected polygon.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
dtPathCorridor::dtPathCorridor() :
|
dtPathCorridor::dtPathCorridor() :
|
||||||
m_path(0),
|
m_path(0),
|
||||||
@ -168,6 +209,9 @@ dtPathCorridor::~dtPathCorridor()
|
|||||||
dtFree(m_path);
|
dtFree(m_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// @warning Cannot be called more than once.
|
||||||
bool dtPathCorridor::init(const int maxPath)
|
bool dtPathCorridor::init(const int maxPath)
|
||||||
{
|
{
|
||||||
dtAssert(!m_path);
|
dtAssert(!m_path);
|
||||||
@ -179,6 +223,10 @@ bool dtPathCorridor::init(const int maxPath)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Essentially, the corridor is set of one polygon in size with the target
|
||||||
|
/// equal to the position.
|
||||||
void dtPathCorridor::reset(dtPolyRef ref, const float* pos)
|
void dtPathCorridor::reset(dtPolyRef ref, const float* pos)
|
||||||
{
|
{
|
||||||
dtAssert(m_path);
|
dtAssert(m_path);
|
||||||
@ -188,6 +236,18 @@ void dtPathCorridor::reset(dtPolyRef ref, const float* pos)
|
|||||||
m_npath = 1;
|
m_npath = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
This is the function used to plan local movement within the corridor. One or more corners can be
|
||||||
|
detected in order to plan movement. It performs essentially the same function as #dtNavMeshQuery::findStraightPath.
|
||||||
|
|
||||||
|
Due to internal optimizations, the maximum number of corners returned will be (@p maxCorners - 1)
|
||||||
|
For example: If the buffers are sized to hold 10 corners, the function will never return more than 9 corners.
|
||||||
|
So if 10 corners are needed, the buffers should be sized for 11 corners.
|
||||||
|
|
||||||
|
If the target is within range, it will be the last corner and have a polygon reference id of zero.
|
||||||
|
*/
|
||||||
int dtPathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
int dtPathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
||||||
dtPolyRef* cornerPolys, const int maxCorners,
|
dtPolyRef* cornerPolys, const int maxCorners,
|
||||||
dtNavMeshQuery* navquery, const dtQueryFilter* /*filter*/)
|
dtNavMeshQuery* navquery, const dtQueryFilter* /*filter*/)
|
||||||
@ -229,6 +289,21 @@ int dtPathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
|||||||
return ncorners;
|
return ncorners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Inaccurate locomotion or dynamic obstacle avoidance can force the argent position significantly outside the
|
||||||
|
original corridor. Over time this can result in the formation of a non-optimal corridor. This function uses an
|
||||||
|
efficient local visibility search to try to re-optimize the corridor between the current position and @p next.
|
||||||
|
|
||||||
|
The corridor will change only if @p next is visible from the current position and moving directly toward the point
|
||||||
|
is better than following the existing path.
|
||||||
|
|
||||||
|
The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency
|
||||||
|
of the call to match the needs to the agent.
|
||||||
|
|
||||||
|
This function is not suitable for long distance searches.
|
||||||
|
*/
|
||||||
void dtPathCorridor::optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
void dtPathCorridor::optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
||||||
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
{
|
{
|
||||||
@ -262,6 +337,16 @@ void dtPathCorridor::optimizePathVisibility(const float* next, const float pathO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Inaccurate locomotion or dynamic obstacle avoidance can force the agent position significantly outside the
|
||||||
|
original corridor. Over time this can result in the formation of a non-optimal corridor. This function will use a
|
||||||
|
local area path search to try to re-optimize the corridor.
|
||||||
|
|
||||||
|
The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency of
|
||||||
|
the call to match the needs to the agent.
|
||||||
|
*/
|
||||||
bool dtPathCorridor::optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
bool dtPathCorridor::optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
{
|
{
|
||||||
dtAssert(navquery);
|
dtAssert(navquery);
|
||||||
@ -333,6 +418,21 @@ bool dtPathCorridor::moveOverOffmeshConnection(dtPolyRef offMeshConRef, dtPolyRe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
- The movement is constrained to the surface of the navigation mesh.
|
||||||
|
- The corridor is automatically adjusted (shorted or lengthened) in order to remain valid.
|
||||||
|
- The new position will be located in the adjusted corridor's first polygon.
|
||||||
|
|
||||||
|
The expected use case is that the desired position will be 'near' the current corridor. What is considered 'near'
|
||||||
|
depends on local polygon density, query search extents, etc.
|
||||||
|
|
||||||
|
The resulting position will differ from the desired position if the desired position is not on the navigation mesh,
|
||||||
|
or it can't be reached using a local search.
|
||||||
|
*/
|
||||||
void dtPathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
void dtPathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
{
|
{
|
||||||
dtAssert(m_path);
|
dtAssert(m_path);
|
||||||
@ -354,6 +454,19 @@ void dtPathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, c
|
|||||||
dtVcopy(m_pos, result);
|
dtVcopy(m_pos, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
- The movement is constrained to the surface of the navigation mesh.
|
||||||
|
- The corridor is automatically adjusted (shorted or lengthened) in order to remain valid.
|
||||||
|
- The new target will be located in the adjusted corridor's last polygon.
|
||||||
|
|
||||||
|
The expected use case is that the desired target will be 'near' the current corridor. What is considered 'near' depends on local polygon density, query search extents, etc.
|
||||||
|
|
||||||
|
The resulting target will differ from the desired target if the desired target is not on the navigation mesh, or it can't be reached using a local search.
|
||||||
|
*/
|
||||||
void dtPathCorridor::moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
void dtPathCorridor::moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
{
|
{
|
||||||
dtAssert(m_path);
|
dtAssert(m_path);
|
||||||
@ -377,6 +490,12 @@ void dtPathCorridor::moveTargetPosition(const float* npos, dtNavMeshQuery* navqu
|
|||||||
dtVcopy(m_target, result);
|
dtVcopy(m_target, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The current corridor position is expected to be within the first polygon in the path. The target
|
||||||
|
/// is expected to be in the last polygon.
|
||||||
|
///
|
||||||
|
/// @warning The size of the path must not exceed the size of corridor's path buffer set during #init().
|
||||||
void dtPathCorridor::setCorridor(const float* target, const dtPolyRef* path, const int npath)
|
void dtPathCorridor::setCorridor(const float* target, const dtPolyRef* path, const int npath)
|
||||||
{
|
{
|
||||||
dtAssert(m_path);
|
dtAssert(m_path);
|
||||||
@ -427,6 +546,10 @@ bool dtPathCorridor::trimInvalidPath(dtPolyRef safeRef, const float* safePos,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The path can be invalidated if there are structural changes to the underlying navigation mesh, or the state of
|
||||||
|
/// a polygon within the path changes resulting in it being filtered out. (E.g. An exclusion or inclusion flag changes.)
|
||||||
bool dtPathCorridor::isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
bool dtPathCorridor::isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
{
|
{
|
||||||
// Check that all polygons still pass query filter.
|
// Check that all polygons still pass query filter.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user