从HelloApp看一个cocos2d-x程序是怎么启动的

初学cocos2d-x,照着别人的示例,稍微改了一些很基础的东西玩玩,例如加些字,加些图片啊什么的。大致了解了,CCScene是个场景类,是被显示的:CCDirector是到导演类,控制程序流程;CCLayer是游戏画面层类,层上可以放置menu、精灵(游戏单位)、其他层等游戏元素。但是我好奇这个程序启动后的流程到底是怎么样的?于是稍微跟踪了一下。

毫无疑问,先main入手。

AppDelegate app;
    CCEGLView* eglView = CCEGLView::sharedOpenGLView();
    eglView->setViewName("HelloCpp");
    eglView->setFrameSize(480, 320);
    return CCApplication::sharedApplication()->run();

和QT差不多,基本main都很简单,先是建一个app对象,然后启动app的run()方法。从命名上看,AppDelegate应该是一个继承于CCApplication的类,而

sharedApplication()
这个静态函数也定是返回了app类的指针。转到AppDelegate.h,一看果然是继承于CCApplication。然后查看sharedApplication() 这个函数的定义
CCApplication* CCApplication::sharedApplication()
{
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}
看了下,基本就是assert()一下,然后返回CCApplication类指针。

到此,思路很简单,就是新建一个App对象,获取指针(至于为什么不直接用,估计是用断言判断下指针非空什么的,提高安全性吧),然后调用app的run()。那么这个run()里面到底发生了什么?

查看run()函数

int CCApplication::run()
{
    PVRFrameEnableControlWindow(false);

    // Main message loop:
    MSG msg;
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nLast;
    LARGE_INTEGER nNow;

    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nLast);

    // Initialize instance and cocos2d.
    if (!<span style="color: rgb(255, 0, 0);">applicationDidFinishLaunching()</span>)
    {
        return 0;
    }

    CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView();
    pMainWnd->centerWindow();
    ShowWindow(pMainWnd->getHWnd(), SW_SHOW);

    while (1)
    {
        if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // Get current time tick.
            QueryPerformanceCounter(&nNow);

            // If it's the time to draw next frame, draw it, else sleep a while.
            if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
            {
                nLast.QuadPart = nNow.QuadPart;
                CCDirector::sharedDirector()->mainLoop();
            }
            else
            {
                Sleep(0);
            }
            continue;
        }

        if (WM_QUIT == msg.message)
        {
            // Quit message loop.
            break;
        }

        // Deal with windows message.
        if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}
发现了一个AppDelegate类中有定义的函数  applicationDidFinishLaunching()。然后下面的结构,一看就是消息循环了,接收msg,处理msg,windows编程也是这个结构,只不过这个例子比较简单,只对一个WM_QUIT做了处理。回过头来查看 applicationDidFinishLaunching()这个函数,这函数父类CCApplication并没有,查了下宗谱,发现原来是爷爷的

class CC_DLL CCApplication : public CCApplicationProtocol
再看这函数的内容
bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    CCDirector* pDirector = CCDirector::sharedDirector();
    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    pDirector->setOpenGLView(pEGLView);
	
    // turn on display FPS
    pDirector->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    CCScene *pScene = HelloWorld::scene();

    // run
    pDirector->runWithScene(pScene);

    return true;
}
终于出现了CCDirector、CCScene这些”名“类,也出现了Helloword这个关键字,项目里的另一个类终于出现了。重点在于

 CCScene *pScene = HelloWorld::scene();

    // run
    pDirector->runWithScene(pScene);
这两句,调用了HelloWorld的一个静态方法获得了一个scene,然后director把运行起来了,然后我们就看到了,事情就是这么简单。继续“转到定义”看scene()这个函数,
CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}
创建一个CCScene对象,然后用HelloWorld类的create()函数创建一个“层”,把“层”布置到场景上,返回给导演用。看了下HelloWorld的定义,发现它的基类也是CCLayer
,粗略一看,没有create()函数。仔细看,发现一个
 CREATE_FUNC(HelloWorld);
点到这个宏上发现正是用这个宏定义这个create()函数,而且还发现这个函数用到了init()函数,正是这个Init()对HelloWorld这个Layer作了修饰,添加了各种图片按钮。

<pre name="code" class="cpp">CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition(CCPointZero);
    this->addChild(pMenu, 1);

添加了按钮
 
 CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
    
    // position the label on the center of the screen
    pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
                            origin.y + visibleSize.height - pLabel->getContentSize().height));

    // add the label as a child to this layer
    this->addChild(pLabel, 1);

添加图标

CCSprite* pSprite = CCSprite::create("HelloWorld.png");

    // position the sprite on the center of the screen
    pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    // add the sprite as a child to this layer
    this->addChild(pSprite, 0);

添加精灵

到此为止,思路基本理清了,故事原来是这样的:main函数新建了一个app对象并启动了它的run接口;这个run接口呢,调用了一个AppDelegate从CCApplicationProtocol那里继承过来的applicationDidFinishLaunching()接口,在里面新建一个了导演(CCDirector),并且用HelloWorld的scene()接口创建了一个HelloWorld的场景,用导演把场景运行起来,然后就进入按部就班模式(消息循环)。HelloWorld在创建场景的时候呢,就调用了自己的create函数,create里生成了那个场景,至于它场景的布置,则是在init()函数里完成的。

这样整个流程就大致清楚了。我可以在run()接口里对多种消息做处理而不只是退出;让导演多做一些控制,而不只是显示,显示也只是显示一个scene;在init里多加一些游戏元素;等等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值