Browse Source

Add navigation mesh id attribute to CrowdManager class.

Yao Wei Tjong 姚伟忠 10 years ago
parent
commit
b7d03abfe1

+ 28 - 28
Source/Urho3D/Navigation/CrowdAgent.cpp

@@ -150,25 +150,6 @@ void CrowdAgent::ApplyAttributes()
     }
 }
 
-void CrowdAgent::OnNodeSet(Node* node)
-{
-    if (node)
-        node->AddListener(this);
-}
-
-void CrowdAgent::OnSceneSet(Scene* scene)
-{
-    if (scene)
-    {
-        if (scene == node_)
-            LOGERROR(GetTypeName() + " should not be created to the root scene node");
-        crowdManager_ = scene->GetOrCreateComponent<DetourCrowdManager>();
-        AddAgentToCrowd();
-    }
-    else
-        RemoveAgentFromCrowd();
-}
-
 void CrowdAgent::OnSetEnabled()
 {
     bool enabled = IsEnabledEffective();
@@ -205,11 +186,6 @@ void CrowdAgent::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
     }
 }
 
-const dtCrowdAgent* CrowdAgent::GetDetourCrowdAgent() const
-{
-    return IsInCrowd() ? crowdManager_->GetCrowdAgent(agentCrowdId_) : 0;
-}
-
 void CrowdAgent::UpdateParameters(unsigned scope)
 {
     const dtCrowdAgent* agent = GetDetourCrowdAgent();
@@ -315,7 +291,7 @@ int CrowdAgent::AddAgentToCrowd(bool force)
             map[P_CROWD_AGENT_STATE] = previousAgentState_;
             map[P_POSITION] = GetPosition();
             map[P_VELOCITY] = GetActualVelocity();
-            SendEvent(E_CROWD_AGENT_FAILURE, map);
+            crowdManager_->SendEvent(E_CROWD_AGENT_FAILURE, map);
 
             // Reevaluate states as handling of event may have resulted in changes
             previousAgentState_ = GetAgentState();
@@ -549,7 +525,7 @@ void CrowdAgent::OnCrowdUpdate(dtCrowdAgent* ag, float dt)
             map[P_VELOCITY] = newVel;
             map[P_ARRIVED] = HasArrived();
             map[P_TIMESTEP] = dt;
-            SendEvent(E_CROWD_AGENT_REPOSITION, map);
+            crowdManager_->SendEvent(E_CROWD_AGENT_REPOSITION, map);
 
             if (updateNodePosition_)
             {
@@ -573,7 +549,7 @@ void CrowdAgent::OnCrowdUpdate(dtCrowdAgent* ag, float dt)
             map[P_CROWD_AGENT_STATE] = newAgentState;
             map[P_POSITION] = newPos;
             map[P_VELOCITY] = newVel;
-            SendEvent(E_CROWD_AGENT_STATE_CHANGED, map);
+            crowdManager_->SendEvent(E_CROWD_AGENT_STATE_CHANGED, map);
 
             // Send a failure event if either state is a failed status
             if (newAgentState == CA_STATE_INVALID || newTargetState == CA_TARGET_FAILED)
@@ -585,7 +561,7 @@ void CrowdAgent::OnCrowdUpdate(dtCrowdAgent* ag, float dt)
                 map[P_CROWD_AGENT_STATE] = newAgentState;
                 map[P_POSITION] = newPos;
                 map[P_VELOCITY] = newVel;
-                SendEvent(E_CROWD_AGENT_FAILURE, map);
+                crowdManager_->SendEvent(E_CROWD_AGENT_FAILURE, map);
             }
 
             // State may have been altered during the handling of the event
@@ -595,6 +571,25 @@ void CrowdAgent::OnCrowdUpdate(dtCrowdAgent* ag, float dt)
     }
 }
 
+void CrowdAgent::OnNodeSet(Node* node)
+{
+    if (node)
+        node->AddListener(this);
+}
+
+void CrowdAgent::OnSceneSet(Scene* scene)
+{
+    if (scene)
+    {
+        if (scene == node_)
+            LOGERROR(GetTypeName() + " should not be created to the root scene node");
+        crowdManager_ = scene->GetOrCreateComponent<DetourCrowdManager>();
+        AddAgentToCrowd();
+    }
+    else
+        RemoveAgentFromCrowd();
+}
+
 void CrowdAgent::OnMarkedDirty(Node* node)
 {
     if (!ignoreTransformChanges_ && IsEnabledEffective())
@@ -611,4 +606,9 @@ void CrowdAgent::OnMarkedDirty(Node* node)
     }
 }
 
+const dtCrowdAgent* CrowdAgent::GetDetourCrowdAgent() const
+{
+    return IsInCrowd() ? crowdManager_->GetCrowdAgent(agentCrowdId_) : 0;
+}
+
 }

+ 1 - 0
Source/Urho3D/Navigation/CrowdAgent.h

@@ -176,6 +176,7 @@ protected:
     virtual void OnMarkedDirty(Node* node);
     /// Get internal Detour crowd agent.
     const dtCrowdAgent* GetDetourCrowdAgent() const;
+
 private:
     /// Update Detour crowd agent parameter.
     void UpdateParameters(unsigned scope = M_MAX_UNSIGNED);

+ 47 - 31
Source/Urho3D/Navigation/CrowdManager.cpp

@@ -59,7 +59,8 @@ CrowdManager::CrowdManager(Context* context) :
     Component(context),
     crowd_(0),
     maxAgents_(DEFAULT_MAX_AGENTS),
-    maxAgentRadius_(DEFAULT_MAX_AGENT_RADIUS)
+    maxAgentRadius_(DEFAULT_MAX_AGENT_RADIUS),
+    navigationMeshId_(0)
 {
 }
 
@@ -75,7 +76,8 @@ void CrowdManager::RegisterObject(Context* context)
 
     ATTRIBUTE("Max Agents", unsigned, maxAgents_, DEFAULT_MAX_AGENTS, AM_DEFAULT);
     ATTRIBUTE("Max Agent Radius", float, maxAgentRadius_, DEFAULT_MAX_AGENT_RADIUS, AM_DEFAULT);
-    //TODO: add attribute for navmesh
+    ATTRIBUTE("Navigation Mesh", unsigned, navigationMeshId_, 0, AM_DEFAULT | AM_COMPONENTID);
+    // TODO: add attributes for crowd filter type and avoidance parameters configuration
 }
 
 void CrowdManager::ApplyAttributes()
@@ -84,8 +86,18 @@ void CrowdManager::ApplyAttributes()
     maxAgents_ = Max(1, maxAgents_);
     maxAgentRadius_ = Max(0.f, maxAgentRadius_);
 
+    Scene* scene = GetScene();
+    if (scene && navigationMeshId_)
+    {
+        NavigationMesh* navMesh = dynamic_cast<NavigationMesh*>(scene->GetComponent(navigationMeshId_));
+        if (navMesh)
+            navigationMesh_ = navMesh;
+    }
+    navigationMeshId_ = navigationMesh_ ? navigationMesh_->GetID() : 0;
+
+    // If the Detour crowd initialization parameters have changed then recreate it
     if (crowd_ && (crowd_->getAgentCount() != maxAgents_ || crowd_->getMaxAgentRadius() != (maxAgentRadius_ > 0.f ? maxAgentRadius_ : navigationMesh_->GetAgentRadius())))
-        CreateCrowd(true);
+        CreateCrowd();
 }
 
 void CrowdManager::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
@@ -158,8 +170,9 @@ void CrowdManager::SetCrowdTarget(const Vector3& position, Node* node)
     Vector3 moveTarget(position);
     for (unsigned i = 0; i < agents.Size(); ++i)
     {
-        CrowdAgent* agent = agents[i];
         // Give application a chance to determine the desired crowd formation when they reach the target position
+        CrowdAgent* agent = agents[i];
+
         using namespace CrowdAgentFormation;
 
         VariantMap& map = GetEventDataMap();
@@ -201,7 +214,7 @@ void CrowdManager::SetMaxAgents(unsigned maxAgents)
     if (maxAgents != maxAgents_ && maxAgents > 0)
     {
         maxAgents_ = maxAgents;
-        CreateCrowd(true);
+        CreateCrowd();
         MarkNetworkUpdate();
     }
 }
@@ -211,7 +224,7 @@ void CrowdManager::SetMaxAgentRadius(float maxAgentRadius)
     if (maxAgentRadius != maxAgentRadius_ && maxAgentRadius > 0.f)
     {
         maxAgentRadius_ = maxAgentRadius;
-        CreateCrowd(true);
+        CreateCrowd();
         MarkNetworkUpdate();
     }
 }
@@ -221,7 +234,8 @@ void CrowdManager::SetNavigationMesh(NavigationMesh* navMesh)
     if (navMesh != navigationMesh_ && navMesh)
     {
         navigationMesh_ = navMesh;
-        CreateCrowd(true);
+        navigationMeshId_ = navMesh->GetID();
+        CreateCrowd();
         MarkNetworkUpdate();
     }
 }
@@ -393,6 +407,32 @@ void CrowdManager::RemoveAgent(CrowdAgent* agent)
     crowd_->removeAgent(agent->GetAgentCrowdId());
 }
 
+void DetourCrowdManager::OnSceneSet(Scene* scene)
+{
+    // Subscribe to the scene subsystem update, which will trigger the crowd update step, and grab a reference
+    // to the scene's NavigationMesh
+    if (scene)
+    {
+        SubscribeToEvent(scene, E_SCENESUBSYSTEMUPDATE, HANDLER(CrowdManager, HandleSceneSubsystemUpdate));
+        NavigationMesh* mesh = GetScene()->GetDerivedComponent<NavigationMesh>();
+        if (mesh)
+        {
+            SubscribeToEvent(mesh, E_NAVIGATION_MESH_REBUILT, HANDLER(CrowdManager, HandleNavMeshFullRebuild));
+            navigationMesh_ = navMesh;
+            navigationMeshId_ = navMesh->GetID();
+            CreateCrowd(false);
+        }
+        else
+            LOGERROR("CrowdManager requires an existing navigation mesh");
+    }
+    else
+    {
+        UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
+        UnsubscribeFromEvent(E_NAVIGATION_MESH_REBUILT);
+        navigationMesh_.Reset();
+    }
+}
+
 void CrowdManager::Update(float delta)
 {
     if (!crowd_ || !navigationMesh_)
@@ -422,28 +462,4 @@ void CrowdManager::HandleNavMeshFullRebuild(StringHash eventType, VariantMap& ev
     SetNavigationMesh(static_cast<NavigationMesh*>(eventData[P_MESH].GetPtr()));
 }
 
-void DetourCrowdManager::OnSceneSet(Scene* scene)
-{
-    // Subscribe to the scene subsystem update, which will trigger the crowd update step, and grab a reference
-    // to the scene's NavigationMesh
-    if (scene)
-    {
-        SubscribeToEvent(scene, E_SCENESUBSYSTEMUPDATE, HANDLER(CrowdManager, HandleSceneSubsystemUpdate));
-        NavigationMesh* mesh = GetScene()->GetDerivedComponent<NavigationMesh>();
-        if (mesh)
-        {
-            SubscribeToEvent(mesh, E_NAVIGATION_MESH_REBUILT, HANDLER(CrowdManager, HandleNavMeshFullRebuild));
-            SetNavigationMesh(mesh);
-        }
-        else
-            LOGERROR("CrowdManager requires an existing navigation mesh");
-    }
-    else
-    {
-        UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
-        UnsubscribeFromEvent(E_NAVIGATION_MESH_REBUILT);
-        navigationMesh_.Reset();
-    }
-}
-
 }

+ 9 - 6
Source/Urho3D/Navigation/CrowdManager.h

@@ -43,6 +43,7 @@ class NavigationMesh;
 class URHO3D_API CrowdManager : public Component
 {
     OBJECT(CrowdManager);
+
     friend class CrowdAgent;
 
 public:
@@ -60,11 +61,11 @@ public:
     /// Add debug geometry to the debug renderer.
     void DrawDebugGeometry(bool depthTest);
 
-    /// Set the crowd target position. The target position is set to all crowd agents found in the specified node, excluding crowd agent which does not have acceleration. Defaulted to scene node.
+    /// Set the crowd target position. The target position is set to all crowd agents found in the specified node. Defaulted to scene node.
     void SetCrowdTarget(const Vector3& position, Node* node = 0);
-    /// Set the crowd move velocity. The move velocity is applied to all crowd agents found in the specified node, excluding crowd agent which does not have acceleration. Defaulted to scene node.
+    /// Set the crowd move velocity. The move velocity is applied to all crowd agents found in the specified node. Defaulted to scene node.
     void SetCrowdVelocity(const Vector3& velocity, Node* node = 0);
-    /// Reset any crowd target for all crowd agents found in the specified node, excluding crowd agent which does not have acceleration. Defaulted to scene node.
+    /// Reset any crowd target for all crowd agents found in the specified node. Defaulted to scene node.
     void ResetCrowdTarget(Node* node = 0);
     /// Set the maximum number of agents.
     void SetMaxAgents(unsigned maxAgents);
@@ -102,17 +103,17 @@ public:
 
 protected:
     /// Create internal Detour crowd object for the specified navigation mesh. If readdCrowdAgents is true then attempt to re-add existing agents in the previous crowd back to the newly created crowd.
-    bool CreateCrowd(bool readdCrowdAgents = false);
+    bool CreateCrowd(bool readdCrowdAgents = true);
     /// Create and adds an detour crowd agent, Agent's radius and height is set through the navigation mesh. Return -1 on error, agent ID on success.
     int AddAgent(CrowdAgent* agent, const Vector3& pos);
     /// Removes the detour crowd agent.
     void RemoveAgent(CrowdAgent* agent);
 
 protected:
-    /// Update the crowd simulation.
-    void Update(float delta);
     /// Handle scene being assigned.
     virtual void OnSceneSet(Scene* scene);
+    /// Update the crowd simulation.
+    void Update(float delta);
     /// Get the detour crowd agent.
     const dtCrowdAgent* GetCrowdAgent(int agent);
     /// Get the internal detour crowd component.
@@ -132,6 +133,8 @@ private:
     unsigned maxAgents_;
     /// The maximum radius of any agent that will be added to the crowd.
     float maxAgentRadius_;
+    /// The NavigationMesh component Id for pending crowd creation.
+    unsigned navigationMeshId_;
 };
 
 }