reposition DT_CROWDAGENT_MAX_NEIGHBOURS, DT_CROWDAGENT_MAX_CORNERS

This commit is contained in:
ikpil 2024-02-15 00:25:55 +09:00
parent bd4825dcd5
commit 742b7f7db8
3 changed files with 130 additions and 123 deletions

View File

@ -24,137 +24,116 @@ using DotRecast.Core;
using DotRecast.Core.Collections; using DotRecast.Core.Collections;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
namespace DotRecast.Detour.Crowd namespace DotRecast.Detour.Crowd
{ {
///////////////////////////////////////////////////////////////////////////
// This section contains detailed documentation for members that don't have
// a source file. It reduces clutter in the main section of the header.
/** /**
* Members in this module implement local steering and dynamic avoidance features.
* @defgroup crowd Crowd
* The crowd is the big beast of the navigation features. It not only handles a lot of the path management for you, but
* also local steering and dynamic avoidance between members of the crowd. I.e. It can keep your agents from running Members in this module implement local steering and dynamic avoidance features.
* into each other.
* The crowd is the big beast of the navigation features. It not only handles a
* Main class: Crowd lot of the path management for you, but also local steering and dynamic
* avoidance between members of the crowd. I.e. It can keep your agents from
* The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy to use path planning features. But in running into each other.
* the end they only give you points that your navigation client should be moving toward. When it comes to deciding
* things like agent velocity and steering to avoid other agents, that is up to you to implement. Unless, of course, you Main class: #dtCrowd
* decide to use Crowd.
* The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy
* Basically, you add an agent to the crowd, providing various configuration settings such as maximum speed and to use path planning features. But in the end they only give you points that
* acceleration. You also provide a local target to move toward. The crowd manager then provides, with every update, the your navigation client should be moving toward. When it comes to deciding things
* new agent position and velocity for the frame. The movement will be constrained to the navigation mesh, and steering like agent velocity and steering to avoid other agents, that is up to you to
* will be applied to ensure agents managed by the crowd do not collide with each other. implement. Unless, of course, you decide to use #dtCrowd.
*
* This is very powerful feature set. But it comes with limitations. Basically, you add an agent to the crowd, providing various configuration
* settings such as maximum speed and acceleration. You also provide a local
* The biggest limitation is that you must give control of the agent's position completely over to the crowd manager. target to more toward. The crowd manager then provides, with every update, the
* You can update things like maximum speed and acceleration. But in order for the crowd manager to do its thing, it new agent position and velocity for the frame. The movement will be
* can't allow you to constantly be giving it overrides to position and velocity. So you give up direct control of the constrained to the navigation mesh, and steering will be applied to ensure
* agent's movement. It belongs to the crowd. agents managed by the crowd do not collide with each other.
*
* The second biggest limitation revolves around the fact that the crowd manager deals with local planning. So the This is very powerful feature set. But it comes with limitations.
* agent's target should never be more than 256 polygons away from its current position. If it is, you risk your agent
* failing to reach its target. So you may still need to do long distance planning and provide the crowd manager with The biggest limitation is that you must give control of the agent's position
* intermediate targets. completely over to the crowd manager. You can update things like maximum speed
* and acceleration. But in order for the crowd manager to do its thing, it can't
* Other significant limitations: allow you to constantly be giving it overrides to position and velocity. So
* you give up direct control of the agent's movement. It belongs to the crowd.
* - All agents using the crowd manager will use the same #dtQueryFilter. - Crowd management is relatively expensive.
* The maximum agents under crowd management at any one time is between 20 and 30. A good place to start is a maximum of The second biggest limitation revolves around the fact that the crowd manager
* 25 agents for 0.5ms per frame. deals with local planning. So the agent's target should never be more than
* 256 polygons aways from its current position. If it is, you risk
* @note This is a summary list of members. Use the index or search feature to find minor members. your agent failing to reach its target. So you may still need to do long
* distance planning and provide the crowd manager with intermediate targets.
* @struct dtCrowdAgentParams
* @see CrowdAgent, Crowd::AddAgent(), Crowd::UpdateAgentParameters() Other significant limitations:
*
* @var dtCrowdAgentParams::obstacleAvoidanceType - All agents using the crowd manager will use the same #dtQueryFilter.
* @par - Crowd management is relatively expensive. The maximum agents under crowd
* management at any one time is between 20 and 30. A good place to start
* #dtCrowd permits agents to use different avoidance configurations. This value is the index of the is a maximum of 25 agents for 0.5ms per frame.
* #dtObstacleAvoidanceParams within the crowd.
* @note This is a summary list of members. Use the index or search
* @see dtObstacleAvoidanceParams, dtCrowd::SetObstacleAvoidanceParams(), dtCrowd::GetObstacleAvoidanceParams() feature to find minor members.
*
* @var dtCrowdAgentParams::collisionQueryRange @struct dtCrowdAgentParams
* @par @see dtCrowdAgent, dtCrowd::addAgent(), dtCrowd::updateAgentParameters()
*
* Collision elements include other agents and navigation mesh boundaries. @var dtCrowdAgentParams::obstacleAvoidanceType
* @par
* This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
* #dtCrowd permits agents to use different avoidance configurations. This value
* @var dtCrowdAgentParams::pathOptimizationRange is the index of the #dtObstacleAvoidanceParams within the crowd.
* @par
* @see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(),
* Only applicable if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag. dtCrowd::getObstacleAvoidanceParams()
*
* This value is often based on the agent radius. E.g. radius * 30 @var dtCrowdAgentParams::collisionQueryRange
* @par
* @see dtPathCorridor::OptimizePathVisibility()
* Collision elements include other agents and navigation mesh boundaries.
* @var dtCrowdAgentParams::separationWeight
* @par This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
*
* A higher value will result in agents trying to stay farther away from each other at the cost of more difficult @var dtCrowdAgentParams::pathOptimizationRange
* steering in tight spaces. @par
*
*/ Only applicable if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag.
/**
* This is the core class of the refs crowd module. See the refs crowd documentation for a summary of the crowd This value is often based on the agent radius. E.g. radius * 30
* features. A common method for setting up the crowd is as follows: -# Allocate the crowd -# Set the avoidance
* configurations using #SetObstacleAvoidanceParams(). -# Add agents using #AddAgent() and make an initial movement @see dtPathCorridor::optimizePathVisibility()
* request using #RequestMoveTarget(). A common process for managing the crowd is as follows: -# Call #Update() to allow
* the crowd to manage its agents. -# Retrieve agent information using #GetActiveAgents(). -# Make movement requests @var dtCrowdAgentParams::separationWeight
* using #RequestMoveTarget() when movement goal changes. -# Repeat every frame. Some agent configuration settings can @par
* be updated using #UpdateAgentParameters(). But the crowd owns the agent position. So it is not possible to update an
* active agent's position. If agent position must be fed back into the crowd, the agent must be removed and re-added. A higher value will result in agents trying to stay farther away from each other at
* Notes: - Path related information is available for newly added agents only after an #Update() has been performed. - the cost of more difficult steering in tight spaces.
* Agent objects are kept in a pool and re-used. So it is important when using agent objects to check the value of
* #dtCrowdAgent::active to determine if the agent is actually in use or not. - This class is meant to provide 'local'
* movement. There is a limit of 256 polygons in the path corridor. So it is not meant to provide automatic pathfinding
* services over long distances.
*
* @see DtAllocCrowd(), DtFreeCrowd(), Init(), dtCrowdAgent
*/ */
/// Provides local steering behaviors for a group of agents.
/// @ingroup crowd
public class DtCrowd public class DtCrowd
{ {
/// The maximum number of corners a crowd agent will look ahead in the path.
/// This value is used for sizing the crowd agent corner buffers.
/// Due to the behavior of the crowd manager, the actual number of useful
/// corners will be one less than this number.
/// @ingroup crowd
public const int DT_CROWDAGENT_MAX_CORNERS = 4;
/// The maximum number of crowd avoidance configurations supported by the
/// crowd manager.
/// @ingroup crowd
/// @see dtObstacleAvoidanceParams, dtCrowd::SetObstacleAvoidanceParams(), dtCrowd::GetObstacleAvoidanceParams(),
/// dtCrowdAgentParams::obstacleAvoidanceType
public const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
/// The maximum number of query filter types supported by the crowd manager.
/// @ingroup crowd
/// @see dtQueryFilter, dtCrowd::GetFilter() dtCrowd::GetEditableFilter(),
/// dtCrowdAgentParams::queryFilterType
public const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
private readonly RcAtomicInteger _agentId = new RcAtomicInteger(); private readonly RcAtomicInteger _agentId = new RcAtomicInteger();
private readonly List<DtCrowdAgent> _agents; private readonly List<DtCrowdAgent> _agents;
private readonly DtPathQueue _pathQ; private readonly DtPathQueue _pathQ;
private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams = new DtObstacleAvoidanceParams[DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]; private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams = new DtObstacleAvoidanceParams[DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];
private readonly DtObstacleAvoidanceQuery _obstacleQuery; private readonly DtObstacleAvoidanceQuery _obstacleQuery;
private DtProximityGrid _grid; private DtProximityGrid _grid;
private readonly RcVec3f _ext = new RcVec3f(); private readonly RcVec3f _ext = new RcVec3f();
private readonly IDtQueryFilter[] _filters = new IDtQueryFilter[DT_CROWD_MAX_QUERY_FILTER_TYPE]; private readonly IDtQueryFilter[] _filters = new IDtQueryFilter[DtCrowdConst.DT_CROWD_MAX_QUERY_FILTER_TYPE];
private DtNavMeshQuery _navQuery; private DtNavMeshQuery _navQuery;
private DtNavMesh _navMesh; private DtNavMesh _navMesh;
private readonly DtCrowdConfig _config; private readonly DtCrowdConfig _config;
private readonly DtCrowdTelemetry _telemetry = new DtCrowdTelemetry(); private readonly DtCrowdTelemetry _telemetry = new DtCrowdTelemetry();
private int _velocitySampleCount; private int _velocitySampleCount;
public DtCrowd(DtCrowdConfig config, DtNavMesh nav) : public DtCrowd(DtCrowdConfig config, DtNavMesh nav) : this(config, nav, i => new DtQueryDefaultFilter())
this(config, nav, i => new DtQueryDefaultFilter())
{ {
} }
@ -165,13 +144,13 @@ namespace DotRecast.Detour.Crowd
_obstacleQuery = new DtObstacleAvoidanceQuery(config.maxObstacleAvoidanceCircles, config.maxObstacleAvoidanceSegments); _obstacleQuery = new DtObstacleAvoidanceQuery(config.maxObstacleAvoidanceCircles, config.maxObstacleAvoidanceSegments);
for (int i = 0; i < DT_CROWD_MAX_QUERY_FILTER_TYPE; i++) for (int i = 0; i < DtCrowdConst.DT_CROWD_MAX_QUERY_FILTER_TYPE; i++)
{ {
_filters[i] = queryFilterFactory.Invoke(i); _filters[i] = queryFilterFactory.Invoke(i);
} }
// Init obstacle query option. // Init obstacle query option.
for (int i = 0; i < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i) for (int i = 0; i < DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i)
{ {
_obstacleQueryParams[i] = new DtObstacleAvoidanceParams(); _obstacleQueryParams[i] = new DtObstacleAvoidanceParams();
} }
@ -206,7 +185,7 @@ namespace DotRecast.Detour.Crowd
/// @param[in] option The new configuration. /// @param[in] option The new configuration.
public void SetObstacleAvoidanceParams(int idx, DtObstacleAvoidanceParams option) public void SetObstacleAvoidanceParams(int idx, DtObstacleAvoidanceParams option)
{ {
if (idx >= 0 && idx < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS) if (idx >= 0 && idx < DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
{ {
_obstacleQueryParams[idx] = new DtObstacleAvoidanceParams(option); _obstacleQueryParams[idx] = new DtObstacleAvoidanceParams(option);
} }
@ -218,7 +197,7 @@ namespace DotRecast.Detour.Crowd
/// @return The requested configuration. /// @return The requested configuration.
public DtObstacleAvoidanceParams GetObstacleAvoidanceParams(int idx) public DtObstacleAvoidanceParams GetObstacleAvoidanceParams(int idx)
{ {
if (idx >= 0 && idx < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS) if (idx >= 0 && idx < DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
{ {
return _obstacleQueryParams[idx]; return _obstacleQueryParams[idx];
} }
@ -375,7 +354,7 @@ namespace DotRecast.Detour.Crowd
public IDtQueryFilter GetFilter(int i) public IDtQueryFilter GetFilter(int i)
{ {
return i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE ? _filters[i] : null; return i >= 0 && i < DtCrowdConst.DT_CROWD_MAX_QUERY_FILTER_TYPE ? _filters[i] : null;
} }
public DtProximityGrid GetGrid() public DtProximityGrid GetGrid()
@ -945,7 +924,7 @@ namespace DotRecast.Detour.Crowd
} }
// Find corners for steering // Find corners for steering
ag.corridor.FindCorners(ref ag.corners, DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]); ag.corridor.FindCorners(ref ag.corners, DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
// Check to see if the corner after the next corner is directly visible, // Check to see if the corner after the next corner is directly visible,
// and short cut to there. // and short cut to there.

View File

@ -0,0 +1,30 @@
namespace DotRecast.Detour.Crowd
{
public static class DtCrowdConst
{
/// The maximum number of neighbors that a crowd agent can take into account
/// for steering decisions.
/// @ingroup crowd
public const int DT_CROWDAGENT_MAX_NEIGHBOURS = 6;
/// The maximum number of corners a crowd agent will look ahead in the path.
/// This value is used for sizing the crowd agent corner buffers.
/// Due to the behavior of the crowd manager, the actual number of useful
/// corners will be one less than this number.
/// @ingroup crowd
public const int DT_CROWDAGENT_MAX_CORNERS = 4;
/// The maximum number of crowd avoidance configurations supported by the
/// crowd manager.
/// @ingroup crowd
/// @see dtObstacleAvoidanceParams, dtCrowd::SetObstacleAvoidanceParams(), dtCrowd::GetObstacleAvoidanceParams(),
/// dtCrowdAgentParams::obstacleAvoidanceType
public const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
/// The maximum number of query filter types supported by the crowd manager.
/// @ingroup crowd
/// @see dtQueryFilter, dtCrowd::GetFilter() dtCrowd::GetEditableFilter(),
/// dtCrowdAgentParams::queryFilterType
public const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
}
}

View File

@ -25,8 +25,6 @@ using DotRecast.Core.Numerics;
namespace DotRecast.Detour.Crowd namespace DotRecast.Detour.Crowd
{ {
public class DtLocalBoundary public class DtLocalBoundary
{ {
public const int MAX_LOCAL_SEGS = 8; public const int MAX_LOCAL_SEGS = 8;