场景图
同电影类似,游戏中也需要一个个场景(Scene),显示图片和动画在屏幕上,展示给玩家观看。Cocos2d-x
引擎中也抽象出来一个场景的概念。
场景图(Scene Graph)是一种安排场景内对象的数据结构,它把场景内所有的 节点(Node) 都包含在一个 树(tree) 上。(场景图虽然叫做”图”,但实际使用一个树结构来表示)。
例如《超级马里奥兄弟》中的著名场景 World 1-1:
场景结构可能是:
绘制顺序
中序遍历
场景图是个树形结构,引擎使用中序遍历(inorder
)来访问每个节点。根据子节点的 localZOrder
属性,为负的划分为左子树,大于等于 0 的划分为右子树。然后以 左子树
-> 父节点
->右子树
的顺序来进行绘制。
实际开发的过程中,可以按照任意顺序添加对象,引擎会按照指定的 localZOrder
来自动排序。
节点属性:
localZOrder
:顾名思义,表示局部 zOrder,影响此节点在兄弟节点中的绘制顺序。越小越先绘制,越大越后绘制。
globalZOrder
:全局 zOrder,影响此节点在整个场景中的绘制顺序。越小越先绘制,越大越后绘制。
示意图:
源码分析
节点访问顺序,中序遍历场景树
C++CCNode.cpp1 2 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.cpp1 2 3 4 5 6 7 8 9
| void Node::sortAllChildren() { if (_reorderChildDirty) { sortNodes(_children); _reorderChildDirty = false; _eventDispatcher->setDirtyForNode(this); } }
|
节点排序模板方法
C++CCNode.h1 2 3 4 5 6 7 8 9 10
| template<typename _T> inline static 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.cpp1 2 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.cpp1 2 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.cpp1 2 3 4
| static bool compareRenderCommand(RenderCommand* a, RenderCommand* b) { return a->getGlobalOrder() < b->getGlobalOrder(); }
|
参考链接