diff --git a/DetourCrowd/Include/DetourCrowd.h b/DetourCrowd/Include/DetourCrowd.h index 243ac5a..9f92cdf 100644 --- a/DetourCrowd/Include/DetourCrowd.h +++ b/DetourCrowd/Include/DetourCrowd.h @@ -45,6 +45,12 @@ static const int DT_CROWDAGENT_MAX_CORNERS = 4; /// dtCrowdAgentParams::obstacleAvoidanceType static 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 +static const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16; + /// Provides neighbor data for agents managed by the crowd. /// @ingroup crowd /// @see dtCrowdAgent::neis, dtCrowd @@ -87,6 +93,9 @@ struct dtCrowdAgentParams /// [Limits: 0 <= value <= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS] unsigned char obstacleAvoidanceType; + /// The index of the query filter used by this agent. + unsigned char queryFilterType; + /// User defined data attached to the agent. void* userData; }; @@ -206,8 +215,9 @@ class dtCrowd int m_maxPathResult; float m_ext[3]; - dtQueryFilter m_filter; - + + dtQueryFilter m_filters[DT_CROWD_MAX_QUERY_FILTER_TYPE]; + float m_maxAgentRadius; int m_velocitySampleCount; @@ -251,6 +261,11 @@ public: /// @return The requested agent. const dtCrowdAgent* getAgent(const int idx); + /// Gets the specified agent from the pool. + /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()] + /// @return The requested agent. + dtCrowdAgent* getEditableAgent(const int idx); + /// The maximum number of agents that can be managed by the object. /// @return The maximum number of agents. int getAgentCount() const; @@ -301,11 +316,11 @@ public: /// Gets the filter used by the crowd. /// @return The filter used by the crowd. - const dtQueryFilter* getFilter() const { return &m_filter; } - + inline const dtQueryFilter* getFilter(const int i) const { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; } + /// Gets the filter used by the crowd. /// @return The filter used by the crowd. - dtQueryFilter* getEditableFilter() { return &m_filter; } + inline dtQueryFilter* getEditableFilter(const int i) { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; } /// Gets the search extents [(x, y, z)] used by the crowd for query operations. /// @return The search extents used by the crowd. [(x, y, z)] diff --git a/DetourCrowd/Source/DetourCrowd.cpp b/DetourCrowd/Source/DetourCrowd.cpp index cf7a027..4297b65 100644 --- a/DetourCrowd/Source/DetourCrowd.cpp +++ b/DetourCrowd/Source/DetourCrowd.cpp @@ -484,6 +484,17 @@ int dtCrowd::getAgentCount() const /// Agents in the pool may not be in use. Check #dtCrowdAgent.active before using the returned object. const dtCrowdAgent* dtCrowd::getAgent(const int idx) { + if (idx < 0 || idx >= m_maxAgents) + return 0; + return &m_agents[idx]; +} + +/// +/// Agents in the pool may not be in use. Check #dtCrowdAgent.active before using the returned object. +dtCrowdAgent* dtCrowd::getEditableAgent(const int idx) +{ + if (idx < 0 || idx >= m_maxAgents) + return 0; return &m_agents[idx]; } @@ -512,13 +523,13 @@ int dtCrowd::addAgent(const float* pos, const dtCrowdAgentParams* params) if (idx == -1) return -1; - dtCrowdAgent* ag = &m_agents[idx]; + dtCrowdAgent* ag = &m_agents[idx]; // Find nearest position on navmesh and place the agent there. float nearest[3]; dtPolyRef ref = 0; dtVcopy(nearest, pos); - dtStatus status = m_navquery->findNearestPoly(pos, m_ext, &m_filter, &ref, nearest); + dtStatus status = m_navquery->findNearestPoly(pos, m_ext, &m_filters[ag->params.queryFilterType], &ref, nearest); if (dtStatusFailed(status)) { dtVcopy(nearest, pos); @@ -691,7 +702,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/) // Quick seach towards the goal. static const int MAX_ITER = 20; - m_navquery->initSlicedFindPath(path[0], ag->targetRef, ag->npos, ag->targetPos, &m_filter); + m_navquery->initSlicedFindPath(path[0], ag->targetRef, ag->npos, ag->targetPos, &m_filters[ag->params.queryFilterType]); m_navquery->updateSlicedFindPath(MAX_ITER, 0); dtStatus status = 0; if (ag->targetReplan) // && npath > 10) @@ -758,7 +769,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/) { dtCrowdAgent* ag = queue[i]; ag->targetPathqRef = m_pathq.request(ag->corridor.getLastPoly(), ag->targetRef, - ag->corridor.getTarget(), ag->targetPos, &m_filter); + ag->corridor.getTarget(), ag->targetPos, &m_filters[ag->params.queryFilterType]); if (ag->targetPathqRef != DT_PATHQ_INVALID) ag->targetState = DT_CROWDAGENT_TARGET_WAITING_FOR_PATH; } @@ -912,7 +923,7 @@ void dtCrowd::updateTopologyOptimization(dtCrowdAgent** agents, const int nagent for (int i = 0; i < nqueue; ++i) { dtCrowdAgent* ag = queue[i]; - ag->corridor.optimizePathTopology(m_navquery, &m_filter); + ag->corridor.optimizePathTopology(m_navquery, &m_filters[ag->params.queryFilterType]); ag->topologyOptTime = 0; } @@ -929,9 +940,6 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const if (ag->state != DT_CROWDAGENT_STATE_WALKING) continue; - - if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY) - continue; ag->targetReplanTime += dt; @@ -942,14 +950,14 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const float agentPos[3]; dtPolyRef agentRef = ag->corridor.getFirstPoly(); dtVcopy(agentPos, ag->npos); - if (!m_navquery->isValidPolyRef(agentRef, &m_filter)) + if (!m_navquery->isValidPolyRef(agentRef, &m_filters[ag->params.queryFilterType])) { // Current location is not valid, try to reposition. // TODO: this can snap agents, how to handle that? float nearest[3]; dtVcopy(nearest, agentPos); agentRef = 0; - m_navquery->findNearestPoly(ag->npos, m_ext, &m_filter, &agentRef, nearest); + m_navquery->findNearestPoly(ag->npos, m_ext, &m_filters[ag->params.queryFilterType], &agentRef, nearest); dtVcopy(agentPos, nearest); if (!agentRef) @@ -971,16 +979,20 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const replan = true; } + // If the agent does not have move target or is controlled by velocity, no need to recover the target nor replan. + if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY) + continue; + // Try to recover move request position. if (ag->targetState != DT_CROWDAGENT_TARGET_NONE && ag->targetState != DT_CROWDAGENT_TARGET_FAILED) { - if (!m_navquery->isValidPolyRef(ag->targetRef, &m_filter)) + if (!m_navquery->isValidPolyRef(ag->targetRef, &m_filters[ag->params.queryFilterType])) { // Current target is not valid, try to reposition. float nearest[3]; dtVcopy(nearest, ag->targetPos); ag->targetRef = 0; - m_navquery->findNearestPoly(ag->targetPos, m_ext, &m_filter, &ag->targetRef, nearest); + m_navquery->findNearestPoly(ag->targetPos, m_ext, &m_filters[ag->params.queryFilterType], &ag->targetRef, nearest); dtVcopy(ag->targetPos, nearest); replan = true; } @@ -993,7 +1005,7 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const } // If nearby corridor is not valid, replan. - if (!ag->corridor.isValid(CHECK_LOOKAHEAD, m_navquery, &m_filter)) + if (!ag->corridor.isValid(CHECK_LOOKAHEAD, m_navquery, &m_filters[ag->params.queryFilterType])) { // Fix current path. // ag->corridor.trimInvalidPath(agentRef, agentPos, m_navquery, &m_filter); @@ -1029,7 +1041,7 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug) dtCrowdAgent** agents = m_activeAgents; int nagents = getActiveAgents(agents, m_maxAgents); - + // Check that all agents still have valid paths. checkPathValidity(agents, nagents, dt); @@ -1060,10 +1072,10 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug) // if it has become invalid. const float updateThr = ag->params.collisionQueryRange*0.25f; if (dtVdist2DSqr(ag->npos, ag->boundary.getCenter()) > dtSqr(updateThr) || - !ag->boundary.isValid(m_navquery, &m_filter)) + !ag->boundary.isValid(m_navquery, &m_filters[ag->params.queryFilterType])) { ag->boundary.update(ag->corridor.getFirstPoly(), ag->npos, ag->params.collisionQueryRange, - m_navquery, &m_filter); + m_navquery, &m_filters[ag->params.queryFilterType]); } // Query neighbour agents ag->nneis = getNeighbours(ag->npos, ag->params.height, ag->params.collisionQueryRange, @@ -1085,14 +1097,14 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug) // Find corners for steering ag->ncorners = ag->corridor.findCorners(ag->cornerVerts, ag->cornerFlags, ag->cornerPolys, - DT_CROWDAGENT_MAX_CORNERS, m_navquery, &m_filter); + DT_CROWDAGENT_MAX_CORNERS, m_navquery, &m_filters[ag->params.queryFilterType]); // Check to see if the corner after the next corner is directly visible, // and short cut to there. if ((ag->params.updateFlags & DT_CROWD_OPTIMIZE_VIS) && ag->ncorners > 0) { const float* target = &ag->cornerVerts[dtMin(1,ag->ncorners-1)*3]; - ag->corridor.optimizePathVisibility(target, ag->params.pathOptimizationRange, m_navquery, &m_filter); + ag->corridor.optimizePathVisibility(target, ag->params.pathOptimizationRange, m_navquery, &m_filters[ag->params.queryFilterType]); // Copy data for debug purposes. if (debugIdx == i) @@ -1372,7 +1384,7 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug) continue; // Move along navmesh. - ag->corridor.movePosition(ag->npos, m_navquery, &m_filter); + ag->corridor.movePosition(ag->npos, m_navquery, &m_filters[ag->params.queryFilterType]); // Get valid constrained position back. dtVcopy(ag->npos, ag->corridor.getPos()); @@ -1422,5 +1434,3 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug) } } - -