cocos2d-x游戏开发(十)执行单元场景CCScene

前端之家收集整理的这篇文章主要介绍了cocos2d-x游戏开发(十)执行单元场景CCScene前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

欢迎转载:http://blog.csdn.net/fylz1125/article/details/8524081


游戏逻辑其实就像拍摄一部电影,整个过程都由导演来驱动。

游戏中的一个一个关卡,一个一个场景都跟电影中类似。每一个场景都有一些特定的元素,比如林冲风雪山神庙这个场景,大环境就是一个大风雪的夜晚,一个银装素裹的破败山头,有一个破败的山神庙,当然还可以有一些其他的元素,比如火光,野狼,灯光,乌鸦连声叫、黄狗大声吼等。这就是一个特定的场景了,呵呵。然后导演大叫一声:“Action!”,然后所有的故事情节就在这里展开,主角和一干配角上场了...

以上所有的元素就组成了这么一个场景,那么在游戏里又如何组织这些元素呢。先来看看cocos2d-x的场景处理流程。

cocos2d-x中的导演执行单元就是场景CCScene。一个场景又有那么多元素,比如一个大的背景,然后又有一些小元素,比如星星,火堆,狗等,又是如何加到场景里的呢。

可以这么说,一个场景就是一个特别的容器(其实就是一个CCNode),它能容纳各类节点(通过addChild)。那么跟电影一样,镜头一出来先有一个大的环境。这个就是主背景层(CCLayer),对,就是CCLayer(怎么翻译好一点)。然后在这个主Layer里面再添加一些其他的元素,比如人物、火堆、狂奔的大狗、清唱的小鸟等。这些元素都是独立的对象(继承CCSprite),他们都有各自的属性和行为,比如人物是一个男人,他在漫无目的的行走,火堆在燃烧放出一跳一跳的火光,狗在奔跑,鸟在飞来飞去等。所有这些元素都添加到主Layer里面,然后这个主Layer又被添加都场景里面(CCScene),最后导演执行这个场景(pDirector->runWithScene(pScene)),一个画面就出来了。

来看一看代码级别的执行过程:

主循环(不知道的看我前面的文章)

  1. voidCCDisplayLinkDirector::mainLoop(void)
  2. {
  3. if(m_bPurgeDirecotorInNextLoop)
  4. m_bPurgeDirecotorInNextLoop=false;
  5. purgeDirector();
  6. }
  7. elseif(!m_bInvalid)
  8. {
  9. drawScene();//注意这里就是画场景了
  10. //releasetheobjects
  11. CCPoolManager::sharedPoolManager()->pop();
  12. }
  13. }

跟进drawScene()看看怎么画的

?
    voidCCDirector::drawScene(void)
  1. //calculate"global"dt
  2. calculateDeltaTime();
  3. //tickbeforeglClear:issue#533
  4. if(!m_bPaused)
  5. m_pScheduler->update(m_fDeltaTime);//按照优先级调度update函数(每个节点都有这么个函数)
  6. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  7. /*toavoidflickr,nextSceneMUSTbehere:aftertickandbeforedraw.
  8. XXX:Whichbugisthisone.Itseemsthatitcan'tbereproducedwithv0.9*/
  9. if(m_pNextScene)//这个变量存下次绘制的场景,本次绘制则是上一次设置的场景
  10. setNextScene();//注意这个,不要被名字误导,其实就是设置下一次要运行的场景
  11. kmGLPushMatrix();
  12. //drawthescene
  13. if(m_pRunningScene)
  14. m_pRunningScene->visit();//注意看这里,这个visit函数就是递归绘制子节点
  15. //drawthenotificationsnode
  16. if(m_pNotificationNode)
  17. m_pNotificationNode->visit();
  18. if(m_bDisplayStats)
  19. showStats();
  20. kmGLPopMatrix();
  21. m_uTotalFrames++;
  22. //swapbuffers
  23. if(m_pobOpenGLView)
  24. m_pobOpenGLView->swapBuffers();
  25. if(m_bDisplayStats)
  26. calculateMPF();
  27. }

好,看注释,有个visit函数,这个就是递归绘制子节点的

?
    voidCCNode::visit()
  1. //quickreturnifnotvisible.childrenwon'tbedrawn.
  2. if(!m_bVisible)
  3. return;
  4. kmGLPushMatrix();
  5. if(m_pGrid&&m_pGrid->isActive())
  6. m_pGrid->beforeDraw();
  7. this->transform();
  8. CCNode*pNode=NULL;
  9. unsignedinti=0;
  10. if(m_pChildren&&m_pChildren->count()>0)//这里开始,如果有子节点就进入
  11. sortAllChildren();//按z坐标排序,就是z序排列子节点
  12. //drawchildrenzOrder<0
  13. ccArray*arrayData=m_pChildren->data;
  14. for(;i<arrayData->num;i++)//画z序<0的子节点
  15. pNode=(CCNode*)arrayData->arr[i];
  16. if(pNode&&pNode->m_nZOrder<0)
  17. pNode->visit();
  18. else
  19. break;
  20. //selfdraw
  21. this->draw();//画自己
  22. for(;i<arrayData->num;i++)
  23. if(pNode)
  24. pNode->visit();
  25. else
  26. this->draw();//没有子节点就画自己
  27. //resetfornextframe
  28. m_uOrderOfArrival=0;
  29. m_pGrid->afterDraw(this);
  30. kmGLPopMatrix();
  31. }

这个是主循环的,但是要运行一个场景是从哪开始的呢,比如

?
    CCScene*pScene=HelloWorld::scene();
  1. //run
  2. pDirector->runWithScene(pScene);

看,第一个场景从这里开始的,跟进

?
    voidCCDirector::runWithScene(CCScene*pScene)
  1. CCAssert(pScene!=NULL,"ThiscommandcanonlybeusedtostarttheCCDirector.Thereisalreadyascenepresent.");
  2. CCAssert(m_pRunningScene==NULL,"m_pRunningSceneshouldbenull");//当前运行为NULL(第一次)
  3. pushScene(pScene);//push是什么呢
  4. startAnimation();//这里控制帧率,同时又进入主循环
  5. }

看这个pushScene函数,是干什么的

?
    voidCCDirector::pushScene(CCScene*pScene)
  1. CCAssert(pScene,"thesceneshouldnotnull");
  2. m_bSendCleanupToScene=false;
  3. m_pobScenesStack->addObject(pScene);//当前scene入栈
  4. m_pNextScene=pScene;//nextScene,就是下一次绘制当前scene
  5. }


好了,这个pushScene干了两件事,将要绘制的scene入栈,将下次要绘制的场景设为pScene。这个函数返回后接着是

startAnimation(),这个函数调整帧率然后再次进入主循环。

再回头看看主循环的drawScene()函数(上面有),其中有段:

?
    if(m_pNextScene)//刚才的pushScene函数设置了这个值
  1. setNextScene();//将下个要运行的Scene给m_pRunningScene
  2. //drawthescene
  3. if(m_pRunningScene)//这里开始渲染当前要运行的Scene
  4. m_pRunningScene->visit();
  5. }

代码有点绕,其实就是一个迭代过程。最开始第一次m_pRunningScene是NULL,然后 runWithScene后就有了,m_pRunningScene就是你传进去的Scene,不过是在下次循环绘制运行。这里有两个过程,一个就是runWithScene函数和replaceScene函数,这两个函数都会设置下个Scene,同时将要运行的Scene入栈。然后进入主循环,在主循环中每次都会检测当前要运行的Scene,如果有就渲染执行。就是这么一个过程。

导演每次只能执行一个场景,执行并不仅仅是绘制,还包括其动作,回调,过渡等。每个场景实质上是一个CCNode,

前面讲过,CCNode有个很重要的成员变量m_pChildren,这是一个CCArray,用来存放添加到该节点的子节点。Scene在渲染的时候会递归渲染其子节点,这就组成一个渲染链,保证整个场景的所有元素都会被渲染。

猜你在找的Cocos2d-x相关文章