您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx(一)-ios平台程序怎么跑起来的

2016-03-17 15:26 603 查看
cocos2dx的在不同平台上可以运行,上层主要使用c++来写的,但是跟平台相关的东西还需要用平台的默认语言跟平台提供的api来写的。下图是AppDelegata相关类图


ios中首先是main函数如下,它创建了AppController类,这是ios app的应用代理类,当app启动时,会调用这个类的

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions 方法。

int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
int retVal = UIApplicationMain(argc, argv, nil, @"AppController");
[pool release];
return retVal;
}


static AppDelegate s_sharedApplication;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Override point for customization after application launch.

// Add the view controller's view to the window and display.
window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
EAGLView *__glView = [EAGLView viewWithFrame: [window bounds]
pixelFormat: kEAGLColorFormatRGB565
depthFormat: GL_DEPTH24_STENCIL8_OES
preserveBackbuffer: NO
sharegroup: nil
multiSampling: NO
numberOfSamples: 0 ];

[__glView setMultipleTouchEnabled:YES];
// Use RootViewController manage EAGLView
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
viewController.view = __glView;

// Set RootViewController to window
if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// warning: addSubView doesn't work on iOS6
[window addSubview: viewController.view];
}
else
{
// use this method on ios6
[window setRootViewController:viewController];
}

[window makeKeyAndVisible];

[[UIApplication sharedApplication] setStatusBarHidden: YES];

cocos2d::CCApplication::sharedApplication()->run();
return YES;
}


上面是这个方法的内容,它创建了窗口与视图控制器,同时设置试图控制器的视图为opnegl视图,这个视图就是以后用来游戏渲染用的。每个app都有一个窗口,窗口下有一个试图控制器,它有一个视图,但是可以添加N个子视图。当完成视图设置后,最后调用了cocos2d::CCApplication::sharedApplication()->run(),这句代码让程序跑了起来。

cocos2d::CCApplication::sharedApplication()这句代码获得的并不是CCApplication类对象,而是它的子类AppDelegate对象。上面代码static AppDelegate s_sharedApplication,它创建了一个全局对象,这个对象的父类是CCApplication,在AppDelegate的父类构造函数中,它把this指针赋值给了父类的静态变量staticCCApplication
* sm_pSharedApplication。我们看到这个类一部分操作父类已经实现,而且父类的父类是CCApplicationProtocol,CCApplicationProtocol是个抽象类,一个方法也没实现,而CCApplication派生于它也没有实现那些方法,也是个抽象类,但是CCApplication实现了run、sharedApplication、setAnimationInterval等一些方法,sharedApplication访问的是sm_pSharedApplication指针,这个指针指向AppDelegate这个对象。

上面的代码其实用到了设计模式里面的对接口编程的这样一个设计思想,CCApplication类压根不知道自己子类是哪个,我们可以声明不同与AppDelegate的类,只要它派生于CCApplication就行了,上面的函数里代码根本不需要修改,只要修改static AppDelegate s_sharedApplication为static 新的类名 s_sharedApplication。这个新的类我们可以重新定义CCApplicationProtocol里面的方法。cocos2d::CCApplication::sharedApplication()->run()要是改成这个cocos2d::AppDelegate::sharedApplication()->run()大家可能就非常容易看懂了,AppDelegate是一个实现类,不能体现上面设计模式的基本思想,所以不要这样做。

int CCApplication::run()
{
if (applicationDidFinishLaunching())
{
[[CCDirectorCaller sharedDirectorCaller] startMainLoop];
}
return 0;
}
run方法里面首先调用了applicationDidFinishLaunching,这个函数其实才是逻辑上的app入口,我们一般在这里面写应用的初始化设置,设置分辨率设计模式,设置帧数什么的。[[CCDirectorCallersharedDirectorCaller]
startMainLoop]这句代码调用了CCDirectorCaller的startMainLoop方法,它的代码如下

-(void) startMainLoop
{
// CCDirector::setAnimationInterval() is called, we should invalidate it first
[displayLink invalidate];
displayLink = nil;

displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];
[displayLink setFrameInterval: self.interval];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}


displayLink是一个垂直同步的定时器,它能保持跟显示器一样的刷新率来调用target的方法。

displayLink = [NSClassFromString(@"CADisplayLink")displayLinkWithTarget:selfselector:@selector(doCaller:)];它设置了垂直同步方法是CCDirectorCaller中的doCaller方法,
doCaller方法如下

-(void) doCaller: (id) sender
{
cocos2d::CCDirector::sharedDirector()->mainLoop();
}


上面方法每帧被调用, [displayLinksetFrameInterval:
self.interval]可以设置帧间隔,如果self.interval为2,就指屏幕每刷新2次产生一帧动画调用。ios设备刷新率是60fps。
cocos2d::CCDirector::sharedDirector()->mainLoop()这句代码很重要,sharedDirector获得的是一个导演类,它获得的其实是一个CCDisplayLinkDirector对象,后面详细讲。mainLoop方法如下

void CCDisplayLinkDirector::mainLoop(void)
{
if (m_bPurgeDirecotorInNextLoop)
{
m_bPurgeDirecotorInNextLoop = false;
purgeDirector();
}
else if (! m_bInvalid)
{
drawScene();

// release the objects
CCPoolManager::sharedPoolManager()->pop();
}
}


bool m_bPurgeDirecotorInNextLoop;// this flag will be set to true in end(),m_bPurgeDirecotorInNextLoop是用于结束游戏的在end会被设置为true,暂时不分析游戏怎么结束的。下面代码是设置m_bInvalid的状态,startAnimation时,它为false,所以在运行动画时,上面的else部分会被调用。

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
}


void CCDisplayLinkDirector::stopAnimation(void)
{
m_bInvalid = true;
}


drawScene会绘制每一帧, CCPoolManager::sharedPoolManager()->pop()代码如下,m_pCurReleasePool是一个自动释放次,没有时是直接返回的,自动释放池也可以有多个,后面再详细讲cocos2dx的内存管理机制

void CCPoolManager::pop()
{
if (! m_pCurReleasePool)
{
return;
}

int nCount = m_pReleasePoolStack->count();

m_pCurReleasePool->clear();

if(nCount > 1)
{
m_pReleasePoolStack->removeObjectAtIndex(nCount-1);

//         if(nCount > 1)
//         {
//             m_pCurReleasePool = m_pReleasePoolStack->objectAtIndex(nCount - 2);
//             return;
//         }
m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
}

/*m_pCurReleasePool = NULL;*/
}


m_pCurReleasePool->clear()代码如下,它是清除释放池的,CCARRAY_FOREACH_REVERSE遍历释放池,把那些加入释放池,也就是那些调过autorelease的对象,把它们的计数减一,如果对象计数为0它就会被销毁。

void CCAutoreleasePool::clear()
{
if(m_pManagedObjectArray->count() > 0)
{
//CCAutoreleasePool* pReleasePool;
#ifdef _DEBUG
int nIndex = m_pManagedObjectArray->count() - 1;
#endif

CCObject* pObj = NULL;
CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
{
if(!pObj)
break;

--(pObj->m_uAutoReleaseCount);
//(*it)->release();
//delete (*it);
#ifdef _DEBUG
nIndex--;
#endif
}

m_pManagedObjectArray->removeAllObjects();
}
}


上面这些代码的分析可以看出,cocos2dx-ios部分使用了cocoa的CADisplayLink接口,以垂直同步屏幕刷新率的方式调用mainLoop函数进行每帧的绘制与内存释放。

就讲到这了,后面准备好好研究下opengl部分,然后写写心得
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: