Browse Source

added node tags

svifylabs 10 years ago
parent
commit
41f5ff1a51

+ 13 - 1
Source/Urho3D/AngelScript/APITemplates.h

@@ -581,6 +581,13 @@ static CScriptArray* NodeGetChildrenWithComponent(const String& typeName, bool r
     return VectorToHandleArray<Node>(nodes, "Array<Node@>");
     return VectorToHandleArray<Node>(nodes, "Array<Node@>");
 }
 }
 
 
+static CScriptArray* NodeGetChildrenWithTag(const StringHash& typeName, bool recursive, Node* ptr)
+{
+	PODVector<Node*> nodes;
+	ptr->GetChildrenWithTag(nodes, typeName, recursive);
+	return VectorToHandleArray<Node>(nodes, "Array<Node@>");
+}
+
 static unsigned NodeGetNumChildrenNonRecursive(Node* ptr)
 static unsigned NodeGetNumChildrenNonRecursive(Node* ptr)
 {
 {
     return ptr->GetNumChildren(false);
     return ptr->GetNumChildren(false);
@@ -691,7 +698,8 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void RemoveAllComponents()", asMETHOD(T, RemoveAllComponents), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveAllComponents()", asMETHOD(T, RemoveAllComponents), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildren(bool recursive = false) const", asFUNCTION(NodeGetChildren), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildren(bool recursive = false) const", asFUNCTION(NodeGetChildren), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithComponent(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithComponent), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithComponent(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithComponent), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(bool recursive = false) const", asFUNCTION(NodeGetChildrenWithScript), asCALL_CDECL_OBJLAST);
+	engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithTag(const StringHash&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithTag), asCALL_CDECL_OBJLAST);
+	engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(bool recursive = false) const", asFUNCTION(NodeGetChildrenWithScript), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithClassName), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithClassName), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Node@+ GetChild(const String&in, bool recursive = false) const", asMETHODPR(T, GetChild, (const String&, bool) const, Node*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ GetChild(const String&in, bool recursive = false) const", asMETHODPR(T, GetChild, (const String&, bool) const, Node*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Array<Component@>@ GetComponents() const", asFUNCTION(NodeGetComponents), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Component@>@ GetComponents() const", asFUNCTION(NodeGetComponents), asCALL_CDECL_OBJLAST);
@@ -750,6 +758,10 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void set_parent(Node@+)", asMETHOD(T, SetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void set_parent(Node@+)", asMETHOD(T, SetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ get_parent() const", asMETHOD(T, GetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ get_parent() const", asMETHOD(T, GetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "VariantMap& get_vars()", asFUNCTION(NodeGetVars), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "VariantMap& get_vars()", asFUNCTION(NodeGetVars), asCALL_CDECL_OBJLAST);
+	engine->RegisterObjectMethod(className, "bool HasTag(const StringHash&in)", asMETHOD(T, HasTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod(className, "StringHash get_tag()", asMETHOD(T, GetTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod(className, "void set_tag(const StringHash&in)", asMETHOD(T, SetTag), asCALL_THISCALL);
+
 }
 }
 
 
 static bool ResourceLoad(File* file, XMLFile* ptr)
 static bool ResourceLoad(File* file, XMLFile* ptr)

+ 17 - 3
Source/Urho3D/AngelScript/SceneAPI.cpp

@@ -165,6 +165,13 @@ static bool SceneLoadXMLVectorBuffer(VectorBuffer& buffer, Scene* ptr)
     return ptr->LoadXML(buffer);
     return ptr->LoadXML(buffer);
 }
 }
 
 
+static CScriptArray* SceneGetNodesWithTag(const StringHash& typeName, Scene* ptr)
+{
+	PODVector<Node*> nodes;
+	ptr->GetNodesWithTag(nodes, typeName);
+	return VectorToHandleArray<Node>(nodes, "Array<Node@>");
+}
+
 static bool SceneLoadJSONVectorBuffer(VectorBuffer& buffer, Scene* ptr)
 static bool SceneLoadJSONVectorBuffer(VectorBuffer& buffer, Scene* ptr)
 {
 {
     return ptr->LoadJSON(buffer);
     return ptr->LoadJSON(buffer);
@@ -349,13 +356,20 @@ static void RegisterScene(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Scene", "void Clear(bool clearReplicated = true, bool clearLocal = true)", asMETHOD(Scene, Clear), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void Clear(bool clearReplicated = true, bool clearLocal = true)", asMETHOD(Scene, Clear), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void AddRequiredPackageFile(PackageFile@+)", asMETHOD(Scene, AddRequiredPackageFile), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void AddRequiredPackageFile(PackageFile@+)", asMETHOD(Scene, AddRequiredPackageFile), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void ClearRequiredPackageFiles()", asMETHOD(Scene, ClearRequiredPackageFiles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void ClearRequiredPackageFiles()", asMETHOD(Scene, ClearRequiredPackageFiles), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Scene", "void RegisterVar(const String&in)", asMETHOD(Scene, RegisterVar), asCALL_THISCALL);
+ 
+	engine->RegisterObjectMethod("Scene", "void RegisterVar(const String&in)", asMETHOD(Scene, RegisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterVar(const String&in)", asMETHOD(Scene, UnregisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterVar(const String&in)", asMETHOD(Scene, UnregisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterAllVars(const String&in)", asMETHOD(Scene, UnregisterAllVars), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterAllVars(const String&in)", asMETHOD(Scene, UnregisterAllVars), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Scene", "Component@+ GetComponent(uint) const", asMETHODPR(Scene, GetComponent, (unsigned) const, Component*), asCALL_THISCALL);
+	
+	engine->RegisterObjectMethod("Scene", "void RegisterTag(const String&in)", asMETHOD(Scene, RegisterTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod("Scene", "void UnregisterTag(const String&in)", asMETHOD(Scene, UnregisterTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod("Scene", "void UnregisterAllTags(const String&in)", asMETHOD(Scene, UnregisterAllTags), asCALL_THISCALL);
+
+	engine->RegisterObjectMethod("Scene", "Component@+ GetComponent(uint) const", asMETHODPR(Scene, GetComponent, (unsigned) const, Component*), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "Node@+ GetNode(uint) const", asMETHOD(Scene, GetNode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "Node@+ GetNode(uint) const", asMETHOD(Scene, GetNode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "const String& GetVarName(StringHash) const", asMETHOD(Scene, GetVarName), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "const String& GetVarName(StringHash) const", asMETHOD(Scene, GetVarName), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Scene", "void Update(float)", asMETHOD(Scene, Update), asCALL_THISCALL);
+	engine->RegisterObjectMethod("Scene", "const String& GetTagName(StringHash) const", asMETHOD(Scene, GetTagName), asCALL_THISCALL);
+	engine->RegisterObjectMethod("Scene", "void Update(float)", asMETHOD(Scene, Update), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_updateEnabled(bool)", asMETHOD(Scene, SetUpdateEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_updateEnabled(bool)", asMETHOD(Scene, SetUpdateEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "bool get_updateEnabled() const", asMETHOD(Scene, IsUpdateEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "bool get_updateEnabled() const", asMETHOD(Scene, IsUpdateEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_timeScale(float)", asMETHOD(Scene, SetTimeScale), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_timeScale(float)", asMETHOD(Scene, SetTimeScale), asCALL_THISCALL);

+ 67 - 1
Source/Urho3D/Scene/Node.cpp

@@ -79,7 +79,8 @@ void Node::RegisterObject(Context* context)
 
 
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Name", GetName, SetName, String, String::EMPTY, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Name", GetName, SetName, String, String::EMPTY, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE);
+	URHO3D_ACCESSOR_ATTRIBUTE("Tag", GetTag, SetTag, StringHash, StringHash::ZERO, AM_DEFAULT);
+	URHO3D_ACCESSOR_ATTRIBUTE("Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE);
     URHO3D_ACCESSOR_ATTRIBUTE("Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
     URHO3D_ACCESSOR_ATTRIBUTE("Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
     URHO3D_ACCESSOR_ATTRIBUTE("Scale", GetScale, SetScale, Vector3, Vector3::ONE, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Scale", GetScale, SetScale, Vector3, Vector3::ONE, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Variables", VariantMap, vars_, Variant::emptyVariantMap, AM_FILE); // Network replication of vars uses custom data
     URHO3D_ATTRIBUTE("Variables", VariantMap, vars_, Variant::emptyVariantMap, AM_FILE); // Network replication of vars uses custom data
@@ -340,6 +341,33 @@ void Node::SetName(const String& name)
     }
     }
 }
 }
 
 
+void Node::SetTag(const StringHash& tag)
+{
+	if (tag_ != tag)
+	{
+		StringHash oldTag = tag_;
+		tag_ = tag;
+
+
+		MarkNetworkUpdate();
+
+		// Send change event
+		if (scene_)
+		{
+			scene_->NodeTagChanged(this, oldTag);
+
+			using namespace NodeTagChanged;
+
+			VariantMap& eventData = GetEventDataMap();
+			eventData[P_SCENE] = scene_;
+			eventData[P_NODE] = this;
+			eventData[P_TAG] = tag_;
+			eventData[P_OLDTAG] = oldTag;
+			scene_->SendEvent(E_NODETAGCHANGED, eventData);
+		}
+	}
+}
+
 void Node::SetPosition(const Vector3& position)
 void Node::SetPosition(const Vector3& position)
 {
 {
     position_ = position;
     position_ = position;
@@ -1112,6 +1140,22 @@ void Node::GetChildrenWithComponent(PODVector<Node*>& dest, StringHash type, boo
         GetChildrenWithComponentRecursive(dest, type);
         GetChildrenWithComponentRecursive(dest, type);
 }
 }
 
 
+void Node::GetChildrenWithTag(PODVector<Node*>& dest, StringHash tag, bool recursive /*= true*/) const
+{
+	dest.Clear();
+
+	if (!recursive)
+	{
+		for (Vector<SharedPtr<Node> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
+		{
+			if ((*i)->HasTag(tag))
+				dest.Push(*i);
+		}
+	}
+	else
+		GetChildrenWithTagRecursive(dest, tag);
+}
+
 Node* Node::GetChild(unsigned index) const
 Node* Node::GetChild(unsigned index) const
 {
 {
     return index < children_.Size() ? children_[index].Get() : 0;
     return index < children_.Size() ? children_[index].Get() : 0;
@@ -1183,6 +1227,16 @@ bool Node::HasComponent(StringHash type) const
     return false;
     return false;
 }
 }
 
 
+bool Node::HasTag(StringHash tag) const
+{
+	return tag_ == tag;
+}
+
+const StringHash& Node::GetTag() const
+{
+	return tag_;
+}
+
 const Variant& Node::GetVar(StringHash key) const
 const Variant& Node::GetVar(StringHash key) const
 {
 {
     VariantMap::ConstIterator i = vars_.Find(key);
     VariantMap::ConstIterator i = vars_.Find(key);
@@ -1953,6 +2007,18 @@ void Node::GetComponentsRecursive(PODVector<Component*>& dest, StringHash type)
         (*i)->GetComponentsRecursive(dest, type);
         (*i)->GetComponentsRecursive(dest, type);
 }
 }
 
 
+void Node::GetChildrenWithTagRecursive(PODVector<Node*>& dest, StringHash tag) const
+{
+	for (Vector<SharedPtr<Node> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
+	{
+		Node* node = *i;
+		if (node->HasTag(tag))
+			dest.Push(node);
+		if (!node->children_.Empty())
+			node->GetChildrenWithTagRecursive(dest, tag);
+	}
+}
+
 Node* Node::CloneRecursive(Node* parent, SceneResolver& resolver, CreateMode mode)
 Node* Node::CloneRecursive(Node* parent, SceneResolver& resolver, CreateMode mode)
 {
 {
     // Create clone node
     // Create clone node

+ 17 - 4
Source/Urho3D/Scene/Node.h

@@ -95,7 +95,9 @@ public:
     bool SaveJSON(Serializer& dest, const String& indentation = "\t") const;
     bool SaveJSON(Serializer& dest, const String& indentation = "\t") const;
     /// Set name of the scene node. Names are not required to be unique.
     /// Set name of the scene node. Names are not required to be unique.
     void SetName(const String& name);
     void SetName(const String& name);
-    /// Set position in parent space. If the scene node is on the root level (is child of the scene itself), this is same as world space.
+	/// Set tag for the scene node. 
+	void SetTag(const StringHash& tag);
+	/// Set position in parent space. If the scene node is on the root level (is child of the scene itself), this is same as world space.
     void SetPosition(const Vector3& position);
     void SetPosition(const Vector3& position);
 
 
     /// Set position in parent space (for Urho2D).
     /// Set position in parent space (for Urho2D).
@@ -305,6 +307,9 @@ public:
     /// Return name hash.
     /// Return name hash.
     StringHash GetNameHash() const { return nameHash_; }
     StringHash GetNameHash() const { return nameHash_; }
 
 
+	/// Return the tag.
+	const StringHash& GetTag() const;
+
     /// Return parent scene node.
     /// Return parent scene node.
     Node* GetParent() const { return parent_; }
     Node* GetParent() const { return parent_; }
 
 
@@ -459,7 +464,10 @@ public:
     void GetChildren(PODVector<Node*>& dest, bool recursive = false) const;
     void GetChildren(PODVector<Node*>& dest, bool recursive = false) const;
     /// Return child scene nodes with a specific component.
     /// Return child scene nodes with a specific component.
     void GetChildrenWithComponent(PODVector<Node*>& dest, StringHash type, bool recursive = false) const;
     void GetChildrenWithComponent(PODVector<Node*>& dest, StringHash type, bool recursive = false) const;
-    /// Return child scene node by index.
+	/// Return child scene nodes with a specific tag.
+	void GetChildrenWithTag(PODVector<Node*>& dest, StringHash tag, bool recursive = false) const;
+
+	/// Return child scene node by index.
     Node* GetChild(unsigned index) const;
     Node* GetChild(unsigned index) const;
     /// Return child scene node by name.
     /// Return child scene node by name.
     Node* GetChild(const String& name, bool recursive = false) const;
     Node* GetChild(const String& name, bool recursive = false) const;
@@ -485,7 +493,8 @@ public:
     Component* GetParentComponent(StringHash type, bool fullTraversal = false) const;
     Component* GetParentComponent(StringHash type, bool fullTraversal = false) const;
     /// Return whether has a specific component.
     /// Return whether has a specific component.
     bool HasComponent(StringHash type) const;
     bool HasComponent(StringHash type) const;
-
+	/// Return whether has a specific tag.
+	bool HasTag(StringHash tag) const;
     /// Return listener components.
     /// Return listener components.
     const Vector<WeakPtr<Component> > GetListeners() const { return listeners_; }
     const Vector<WeakPtr<Component> > GetListeners() const { return listeners_; }
 
 
@@ -595,7 +604,9 @@ private:
     void GetChildrenRecursive(PODVector<Node*>& dest) const;
     void GetChildrenRecursive(PODVector<Node*>& dest) const;
     /// Return child nodes with a specific component recursively.
     /// Return child nodes with a specific component recursively.
     void GetChildrenWithComponentRecursive(PODVector<Node*>& dest, StringHash type) const;
     void GetChildrenWithComponentRecursive(PODVector<Node*>& dest, StringHash type) const;
-    /// Return specific components recursively.
+	/// Return child nodes with a specific tag recursively.
+	void GetChildrenWithTagRecursive(PODVector<Node*>& dest, StringHash tag) const;
+	/// Return specific components recursively.
     void GetComponentsRecursive(PODVector<Component*>& dest, StringHash type) const;
     void GetComponentsRecursive(PODVector<Component*>& dest, StringHash type) const;
     /// Clone node recursively.
     /// Clone node recursively.
     Node* CloneRecursive(Node* parent, SceneResolver& resolver, CreateMode mode);
     Node* CloneRecursive(Node* parent, SceneResolver& resolver, CreateMode mode);
@@ -638,6 +649,8 @@ private:
     Connection* owner_;
     Connection* owner_;
     /// Name.
     /// Name.
     String name_;
     String name_;
+	/// Tag.
+	StringHash tag_;
     /// Name hash.
     /// Name hash.
     StringHash nameHash_;
     StringHash nameHash_;
     /// Attribute buffer for network updates.
     /// Attribute buffer for network updates.

+ 75 - 0
Source/Urho3D/Scene/Scene.cpp

@@ -109,6 +109,7 @@ void Scene::RegisterObject(Context* context)
     URHO3D_ATTRIBUTE("Next Local Component ID", unsigned, localComponentID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
     URHO3D_ATTRIBUTE("Next Local Component ID", unsigned, localComponentID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
     URHO3D_ATTRIBUTE("Variables", VariantMap, vars_, Variant::emptyVariantMap, AM_FILE); // Network replication of vars uses custom data
     URHO3D_ATTRIBUTE("Variables", VariantMap, vars_, Variant::emptyVariantMap, AM_FILE); // Network replication of vars uses custom data
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Variable Names", GetVarNamesAttr, SetVarNamesAttr, String, String::EMPTY, AM_FILE | AM_NOEDIT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Variable Names", GetVarNamesAttr, SetVarNamesAttr, String, String::EMPTY, AM_FILE | AM_NOEDIT);
+	URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Tag Names", GetTagNamesAttr, SetTagNamesAttr, String, String::EMPTY, AM_FILE | AM_NOEDIT);
 }
 }
 
 
 bool Scene::Load(Deserializer& source, bool setInstanceDefault)
 bool Scene::Load(Deserializer& source, bool setInstanceDefault)
@@ -703,6 +704,21 @@ void Scene::UnregisterAllVars()
     varNames_.Clear();
     varNames_.Clear();
 }
 }
 
 
+void Scene::RegisterTag(const String& name)
+{
+	tagNames_[name] = name;
+}
+
+void Scene::UnregisterTag(const String& name)
+{
+	tagNames_.Erase(name);
+}
+
+void Scene::UnregisterAllTags()
+{
+	tagNames_.Clear();
+}
+
 Node* Scene::GetNode(unsigned id) const
 Node* Scene::GetNode(unsigned id) const
 {
 {
     if (id < FIRST_LOCAL_ID)
     if (id < FIRST_LOCAL_ID)
@@ -717,6 +733,19 @@ Node* Scene::GetNode(unsigned id) const
     }
     }
 }
 }
 
 
+bool Scene::GetNodesWithTag(PODVector<Node*>& dest, StringHash tag) const
+{
+	dest.Clear();
+	HashMap<StringHash, PODVector<Node*> >::ConstIterator it = tagedNodes_.Find(tag);
+	if (it != tagedNodes_.End())
+	{
+		dest = it->second_;
+		return true;
+	}
+	else
+		return false;
+}
+
 Component* Scene::GetComponent(unsigned id) const
 Component* Scene::GetComponent(unsigned id) const
 {
 {
     if (id < FIRST_LOCAL_ID)
     if (id < FIRST_LOCAL_ID)
@@ -744,6 +773,12 @@ const String& Scene::GetVarName(StringHash hash) const
     return i != varNames_.End() ? i->second_ : String::EMPTY;
     return i != varNames_.End() ? i->second_ : String::EMPTY;
 }
 }
 
 
+const String& Scene::GetTagName(StringHash tag) const
+{
+	HashMap<StringHash, String>::ConstIterator i = tagNames_.Find(tag);
+	return i != tagNames_.End() ? i->second_ : String::EMPTY;
+}
+
 void Scene::Update(float timeStep)
 void Scene::Update(float timeStep)
 {
 {
     if (asyncLoading_)
     if (asyncLoading_)
@@ -936,6 +971,10 @@ void Scene::NodeAdded(Node* node)
         localNodes_[id] = node;
         localNodes_[id] = node;
     }
     }
 
 
+	// cache tag if already taged.
+	if (node->GetTag() != StringHash::ZERO)
+		tagedNodes_[node->GetTag()].Push(node);
+
     // Add already created components and child nodes now
     // Add already created components and child nodes now
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
     for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
     for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
@@ -945,6 +984,14 @@ void Scene::NodeAdded(Node* node)
         NodeAdded(*i);
         NodeAdded(*i);
 }
 }
 
 
+void Scene::NodeTagChanged(Node* node, StringHash oldTag)
+{
+	if (oldTag != StringHash::ZERO)
+		tagedNodes_[oldTag].Remove(node);
+	if (node->GetTag() != StringHash::ZERO)
+		tagedNodes_[node->GetTag()].Push(node);
+}
+
 void Scene::NodeRemoved(Node* node)
 void Scene::NodeRemoved(Node* node)
 {
 {
     if (!node || node->GetScene() != this)
     if (!node || node->GetScene() != this)
@@ -961,6 +1008,10 @@ void Scene::NodeRemoved(Node* node)
 
 
     node->ResetScene();
     node->ResetScene();
 
 
+	// Remove cached taged node 
+	if(node->GetTag() != StringHash::ZERO)
+		tagedNodes_[node->GetTag()].Remove(node);
+
     // Remove components and child nodes as well
     // Remove components and child nodes as well
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
     for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
     for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
@@ -1489,6 +1540,30 @@ void Scene::PreloadResourcesJSON(const JSONValue& value)
 #endif
 #endif
 }
 }
 
 
+void Scene::SetTagNamesAttr(const String& value)
+{
+	Vector<String> tagNames = value.Split(';');
+
+	tagNames_.Clear();
+	for (Vector<String>::ConstIterator i = tagNames.Begin(); i != tagNames.End(); ++i)
+		tagNames_[*i] = *i;
+}
+
+Urho3D::String Scene::GetTagNamesAttr() const
+{
+	String ret;
+
+	if (!tagNames_.Empty())
+	{
+		for (HashMap<StringHash, String>::ConstIterator i = tagNames_.Begin(); i != tagNames_.End(); ++i)
+			ret += i->second_ + ';';
+
+		ret.Resize(ret.Length() - 1);
+	}
+
+	return ret;
+}
+
 void RegisterSceneLibrary(Context* context)
 void RegisterSceneLibrary(Context* context)
 {
 {
     ValueAnimation::RegisterObject(context);
     ValueAnimation::RegisterObject(context);

+ 25 - 5
Source/Urho3D/Scene/Scene.h

@@ -165,14 +165,22 @@ public:
     void UnregisterVar(const String& name);
     void UnregisterVar(const String& name);
     /// Clear all registered node user variable hash reverse mappings.
     /// Clear all registered node user variable hash reverse mappings.
     void UnregisterAllVars();
     void UnregisterAllVars();
+	/// Register a node Tag.
+	void RegisterTag(const String& name);
+	/// Unregister a node Tag and if set remove Tag from nodes.
+	void UnregisterTag(const String& name);
+	/// Clear all registered node Tag.
+	void UnregisterAllTags();
 
 
     /// Return node from the whole scene by ID, or null if not found.
     /// Return node from the whole scene by ID, or null if not found.
     Node* GetNode(unsigned id) const;
     Node* GetNode(unsigned id) const;
     /// Return component from the whole scene by ID, or null if not found.
     /// Return component from the whole scene by ID, or null if not found.
     Component* GetComponent(unsigned id) const;
     Component* GetComponent(unsigned id) const;
-
-    /// Return whether updates are enabled.
-    bool IsUpdateEnabled() const { return updateEnabled_; }
+	/// Get nodes with specific tag from the whole scene, return false if empty.
+	bool GetNodesWithTag(PODVector<Node*>& dest, StringHash tag)  const;
+	
+	/// Return whether updates are enabled.
+	bool IsUpdateEnabled() const { return updateEnabled_; }
 
 
     /// Return whether an asynchronous loading operation is in progress.
     /// Return whether an asynchronous loading operation is in progress.
     bool IsAsyncLoading() const { return asyncLoading_; }
     bool IsAsyncLoading() const { return asyncLoading_; }
@@ -207,8 +215,10 @@ public:
     /// Return required package files.
     /// Return required package files.
     const Vector<SharedPtr<PackageFile> >& GetRequiredPackageFiles() const { return requiredPackageFiles_; }
     const Vector<SharedPtr<PackageFile> >& GetRequiredPackageFiles() const { return requiredPackageFiles_; }
 
 
-    /// Return a node user variable name, or empty if not registered.
-    const String& GetVarName(StringHash hash) const;
+	/// Return a node user variable name, or empty if not registered.
+	const String& GetVarName(StringHash hash) const;
+	/// Return a node tag name, or empty if not registered.
+	const String& GetTagName(StringHash tag) const;
 
 
     /// Update scene. Called by HandleUpdate.
     /// Update scene. Called by HandleUpdate.
     void Update(float timeStep);
     void Update(float timeStep);
@@ -226,6 +236,8 @@ public:
     unsigned GetFreeNodeID(CreateMode mode);
     unsigned GetFreeNodeID(CreateMode mode);
     /// Get free component ID, either non-local or local.
     /// Get free component ID, either non-local or local.
     unsigned GetFreeComponentID(CreateMode mode);
     unsigned GetFreeComponentID(CreateMode mode);
+	/// Cache node by tag if tag not zero.
+	void NodeTagChanged(Node* node, StringHash oldTag);
     /// Node added. Assign scene pointer and add to ID map.
     /// Node added. Assign scene pointer and add to ID map.
     void NodeAdded(Node* node);
     void NodeAdded(Node* node);
     /// Node removed. Remove from ID map.
     /// Node removed. Remove from ID map.
@@ -238,6 +250,10 @@ public:
     void SetVarNamesAttr(const String& value);
     void SetVarNamesAttr(const String& value);
     /// Return node user variable reverse mappings.
     /// Return node user variable reverse mappings.
     String GetVarNamesAttr() const;
     String GetVarNamesAttr() const;
+	/// Set node tag reverse mappings.
+	void SetTagNamesAttr(const String& value);
+	/// Return node tag reverse mappings.
+	String GetTagNamesAttr() const;
     /// Prepare network update by comparing attributes and marking replication states dirty as necessary.
     /// Prepare network update by comparing attributes and marking replication states dirty as necessary.
     void PrepareNetworkUpdate();
     void PrepareNetworkUpdate();
     /// Clean up all references to a network connection that is about to be removed.
     /// Clean up all references to a network connection that is about to be removed.
@@ -277,6 +293,8 @@ private:
     HashMap<unsigned, Component*> replicatedComponents_;
     HashMap<unsigned, Component*> replicatedComponents_;
     /// Local components by ID.
     /// Local components by ID.
     HashMap<unsigned, Component*> localComponents_;
     HashMap<unsigned, Component*> localComponents_;
+	/// Cached taged nodes by tag.
+	HashMap<StringHash, PODVector<Node*> > tagedNodes_;
     /// Asynchronous loading progress.
     /// Asynchronous loading progress.
     AsyncProgress asyncProgress_;
     AsyncProgress asyncProgress_;
     /// Node and component ID resolver for asynchronous loading.
     /// Node and component ID resolver for asynchronous loading.
@@ -287,6 +305,8 @@ private:
     Vector<SharedPtr<PackageFile> > requiredPackageFiles_;
     Vector<SharedPtr<PackageFile> > requiredPackageFiles_;
     /// Registered node user variable reverse mappings.
     /// Registered node user variable reverse mappings.
     HashMap<StringHash, String> varNames_;
     HashMap<StringHash, String> varNames_;
+	/// Registered node tag reverse mappings.
+	HashMap<StringHash, String> tagNames_;
     /// Nodes to check for attribute changes on the next network update.
     /// Nodes to check for attribute changes on the next network update.
     HashSet<unsigned> networkUpdateNodes_;
     HashSet<unsigned> networkUpdateNodes_;
     /// Components to check for attribute changes on the next network update.
     /// Components to check for attribute changes on the next network update.

+ 9 - 0
Source/Urho3D/Scene/SceneEvents.h

@@ -156,6 +156,15 @@ URHO3D_EVENT(E_NODEENABLEDCHANGED, NodeEnabledChanged)
     URHO3D_PARAM(P_NODE, Node);                    // Node pointer
     URHO3D_PARAM(P_NODE, Node);                    // Node pointer
 }
 }
 
 
+/// A node's tag has changed.
+URHO3D_EVENT(E_NODETAGCHANGED, NodeTagChanged)
+{
+	URHO3D_PARAM(P_SCENE, Scene);					// Scene pointer
+	URHO3D_PARAM(P_NODE, Node);						// Node pointer
+	URHO3D_PARAM(P_TAG, Tag);						// StringHash tag
+	URHO3D_PARAM(P_OLDTAG, Tag);					// StringHash tag
+}
+
 /// A component's enabled state has changed.
 /// A component's enabled state has changed.
 URHO3D_EVENT(E_COMPONENTENABLEDCHANGED, ComponentEnabledChanged)
 URHO3D_EVENT(E_COMPONENTENABLEDCHANGED, ComponentEnabledChanged)
 {
 {