mirror of https://github.com/axmolengine/axmol.git
Add children indexer map for fast getChildByTag & getChildByName support
This commit is contained in:
parent
ac6636641b
commit
b4549fd38c
|
@ -34,6 +34,7 @@ THE SOFTWARE.
|
|||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "xxhash.h"
|
||||
#include "base/CCDirector.h"
|
||||
#include "base/CCScheduler.h"
|
||||
#include "base/CCEventDispatcher.h"
|
||||
|
@ -53,6 +54,10 @@ THE SOFTWARE.
|
|||
#define RENDER_IN_SUBPIXEL(__ARGS__) (ceil(__ARGS__))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4.5x faster than std::hash in release mode
|
||||
*/
|
||||
#define CC_HASH_NODE_NAME(name) (!name.empty() ? XXH3_64bits(name.c_str(), name.length()) : 0)
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
|
@ -84,13 +89,14 @@ Node::Node()
|
|||
, _additionalTransformDirty(false)
|
||||
, _transformUpdated(true)
|
||||
// children (lazy allocs)
|
||||
, _childrenIndexer(nullptr)
|
||||
// lazy alloc
|
||||
, _localZOrder$Arrival(0LL)
|
||||
, _globalZOrder(0)
|
||||
, _parent(nullptr)
|
||||
// "whole screen" objects. like Scenes and Layers, should set _ignoreAnchorPointForPosition to true
|
||||
, _tag(Node::INVALID_TAG)
|
||||
, _name("")
|
||||
, _name()
|
||||
, _hashOfName(0)
|
||||
// userData is always inited as nil
|
||||
, _userData(nullptr)
|
||||
|
@ -149,6 +155,8 @@ Node * Node::create()
|
|||
Node::~Node()
|
||||
{
|
||||
CCLOGINFO( "deallocing Node: %p - tag: %i", this, _tag );
|
||||
|
||||
CC_SAFE_DELETE(_childrenIndexer);
|
||||
|
||||
#if CC_ENABLE_SCRIPT_BINDING
|
||||
if (_updateScriptHandler)
|
||||
|
@ -680,7 +688,15 @@ int Node::getTag() const
|
|||
/// tag setter
|
||||
void Node::setTag(int tag)
|
||||
{
|
||||
_tag = tag ;
|
||||
auto parentChildrenIndexer = getParentChildrenIndexer();
|
||||
if (parentChildrenIndexer)
|
||||
{
|
||||
if (_tag != tag)
|
||||
parentChildrenIndexer->erase(_tag);
|
||||
(*parentChildrenIndexer)[tag] = this;
|
||||
}
|
||||
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
const std::string& Node::getName() const
|
||||
|
@ -690,9 +706,30 @@ const std::string& Node::getName() const
|
|||
|
||||
void Node::setName(const std::string& name)
|
||||
{
|
||||
uint64_t newHash = CC_HASH_NODE_NAME(name);
|
||||
auto parentChildrenIndexer = getParentChildrenIndexer();
|
||||
if (parentChildrenIndexer)
|
||||
{
|
||||
auto oldHash = CC_HASH_NODE_NAME(_name);
|
||||
if (oldHash != newHash)
|
||||
parentChildrenIndexer->erase(oldHash);
|
||||
(*parentChildrenIndexer)[newHash] = this;
|
||||
}
|
||||
|
||||
_name = name;
|
||||
std::hash<std::string> h;
|
||||
_hashOfName = h(name);
|
||||
_hashOfName = newHash;
|
||||
}
|
||||
|
||||
NodeIndexerMap_t* Node::getParentChildrenIndexer()
|
||||
{
|
||||
if (!_director->isChildrenIndexerEnabled())
|
||||
return nullptr;
|
||||
auto parent = getParent();
|
||||
|
||||
NodeIndexerMap_t* indexer = nullptr;
|
||||
if (parent && !parent->_childrenIndexer)
|
||||
indexer = parent->_childrenIndexer = new NodeIndexerMap_t();
|
||||
return indexer;
|
||||
}
|
||||
|
||||
/// userData setter
|
||||
|
@ -750,26 +787,41 @@ Node* Node::getChildByTag(int tag) const
|
|||
{
|
||||
CCASSERT(tag != Node::INVALID_TAG, "Invalid tag");
|
||||
|
||||
for (const auto child : _children)
|
||||
if (_childrenIndexer)
|
||||
{
|
||||
if(child && child->_tag == tag)
|
||||
return child;
|
||||
auto it = _childrenIndexer->find(tag);
|
||||
if (it != _childrenIndexer->end())
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto child : _children)
|
||||
{
|
||||
if (child && child->_tag == tag)
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node* Node::getChildByName(const std::string& name) const
|
||||
{
|
||||
CCASSERT(!name.empty(), "Invalid name");
|
||||
|
||||
std::hash<std::string> h;
|
||||
size_t hash = h(name);
|
||||
|
||||
for (const auto& child : _children)
|
||||
// CCASSERT(!name.empty(), "Invalid name");
|
||||
auto hash = CC_HASH_NODE_NAME(name);
|
||||
if (_childrenIndexer)
|
||||
{
|
||||
// Different strings may have the same hash code, but can use it to compare first for speed
|
||||
if(child->_hashOfName == hash && child->_name.compare(name) == 0)
|
||||
return child;
|
||||
auto it = _childrenIndexer->find(hash);
|
||||
if (it != _childrenIndexer->end())
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& child : _children)
|
||||
{
|
||||
// Different strings may have the same hash code, but can use it to compare first for speed
|
||||
if (child->_hashOfName == hash && child->_name.compare(name) == 0)
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -937,14 +989,14 @@ void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::stri
|
|||
}
|
||||
|
||||
this->insertChild(child, localZOrder);
|
||||
|
||||
|
||||
child->setParent(this);
|
||||
|
||||
if (setTag)
|
||||
child->setTag(tag);
|
||||
else
|
||||
child->setName(name);
|
||||
|
||||
child->setParent(this);
|
||||
|
||||
child->updateOrderOfArrival();
|
||||
|
||||
if( _running )
|
||||
|
@ -1056,6 +1108,7 @@ void Node::removeAllChildrenWithCleanup(bool cleanup)
|
|||
}
|
||||
|
||||
_children.clear();
|
||||
CC_SAFE_DELETE(_childrenIndexer);
|
||||
}
|
||||
|
||||
void Node::resetChild(Node* child, bool cleanup)
|
||||
|
|
|
@ -82,6 +82,8 @@ enum {
|
|||
|
||||
class EventListener;
|
||||
|
||||
typedef std::map<uint64_t, Node*> NodeIndexerMap_t;
|
||||
|
||||
/** @class Node
|
||||
* @brief Node is the base element of the Scene Graph. Elements of the Scene Graph must be Node objects or subclasses of it.
|
||||
The most common Node objects are: Scene, Layer, Sprite, Menu, Label.
|
||||
|
@ -1841,6 +1843,8 @@ protected:
|
|||
private:
|
||||
void addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag);
|
||||
|
||||
NodeIndexerMap_t* getParentChildrenIndexer();
|
||||
|
||||
protected:
|
||||
|
||||
float _rotationX; ///< rotation on the X-axis
|
||||
|
@ -1897,6 +1901,7 @@ protected:
|
|||
static std::uint32_t s_globalOrderOfArrival;
|
||||
|
||||
Vector<Node*> _children; ///< array of children nodes
|
||||
NodeIndexerMap_t* _childrenIndexer; ///< The children indexer for fast find child
|
||||
Node *_parent; ///< weak reference to parent node
|
||||
Director* _director; //cached director pointer to improve rendering performance
|
||||
int _tag; ///< a tag. Can be any number you assigned just to identify this node
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2019 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2021 Bytedance Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
https://adxe.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -502,6 +503,9 @@ public:
|
|||
*/
|
||||
const std::thread::id& getCocos2dThreadId() const { return _cocos2d_thread_id; }
|
||||
|
||||
void setChildrenIndexerEnabled(bool enable) { _childrenIndexerEnabled = enable; }
|
||||
bool isChildrenIndexerEnabled() const { return _childrenIndexerEnabled; }
|
||||
|
||||
/**
|
||||
* returns whether or not the Director is in a valid state
|
||||
*/
|
||||
|
@ -638,12 +642,14 @@ protected:
|
|||
|
||||
bool _isStatusLabelUpdated = true;
|
||||
|
||||
/* cocos2d thread id */
|
||||
std::thread::id _cocos2d_thread_id;
|
||||
|
||||
/* whether or not the director is in a valid state */
|
||||
bool _invalid = false;
|
||||
|
||||
bool _childrenIndexerEnabled = false;
|
||||
|
||||
/* cocos2d thread id */
|
||||
std::thread::id _cocos2d_thread_id;
|
||||
|
||||
// GLView will recreate stats labels to fit visible rect
|
||||
friend class GLView;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue