Kaynağa Gözat

Fixes for moving a node from one scene to another. Related CollisionShape & Constraint fixes.

Lasse Öörni 10 yıl önce
ebeveyn
işleme
7bff2a4734

+ 17 - 1
Source/Urho3D/Physics/CollisionShape.cpp

@@ -415,7 +415,8 @@ CollisionShape::CollisionShape(Context* context) :
     lodLevel_(0),
     customGeometryID_(0),
     margin_(DEFAULT_COLLISION_MARGIN),
-    recreateShape_(true)
+    recreateShape_(true),
+    retryCreation_(false)
 {
 }
 
@@ -931,6 +932,13 @@ void CollisionShape::OnSceneSet(Scene* scene)
 
         physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
         physicsWorld_->AddCollisionShape(this);
+
+        // Create shape now if necessary (attributes modified before adding to scene)
+        if (retryCreation_)
+        {
+            UpdateShape();
+            NotifyRigidBody();
+        }
     }
     else
     {
@@ -938,6 +946,9 @@ void CollisionShape::OnSceneSet(Scene* scene)
 
         if (physicsWorld_)
             physicsWorld_->RemoveCollisionShape(this);
+
+        // Recreate when moved to a scene again
+        retryCreation_ = true;
     }
 }
 
@@ -1001,8 +1012,12 @@ void CollisionShape::UpdateShape()
 
     ReleaseShape();
 
+    // If no physics world available now mark for retry later
     if (!physicsWorld_)
+    {
+        retryCreation_ = true;
         return;
+    }
 
     if (node_)
     {
@@ -1151,6 +1166,7 @@ void CollisionShape::UpdateShape()
         physicsWorld_->CleanupGeometryCache();
 
     recreateShape_ = false;
+    retryCreation_ = false;
 }
 
 void CollisionShape::HandleTerrainCreated(StringHash eventType, VariantMap& eventData)

+ 2 - 0
Source/Urho3D/Physics/CollisionShape.h

@@ -264,6 +264,8 @@ private:
     float margin_;
     /// Recrease collision shape flag.
     bool recreateShape_;
+    /// Shape creation retry flag if attributes initially set without scene.
+    bool retryCreation_;
 };
 
 }

+ 14 - 1
Source/Urho3D/Physics/Constraint.cpp

@@ -65,7 +65,8 @@ Constraint::Constraint(Context* context) :
     otherBodyNodeID_(0),
     disableCollision_(false),
     recreateConstraint_(true),
-    framesDirty_(false)
+    framesDirty_(false),
+    retryCreation_(false)
 {
 }
 
@@ -455,6 +456,10 @@ void Constraint::OnSceneSet(Scene* scene)
 
         physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
         physicsWorld_->AddConstraint(this);
+
+        // Create constraint now if necessary (attributes modified before adding to scene)
+        if (retryCreation_)
+            CreateConstraint();
     }
     else
     {
@@ -462,6 +467,9 @@ void Constraint::OnSceneSet(Scene* scene)
 
         if (physicsWorld_)
             physicsWorld_->RemoveConstraint(this);
+
+        // Recreate when moved to a scene again
+        retryCreation_ = true;
     }
 }
 
@@ -484,8 +492,12 @@ void Constraint::CreateConstraint()
     btRigidBody* ownBody = ownBody_ ? ownBody_->GetBody() : 0;
     btRigidBody* otherBody = otherBody_ ? otherBody_->GetBody() : 0;
 
+    // If no physics world available now mark for retry later
     if (!physicsWorld_ || !ownBody)
+    {
+        retryCreation_ = true;
         return;
+    }
 
     if (!otherBody)
         otherBody = &btTypedConstraint::getFixedBody();
@@ -546,6 +558,7 @@ void Constraint::CreateConstraint()
 
     recreateConstraint_ = false;
     framesDirty_ = false;
+    retryCreation_ = false;
 }
 
 void Constraint::ApplyLimits()

+ 2 - 0
Source/Urho3D/Physics/Constraint.h

@@ -183,6 +183,8 @@ private:
     bool recreateConstraint_;
     /// Coordinate frames dirty flag.
     bool framesDirty_;
+    /// Constraint creation retry flag if attributes initially set without scene.
+    bool retryCreation_;
 };
 
 }

+ 1 - 1
Source/Urho3D/Scene/Node.h

@@ -421,7 +421,7 @@ public:
     void SetID(unsigned id);
     /// Set scene. Called by Scene.
     void SetScene(Scene* scene);
-    /// Reset scene. Called by Scene.
+    /// Reset scene, ID and owner. Called by Scene.
     void ResetScene();
     /// Set network position attribute.
     void SetNetPositionAttr(const Vector3& value);

+ 23 - 12
Source/Urho3D/Scene/Scene.cpp

@@ -744,14 +744,10 @@ void Scene::NodeAdded(Node* node)
     if (!node || node->GetScene() == this)
         return;
 
-    // If node already exists in another scene, remove. This is unsupported, as components will not reinitialize themselves
-    // to use the new scene
+    // Remove from old scene first
     Scene* oldScene = node->GetScene();
     if (oldScene)
-    {
-        LOGERROR("Moving a node from one scene to another is unsupported");
         oldScene->NodeRemoved(node);
-    }
 
     node->SetScene(this);
 
@@ -770,7 +766,7 @@ void Scene::NodeAdded(Node* node)
         if (i != replicatedNodes_.End() && i->second_ != node)
         {
             LOGWARNING("Overwriting node with ID " + String(id));
-            i->second_->ResetScene();
+            NodeRemoved(i->second_);
         }
 
         replicatedNodes_[id] = node;
@@ -784,11 +780,18 @@ void Scene::NodeAdded(Node* node)
         if (i != localNodes_.End() && i->second_ != node)
         {
             LOGWARNING("Overwriting node with ID " + String(id));
-            i->second_->ResetScene();
+            NodeRemoved(i->second_);
         }
-
         localNodes_[id] = node;
     }
+
+    // Add already created components and child nodes now
+    const Vector<SharedPtr<Component> >& components = node->GetComponents();
+    for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
+        ComponentAdded(*i);
+    const Vector<SharedPtr<Node> >& children = node->GetChildren();
+    for (Vector<SharedPtr<Node> >::ConstIterator i = children.Begin(); i != children.End(); ++i)
+        NodeAdded(*i);
 }
 
 void Scene::NodeRemoved(Node* node)
@@ -805,8 +808,8 @@ void Scene::NodeRemoved(Node* node)
     else
         localNodes_.Erase(id);
 
-    node->SetID(0);
-    node->SetScene(0);
+    node->ResetScene();
+
     // Remove components and child nodes as well
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
     for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
@@ -822,13 +825,21 @@ void Scene::ComponentAdded(Component* component)
         return;
 
     unsigned id = component->GetID();
+
+    // If the new component has an ID of zero (default), assign a replicated ID now
+    if (!id)
+    {
+        id = GetFreeComponentID(REPLICATED);
+        component->SetID(id);
+    }
+
     if (id < FIRST_LOCAL_ID)
     {
         HashMap<unsigned, Component*>::Iterator i = replicatedComponents_.Find(id);
         if (i != replicatedComponents_.End() && i->second_ != component)
         {
             LOGWARNING("Overwriting component with ID " + String(id));
-            i->second_->SetID(0);
+            ComponentRemoved(i->second_);
         }
 
         replicatedComponents_[id] = component;
@@ -839,7 +850,7 @@ void Scene::ComponentAdded(Component* component)
         if (i != localComponents_.End() && i->second_ != component)
         {
             LOGWARNING("Overwriting component with ID " + String(id));
-            i->second_->SetID(0);
+            ComponentRemoved(i->second_);
         }
 
         localComponents_[id] = component;