Browse Source

Added batch files to start the navigation example.
Added recursive flag to Navigable to optionally disable recursive collection of geometries.
Check that Navigable is enabled before collecting navigation geometry.

Lasse Öörni 12 years ago
parent
commit
be3b304836

+ 9 - 9
Bin/Data/Scripts/Navigation.as

@@ -11,7 +11,6 @@ NavigationMesh@ navMesh;
 Vector3 startPos;
 Vector3 endPos;
 
-bool setStartPos = true;
 bool startPosSet = false;
 bool endPosSet = false;
 
@@ -44,6 +43,7 @@ void InitConsole()
     engine.CreateDebugHud();
     debugHud.style = uiStyle;
     debugHud.mode = DEBUGHUD_SHOW_ALL;
+    debugHud.SetAppStats("Instructions:", "Shift+LMB to set startpoint, LMB to set endpoint");
 
     engine.CreateConsole();
     console.style = uiStyle;
@@ -290,13 +290,13 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
 
         if (key == KEY_F5)
         {
-            File@ xmlFile = File(fileSystem.programDir + "Data/Scenes/TestScene.xml", FILE_WRITE);
+            File@ xmlFile = File(fileSystem.programDir + "Data/Scenes/Navigation.xml", FILE_WRITE);
             testScene.SaveXML(xmlFile);
         }
 
         if (key == KEY_F7)
         {
-            File@ xmlFile = File(fileSystem.programDir + "Data/Scenes/TestScene.xml", FILE_READ);
+            File@ xmlFile = File(fileSystem.programDir + "Data/Scenes/Navigation.xml", FILE_READ);
             if (xmlFile.open)
                 testScene.LoadXML(xmlFile);
         }
@@ -328,10 +328,11 @@ void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
 
     if (button == MOUSEB_LEFT && ui.GetElementAt(ui.cursorPosition, true) is null && ui.focusElement is null)
     {
+        bool setStartPos = input.qualifierDown[QUAL_SHIFT];
         IntVector2 pos = ui.cursorPosition;
         Ray cameraRay = camera.GetScreenRay(float(pos.x) / graphics.width, float(pos.y) / graphics.height);
-        RayQueryResult result = testScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, 250.0, DRAWABLE_GEOMETRY);
-    
+        RayQueryResult result = testScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, 1000.0, DRAWABLE_GEOMETRY);
+
         if (result.drawable !is null)
         {
             Vector3 rayHitPos = cameraRay.origin + cameraRay.direction * result.distance;
@@ -345,8 +346,7 @@ void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
                 endPos = rayHitPos;
                 endPosSet = true;
             }
-            setStartPos = !setStartPos;
-            
+
             if (startPosSet && endPosSet)
                 path = navMesh.FindPath(startPos, endPos);
         }
@@ -370,13 +370,13 @@ void HandlePostRenderUpdate()
     if (drawDebug == 2)
         testScene.physicsWorld.DrawDebugGeometry(true);
     if (drawDebug == 3)
-        navMesh.DrawDebugGeometry(testScene.debugRenderer, false);
+        navMesh.DrawDebugGeometry(testScene.debugRenderer, true);
 
     IntVector2 pos = ui.cursorPosition;
     if (ui.GetElementAt(pos, true) is null && testScene.octree !is null)
     {
         Ray cameraRay = camera.GetScreenRay(float(pos.x) / graphics.width, float(pos.y) / graphics.height);
-        RayQueryResult result = testScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, 250.0, DRAWABLE_GEOMETRY);
+        RayQueryResult result = testScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, 1000.0, DRAWABLE_GEOMETRY);
         if (result.drawable !is null)
         {
             Vector3 rayHitPos = cameraRay.origin + cameraRay.direction * result.distance;

+ 1 - 0
Bin/Navigation.bat

@@ -0,0 +1 @@
+Urho3D.exe Scripts/Navigation.as %1 %2 %3 %4 %5 %6 %7 %8

+ 1 - 0
Bin/Navigation.sh

@@ -0,0 +1 @@
+./Urho3D Scripts/Navigation.as $@

+ 10 - 1
Docs/GettingStarted.dox

@@ -93,7 +93,7 @@ The scripting language used is AngelScript (http://www.angelcode.com/angelscript
 
 On Android and iOS there are no command line options, so running the NinjaSnowWar example is hardcoded. This can be changed from the file Urho3D/Urho3D.cpp.
 
-Currently nine example application scripts exist:
+Currently ten example application scripts exist:
 
 \section Running_NinjaSnowWar NinjaSnowWar
 
@@ -153,6 +153,15 @@ For details on how to use the editor, see \ref EditorInstructions "Editor instru
 L           Toggle buoyant liquid volume
 \endverbatim
 
+\section Running_Navigation Navigation
+
+A test of navigation mesh generation and path queries. Generates the same static scene as TestScene. To start, run Navigation.bat in the Bin directory, or use the command Urho3D.exe Scripts\Navigation.as. Controls are like in TestScene, except:
+
+\verbatim
+Left mouse  Set path query end point
+Shift+LMB   Set path query start point
+\endverbatim
+
 \section Running_Physics Physics
 
 A stress test of 1000 moving physics objects, which also showcases the performance difference instancing can make. Run with Physics.bat, or use the command Urho3D.exe Scripts/Physics.as. %Controls as in TestScene.

+ 1 - 0
Docs/ScriptAPI.dox

@@ -5376,6 +5376,7 @@ Properties:<br>
 - bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
+- bool recursive
 
 
 NavigationMesh

+ 2 - 0
Engine/Engine/NavigationAPI.cpp

@@ -31,6 +31,8 @@ namespace Urho3D
 void RegisterNavigable(asIScriptEngine* engine)
 {
     RegisterComponent<Navigable>(engine, "Navigable");
+    engine->RegisterObjectMethod("Navigable", "void set_recursive(bool)", asMETHOD(Navigable, SetRecursive), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Navigable", "bool get_recursive() const", asMETHOD(Navigable, IsRecursive), asCALL_THISCALL);
 }
 
 static CScriptArray* NavigationMeshFindPath(const Vector3& start, const Vector3& end, const Vector3& extents, NavigationMesh* ptr)

+ 9 - 1
Engine/Navigation/Navigable.cpp

@@ -32,7 +32,8 @@ namespace Urho3D
 OBJECTTYPESTATIC(Navigable);
 
 Navigable::Navigable(Context* context) :
-    Component(context)
+    Component(context),
+    recursive_(true)
 {
 }
 
@@ -43,6 +44,13 @@ Navigable::~Navigable()
 void Navigable::RegisterObject(Context* context)
 {
     context->RegisterFactory<Navigable>();
+    
+    ATTRIBUTE(Navigable, VAR_BOOL, "Recursive", recursive_, true, AM_DEFAULT);
+}
+
+void Navigable::SetRecursive(bool enable)
+{
+    recursive_ = enable;
 }
 
 }

+ 10 - 1
Engine/Navigation/Navigable.h

@@ -27,7 +27,7 @@
 namespace Urho3D
 {
 
-/// Navigable geometry properties component. Any geometry components from its node and child nodes will be included in the navigation mesh.
+/// Navigable component, tags geometry for inclusion in the navigation mesh. Optionally auto-includes geometry also from child nodes.
 class Navigable : public Component
 {
     OBJECT(Navigable);
@@ -39,6 +39,15 @@ public:
     virtual ~Navigable();
     /// Register object factory.
     static void RegisterObject(Context* context);
+    
+    /// Set whether geometry is automatically collected from child nodes. Default true.
+    void SetRecursive(bool enable);
+    /// Return whether geometry is automatically collected from child nodes.
+    bool IsRecursive() const { return recursive_; }
+    
+private:
+    /// Recursive flag.
+    bool recursive_;
 };
 
 }

+ 21 - 13
Engine/Navigation/NavigationMesh.cpp

@@ -263,8 +263,12 @@ bool NavigationMesh::Build()
         PODVector<Navigable*> navigables;
         node_->GetComponents<Navigable>(navigables, true);
         
+        HashSet<Node*> processedNodes;
         for (unsigned i = 0; i < navigables.Size(); ++i)
-            CollectGeometries(build, navigables[i]->GetNode(), navigables[i]->GetNode());
+        {
+            if (navigables[i]->IsEnabledEffective())
+                CollectGeometries(build, navigables[i]->GetNode(), processedNodes, navigables[i]->IsRecursive());
+        }
         
         LOGDEBUG("Navigation mesh has " + String(build.vertices_.Size()) + " vertices and " + String(build.indices_.Size()) +
             " indices");
@@ -388,12 +392,12 @@ bool NavigationMesh::Build()
         }
         
         // Set polygon flags.
-        /// \todo Allow to define custom flags
-        for (int i = 0; i < build.polyMesh_->npolys; ++i)
-        {
-            if (build.polyMesh_->areas[i] == RC_WALKABLE_AREA)
-                build.polyMesh_->flags[i] = 0x1;
-        }
+        /// \todo Allow to define custom flags
+        for (int i = 0; i < build.polyMesh_->npolys; ++i)
+        {
+            if (build.polyMesh_->areas[i] == RC_WALKABLE_AREA)
+                build.polyMesh_->flags[i] = 0x1;
+        }
         
         unsigned char* navData = 0;
         int navDataSize = 0;
@@ -488,11 +492,12 @@ void NavigationMesh::SetNavigationDataAttr(const PODVector<unsigned char>& data)
     CreateNavMesh(navData, data.Size());
 }
 
-void NavigationMesh::CollectGeometries(NavigationBuildData& build, Node* node, Node* baseNode)
+void NavigationMesh::CollectGeometries(NavigationBuildData& build, Node* node, HashSet<Node*>& processedNodes, bool recursive)
 {
-    // If find a navigable from a child node that's not the current base node, abort so we're not going to add the geometry twice
-    if (node != baseNode && node->HasComponent<Navigable>())
+    // Make sure nodes are not included twice
+    if (processedNodes.Contains(node))
         return;
+    processedNodes.Insert(node);
     
     /// \todo Prefer physics geometry if available
     PODVector<Drawable*> drawables;
@@ -517,9 +522,12 @@ void NavigationMesh::CollectGeometries(NavigationBuildData& build, Node* node, N
             AddGeometry(build, node, drawable->GetLodGeometry(j, lodLevel));
     }
     
-    const Vector<SharedPtr<Node> >& children = node->GetChildren();
-    for(unsigned i = 0; i < children.Size(); ++i)
-        CollectGeometries(build, children[i], baseNode);
+    if (recursive)
+    {
+        const Vector<SharedPtr<Node> >& children = node->GetChildren();
+        for(unsigned i = 0; i < children.Size(); ++i)
+            CollectGeometries(build, children[i], processedNodes, recursive);
+    }
 }
 
 void NavigationMesh::AddGeometry(NavigationBuildData& build, Node* node, Geometry* geometry)

+ 1 - 1
Engine/Navigation/NavigationMesh.h

@@ -116,7 +116,7 @@ public:
     
 private:
     /// Visit nodes and collect navigable geometry.
-    void CollectGeometries(NavigationBuildData& build, Node* node, Node* baseNode);
+    void CollectGeometries(NavigationBuildData& build, Node* node, HashSet<Node*>& processedNodes, bool recursive);
     /// Add a geometry to the mesh.
     void AddGeometry(NavigationBuildData& build, Node* node, Geometry* geometry);
     /// Create Detour navmesh. Return true if successful.