cocos2d-x: 死磕"HelloWorld"(5)——场景渲染准备工作
2014-07-05 07:41
549 查看
场景创建好之后,下一步便是将场景在屏幕上渲染出来。但是在渲染之前还有一些准备工作,该篇就是分析渲染准备函数runWithScene()。在第三篇中我们看到它在应用初始化函数applicationDidFinishLaunching()中被调用,且紧接场景创建函数HelloWorld::scene()之后。我们现在就来看看该函数定义:
CCDirector.cpp
void CCDirector::runWithScene(CCScene *pScene)
{
CCAssert(pScene != NULL, "This command can only be used to start the CCDirector. There is already a scene present.");
CCAssert(m_pRunningScene == NULL, "m_pRunningScene should be null");
pushScene(pScene);
startAnimation();
}
先判断即将运行的场景是否为空,如果是空的就无法运行,然后判断当前是否已经有场景在运行,如果已经有场景在运行就无法运行新的场景。判断完之后调用了两个函数,一是加载场景,二是开始动画。下面就来看第一个函数pushScence():
CCDirector.cpp
照样先判断即将加载的场景是否为空。然后将m_bSendCleanupToScene设为假。接着调用m_pobScenesStack成员函数addObject加载场景,最后将场景指针传递给m_pNextScene。下面进入函数addObject()
CCArray.cpp
该函数是CCArray类的成员函数。CCArray从名字上看是一个容器类,容器里面装的是CCObject类对象指针。由于场景继承了节点,而节点继承了CCObject类,所以场景对象也是CCObject对象。这里只调用了一个函数,顾名思义,调整大小加载对象。具体内容必须看一下该函数的定义
ccCArray.cpp
注意该函数不是CCArray类的成员函数,而是在ccCArray(不是CCArray)里定义的一个普通函数。它有两个参数,一是ccArray指针,另一个是CCObject指针。注意ccArray也不是CCArray,它是一个结构类型,定义如下
ccCArray.h
它有两个无符号整数num和max,和一个对象指针数组(即数组元素为对象指针),用于存放对象。知道了ccArray类型定义,对ccArrayAppendObjectWithResize()函数的理解就容易了一些,先看它调用的第一个函数
ccCArray.cpp
假如arr的数组大小小于arr的当前存储量(已利用元素数目)加上将要增加储存量,则调用ccArrayDoubleCapacity(arr)将arr数组扩大一倍。该扩充函数定义如下
ccCArray.cpp
主要就是调用了一个realloc来扩充内存空间。(有个疑问,为什么不用list来保存对象呢?这样不就不用担心存储空间了吗?待解决)。当有了足够的存储空间之后,便调用第二个函数ccArrayAppendObject()来加载场景
ccCArray.cpp
先判断添加的对象是否为空。不为空则调用对象的retain()函数将引用计数器加一(这是一种内存管理方式,当引用计数器降到零时,也就是对象不再被引用时才删除对象,详情请参考点击打开链接),然后就将对象指针添加到arr数组里,并将元素数目加一。
runWithScene()调用的另一函数定义为startAnimation()
CCDirector.cpp
如果gettimeofdayCocos2d()返回不为零,则说明获取当前时间失败。然后将m_bInvalid设置为假。如果宏EMSCRIPTEN未定义(默认未定义),则调用CCApplication函数setAnimationInterval()来设置动画帧间隔。
CCApplication.cpp
void CCApplication::setAnimationInterval(double interval)
{
LARGE_INTEGER nFreq;
QueryPerformanceFrequency(&nFreq);
m_nAnimationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
}注意setAnimationInterval()有两个定义,一个在CCDirector里,另一个在CCApplication里。前者在第三节的applicationDidFinishLaunching()里出现过,它设置的动画帧间隔的单位是秒(在该HelloWorld例子里为1/60秒),而后者在此处被调用。它的功能是将之前设置的时间间隔转换为windows高精度定时器的振荡次数。先利用QuerPerformanceFrequency()获取定时器的频率,然后将之前设置的时间间隔m_dAnimationInterval乘上该频率便得到以定时器的振荡次数为单位的动画帧间隔。
至此导演类成员函数runWithScene()已经基本解释完毕。它其实只是做了一个渲染准备工作,即将场景(严格的说只是场景指针)压入栈m_pobScenesStack中,便于导演管理场景切换渲染。另外顺便设置了动画帧间隔。但是对于HelloWorld这个简单例子而言,它只有一个场景,无需切换,所以并未用到场景栈。我们在pushScene()函数中已经看到HelloWorld场景指针已经被传递给m_pNextScene,我们在下一篇场景渲染实施中将看到,导演还会把m_pNextScene传递给 m_pRunningScene,然后对其进行渲染。
CCDirector.cpp
void CCDirector::runWithScene(CCScene *pScene)
{
CCAssert(pScene != NULL, "This command can only be used to start the CCDirector. There is already a scene present.");
CCAssert(m_pRunningScene == NULL, "m_pRunningScene should be null");
pushScene(pScene);
startAnimation();
}
先判断即将运行的场景是否为空,如果是空的就无法运行,然后判断当前是否已经有场景在运行,如果已经有场景在运行就无法运行新的场景。判断完之后调用了两个函数,一是加载场景,二是开始动画。下面就来看第一个函数pushScence():
CCDirector.cpp
void CCDirector::pushScene(CCScene *pScene) { CCAssert(pScene, "the scene should not null"); m_bSendCleanupToScene = false; m_pobScenesStack->addObject(pScene); m_pNextScene = pScene; }
照样先判断即将加载的场景是否为空。然后将m_bSendCleanupToScene设为假。接着调用m_pobScenesStack成员函数addObject加载场景,最后将场景指针传递给m_pNextScene。下面进入函数addObject()
CCArray.cpp
void CCArray::addObject(CCObject* object) { ccArrayAppendObjectWithResize(data, object); }
该函数是CCArray类的成员函数。CCArray从名字上看是一个容器类,容器里面装的是CCObject类对象指针。由于场景继承了节点,而节点继承了CCObject类,所以场景对象也是CCObject对象。这里只调用了一个函数,顾名思义,调整大小加载对象。具体内容必须看一下该函数的定义
ccCArray.cpp
/** Appends an object. Capacity of arr is increased if needed. */ void ccArrayAppendObjectWithResize(ccArray *arr, CCObject* object) { ccArrayEnsureExtraCapacity(arr, 1); ccArrayAppendObject(arr, object); }
注意该函数不是CCArray类的成员函数,而是在ccCArray(不是CCArray)里定义的一个普通函数。它有两个参数,一是ccArray指针,另一个是CCObject指针。注意ccArray也不是CCArray,它是一个结构类型,定义如下
ccCArray.h
typedef struct _ccArray { unsigned int num, max; CCObject** arr; } ccArray;
它有两个无符号整数num和max,和一个对象指针数组(即数组元素为对象指针),用于存放对象。知道了ccArray类型定义,对ccArrayAppendObjectWithResize()函数的理解就容易了一些,先看它调用的第一个函数
ccCArray.cpp
void ccArrayEnsureExtraCapacity(ccArray *arr, unsigned int extra) { while (arr->max < arr->num + extra) { ccArrayDoubleCapacity(arr); } }
假如arr的数组大小小于arr的当前存储量(已利用元素数目)加上将要增加储存量,则调用ccArrayDoubleCapacity(arr)将arr数组扩大一倍。该扩充函数定义如下
ccCArray.cpp
void ccArrayDoubleCapacity(ccArray *arr) { arr->max *= 2; CCObject** newArr = (CCObject**)realloc( arr->arr, arr->max * sizeof(CCObject*) ); // will fail when there's not enough memory CCAssert(newArr != 0, "ccArrayDoubleCapacity failed. Not enough memory"); arr->arr = newArr; }
主要就是调用了一个realloc来扩充内存空间。(有个疑问,为什么不用list来保存对象呢?这样不就不用担心存储空间了吗?待解决)。当有了足够的存储空间之后,便调用第二个函数ccArrayAppendObject()来加载场景
ccCArray.cpp
void ccArrayAppendObject(ccArray *arr, CCObject* object) { CCAssert(object != NULL, "Invalid parameter!"); object->retain(); arr->arr[arr->num] = object; arr->num++; }
先判断添加的对象是否为空。不为空则调用对象的retain()函数将引用计数器加一(这是一种内存管理方式,当引用计数器降到零时,也就是对象不再被引用时才删除对象,详情请参考点击打开链接),然后就将对象指针添加到arr数组里,并将元素数目加一。
runWithScene()调用的另一函数定义为startAnimation()
CCDirector.cpp
void CCDisplayLinkDirector::startAnimation(void) { if (CCTime::gettimeofdayCocos2d(m_pLastUpdate, NULL) != 0) { CCLOG("cocos2d: DisplayLinkDirector: Error on gettimeofday"); } m_bInvalid = false; #ifndef EMSCRIPTEN CCApplication::sharedApplication()->setAnimationInterval(m_dAnimationInterval); #endif // EMSCRIPTEN }
如果gettimeofdayCocos2d()返回不为零,则说明获取当前时间失败。然后将m_bInvalid设置为假。如果宏EMSCRIPTEN未定义(默认未定义),则调用CCApplication函数setAnimationInterval()来设置动画帧间隔。
CCApplication.cpp
void CCApplication::setAnimationInterval(double interval)
{
LARGE_INTEGER nFreq;
QueryPerformanceFrequency(&nFreq);
m_nAnimationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
}注意setAnimationInterval()有两个定义,一个在CCDirector里,另一个在CCApplication里。前者在第三节的applicationDidFinishLaunching()里出现过,它设置的动画帧间隔的单位是秒(在该HelloWorld例子里为1/60秒),而后者在此处被调用。它的功能是将之前设置的时间间隔转换为windows高精度定时器的振荡次数。先利用QuerPerformanceFrequency()获取定时器的频率,然后将之前设置的时间间隔m_dAnimationInterval乘上该频率便得到以定时器的振荡次数为单位的动画帧间隔。
至此导演类成员函数runWithScene()已经基本解释完毕。它其实只是做了一个渲染准备工作,即将场景(严格的说只是场景指针)压入栈m_pobScenesStack中,便于导演管理场景切换渲染。另外顺便设置了动画帧间隔。但是对于HelloWorld这个简单例子而言,它只有一个场景,无需切换,所以并未用到场景栈。我们在pushScene()函数中已经看到HelloWorld场景指针已经被传递给m_pNextScene,我们在下一篇场景渲染实施中将看到,导演还会把m_pNextScene传递给 m_pRunningScene,然后对其进行渲染。
相关文章推荐
- cocos2d-x: 死磕"HelloWorld"(6)——场景渲染的实施
- cocos2d-x: 死磕"HelloWorld"(4)——HelloWorld场景的创建
- cocos2d-x: 死磕"HelloWorld"(1)——入口函数及其带来的疑问
- cocos2d-x: 死磕"HelloWorld"(2)——应用实例的创建
- cocos2d-x: 死磕"HelloWorld"(3)——游戏运行主函数run()
- Cocos2d-x--"Hello World"深入分析
- Cocos2d-x简单游戏<打飞机>代码实现|第四部分:主场景<Helloworld.h>
- Java开发环境的准备及"hello world"
- cocos2d-x简单游戏<打飞机>代码实现|第四部分:主场景<Helloworld.m>
- cocos2d 游戏开发:Cocos2d v3 "hello world"+显示飞船
- cocos2d 游戏开发:Cocos2d v3 "hello world"+显示飞船
- python爬虫"Hello World"级入门实例(二),使用json从中国天气网抓取数据
- "Hello world" ,frist program
- Cocos2d-x HelloWorld的全面解析
- Web jquery表格组件 JQGrid 的使用 - 6.准备工作 & Hello JQGrid
- 1.第一个程序: "Hello, World"
- /bin/helloworld: line 1: syntax error: unexpected word (expecting ")")
- (原)cocos2d笔记——解析HelloWorldScene
- RabbitMQ随手笔记(二)RabbitMQ-"Hello World" 之生产者(netCore2.0)
- Cocos2d-x 图像渲染和动画——场景转换(Transitions)