场景图
同电影类似,游戏中也需要一个个场景(Scene),显示图片和动画在屏幕上,展示给玩家观看。Cocos2d-x 引擎中也抽象出来一个场景的概念。
场景图(Scene Graph)是一种安排场景内对象的数据结构,它把场景内所有的 节点(Node) 都包含在一个 树(tree) 上。(场景图虽然叫做”图”,但实际使用一个树结构来表示)。
例如《超级马里奥兄弟》中的著名场景 World 1-1:
 
场景结构可能是:
 
绘制顺序
中序遍历
场景图是个树形结构,引擎使用中序遍历(inorder)来访问每个节点。根据子节点的 localZOrder 属性,为负的划分为左子树,大于等于 0 的划分为右子树。然后以 左子树 -> 父节点->右子树 的顺序来进行绘制。
实际开发的过程中,可以按照任意顺序添加对象,引擎会按照指定的 localZOrder 来自动排序。
节点属性:
- localZOrder:顾名思义,表示局部 zOrder,影响此节点在兄弟节点中的绘制顺序。越小越先绘制,越大越后绘制。
- globalZOrder:全局 zOrder,影响此节点在整个场景中的绘制顺序。越小越先绘制,越大越后绘制。
示意图:
 
源码分析
节点访问顺序,中序遍历场景树
C++CCNode.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags) {
 
 
 
 int i = 0;
 
 if(!_children.empty())
 {
 
 sortAllChildren();
 
 for(auto size = _children.size(); i < size; ++i)
 {
 auto node = _children.at(i);
 
 if (node && node->_localZOrder < 0)
 node->visit(renderer, _modelViewTransform, flags);
 else
 break;
 }
 
 if (visibleByCamera)
 this->draw(renderer, _modelViewTransform, flags);
 
 
 for(auto it=_children.cbegin()+i, itCend = _children.cend(); it != itCend; ++it)
 (*it)->visit(renderer, _modelViewTransform, flags);
 }
 
 
 
 }
 
 | 
 
对子节点进行排序
C++CCNode.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 
 | void Node::sortAllChildren(){
 if (_reorderChildDirty)
 {
 sortNodes(_children);
 _reorderChildDirty = false;
 _eventDispatcher->setDirtyForNode(this);
 }
 }
 
 | 
 
节点排序模板方法
C++CCNode.h| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | template<typename _T> inlinestatic void sortNodes(cocos2d::Vector<_T*>& nodes)
 {
 
 static_assert(std::is_base_of<Node, _T>::value, "Node::sortNodes: Only accept derived of Node!");
 std::stable_sort(std::begin(nodes), std::end(nodes), [](_T* n1, _T* n2) {
 
 return n1->_localZOrder < n2->_localZOrder;
 });
 }
 
 | 
 
渲染器渲染方法,globalZOrder 属性影响渲染顺序。
C++CCRenderer.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | void Renderer::render(){
 
 
 
 
 _isRendering = true;
 
 if (_glViewAssigned)
 {
 
 
 for (auto &renderqueue : _renderGroups)
 {
 
 renderqueue.sort();
 }
 visitRenderQueue(_renderGroups[0]);
 }
 clean();
 _isRendering = false;
 }
 
 | 
 
渲染队列中的排序方法
C++CCRenderer.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 
 | void RenderQueue::sort(){
 
 std::stable_sort(std::begin(_commands[QUEUE_GROUP::TRANSPARENT_3D]), std::end(_commands[QUEUE_GROUP::TRANSPARENT_3D]), compare3DCommand);
 
 std::stable_sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_NEG]), std::end(_commands[QUEUE_GROUP::GLOBALZ_NEG]), compareRenderCommand);
 
 std::stable_sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_POS]), std::end(_commands[QUEUE_GROUP::GLOBALZ_POS]), compareRenderCommand);
 }
 
 | 
 
比较 globalZOrder 方法
C++CCRenderer.cpp| 12
 3
 4
 
 | static bool compareRenderCommand(RenderCommand* a, RenderCommand* b){
 return a->getGlobalOrder() < b->getGlobalOrder();
 }
 
 | 
 
参考链接