cocos2dx 3.5 ”hello world“解析

来源:互联网 发布:stl源码剖析 编辑:程序博客网 时间:2024/06/10 17:10

cocos2dx 3.5工程下自带的helloworld程序目录如下:


先看看main.h和main.cpp:

#ifndef __MAIN_H__#define __MAIN_H__#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers// Windows Header Files:#include <windows.h>#include <tchar.h>// C RunTime Header Files#include "CCStdC.h"#endif    // __MAIN_H__

#include "main.h"#include "../Classes/AppDelegate.h"USING_NS_CC;int APIENTRY _tWinMain(HINSTANCE hInstance,                       HINSTANCE hPrevInstance,                       LPTSTR    lpCmdLine,                       int       nCmdShow){    UNREFERENCED_PARAMETER(hPrevInstance);    UNREFERENCED_PARAMETER(lpCmdLine);    // create the application instance    AppDelegate app;    return Application::getInstance()->run();}
这是程序主入口,可以看出,此处做的唯一事情就是定义一个AppDelegate类对象,之后,让其跑起来,结构十分清晰。
以下看看我们的应用代理类(AppDelegate.h和AppDelegate.cpp):

#ifndef  _APP_DELEGATE_H_#define  _APP_DELEGATE_H_#include "cocos2d.h"/**@brief    The cocos2d Application.The reason for implement as private inheritance is to hide some interface call by Director.*/class  AppDelegate : private cocos2d::Application{public:    AppDelegate();    virtual ~AppDelegate();    virtual void initGLContextAttrs();        /**    @brief    Implement Director and Scene init code here.    @return true    Initialize success, app continue.    @return false   Initialize failed, app terminate.    */    virtual bool applicationDidFinishLaunching();    /**    @brief  The function be called when the application enter background    @param  the pointer of the application    */    virtual void applicationDidEnterBackground();    /**    @brief  The function be called when the application enter foreground    @param  the pointer of the application    */    virtual void applicationWillEnterForeground();};#endif // _APP_DELEGATE_H_

#include "AppDelegate.h"#include <vector>#include <string>#include "HelloWorldScene.h"#include "AppMacros.h"USING_NS_CC;using namespace std;AppDelegate::AppDelegate() {}AppDelegate::~AppDelegate() {}void AppDelegate::initGLContextAttrs(){    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};    GLView::setGLContextAttrs(glContextAttrs);}bool AppDelegate::<strong><span style="color:#ff0000;">applicationDidFinishLaunching</span></strong>() {    // initialize director    auto director = Director::getInstance();    auto glview = director->getOpenGLView();    if(!glview) {        glview = GLViewImpl::create("Cpp Empty Test");        director->setOpenGLView(glview);    }    director->setOpenGLView(glview);    // Set the design resolution#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)    // a bug in DirectX 11 level9-x on the device prevents ResolutionPolicy::NO_BORDER from working correctly    glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL);#else    glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL);#endifSize frameSize = glview->getFrameSize();        vector<string> searchPath;    // In this demo, we select resource according to the frame's height.    // If the resource size is different from design resolution size, you need to set contentScaleFactor.    // We use the ratio of resource's height to the height of design resolution,    // this can make sure that the resource's height could fit for the height of design resolution.    // if the frame's height is larger than the height of medium resource size, select large resource.if (frameSize.height > mediumResource.size.height){        searchPath.push_back(largeResource.directory);        director->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));}    // if the frame's height is larger than the height of small resource size, select medium resource.    else if (frameSize.height > smallResource.size.height)    {        searchPath.push_back(mediumResource.directory);                director->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));    }    // if the frame's height is smaller than the height of medium resource size, select small resource.else    {        searchPath.push_back(smallResource.directory);        director->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));    }        // set searching path    FileUtils::getInstance()->setSearchPaths(searchPath);    // turn on display FPS    director->setDisplayStats(true);    // set FPS. the default value is 1.0/60 if you don't call this    director->setAnimationInterval(1.0 / 60);    // create a scene. it's an autorelease object    auto scene = HelloWorld::scene();    // run    director->runWithScene(scene);    return true;}// This function will be called when the app is inactive. When comes a phone call,it's be invoked toovoid AppDelegate::applicationDidEnterBackground() {    Director::getInstance()->stopAnimation();    // if you use SimpleAudioEngine, it must be pause    // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();}// this function will be called when the app is active againvoid AppDelegate::applicationWillEnterForeground() {    Director::getInstance()->startAnimation();    // if you use SimpleAudioEngine, it must resume here    // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();}
这里代码流程不是很好看,先贴出以上代码以供参考,下面调试跟踪下代码流程:

1)程序启动后,创建应用程序代理对象,此时会调用其基类构造函数:

Application::Application(): _instance(nullptr), _accelTable(nullptr){    _instance    = GetModuleHandle(nullptr);    _animationInterval.QuadPart = 0;    CC_ASSERT(! sm_pSharedApplication);    sm_pSharedApplication = this;}

可以看出这里主要是获取了当前进程模块的句柄以及保存了当前的应用程序对象指针。之后便run起来了:

Application::getInstance()->run();

int Application::run(){    PVRFrameEnableControlWindow(false);    // Main message loop:    LARGE_INTEGER nLast;    LARGE_INTEGER nNow;    QueryPerformanceCounter(&nLast);    initGLContextAttrs();    // Initialize instance and cocos2d.    if (!<span style="color:#ff0000;"><strong>applicationDidFinishLaunching</strong></span>())    {        return 0;    }    auto director = Director::getInstance();    auto glview = director->getOpenGLView();    // Retain glview to avoid glview being released in the while loop    glview->retain();    while(!glview->windowShouldClose())    {        QueryPerformanceCounter(&nNow);        if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)        {            nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart);                        director->mainLoop();            glview->pollEvents();        }        else        {            Sleep(1);        }    }    // Director should still do a cleanup if the window was closed manually.    if (glview->isOpenGLReady())    {        director->end();        director->mainLoop();        director = nullptr;    }    glview->release();    return true;}

从这里可以看出,我们自己所写的AppDelegate类中的applicationDidFinishLaunching,initGLContextAttrs等函数的调用时机。可以看出以上代码关键部分为消息循环:

<span style="color:#ff0000;"><strong>  while(!glview->windowShouldClose())    {        QueryPerformanceCounter(&nNow);        if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)        {            nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart);                        director->mainLoop();            glview->pollEvents();        }        else        {            Sleep(1);        }<span style="font-family: Arial, Helvetica, sans-serif;">}</span></strong></span>
director->mainLoop主循环主要代码如下:



可看出这里主要是做渲染场景的工作,glview->pollEvents()代码主要为:

void GLViewImpl::pollEvents(){    glfwPollEvents();}
可以看出cocos使用的是glfw框架,还是重点瞧瞧drawScene方法:

// Draw the Scenevoid Director::drawScene(){    // calculate "global" dt    calculateDeltaTime();        if (_openGLView)    {        _openGLView->pollEvents();    }    //tick before glClear: issue #533    if (! _paused)    {        <span style="color:#ff0000;"><strong>_scheduler->update(_deltaTime);</strong></span>        _eventDispatcher->dispatchEvent(_eventAfterUpdate);    }    _renderer->clear();    /* to avoid flickr, nextScene MUST be here: after tick and before draw.     * FIXME: Which bug is this one. It seems that it can't be reproduced with v0.9     */    if (_nextScene)    {        setNextScene();    }    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);        if (_runningScene)    {#if CC_USE_PHYSICS        auto physicsWorld = _runningScene->getPhysicsWorld();        if (physicsWorld && physicsWorld->isAutoStep())        {            physicsWorld->update(_deltaTime, false);        }#endif        //clear draw stats        _renderer->clearDrawStats();                //render the scene        _runningScene->render(_renderer);                _eventDispatcher->dispatchEvent(_eventAfterVisit);    }    // draw the notifications node    if (_notificationNode)    {        _notificationNode->visit(_renderer, Mat4::IDENTITY, 0);    }    if (_displayStats)    {        showStats();    }    _renderer->render();    _eventDispatcher->dispatchEvent(_eventAfterDraw);    popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);    _totalFrames++;    // swap buffers    if (_openGLView)    {        _openGLView->swapBuffers();    }    if (_displayStats)    {        calculateMPF();    }}

可以看出关键的逻辑更新代码_scheduler->update(_deltaTime);为

// main loopvoid Scheduler::update(float dt){    _updateHashLocked = true;    if (_timeScale != 1.0f)    {        dt *= _timeScale;    }    //    // Selector callbacks    //    // Iterate over all the Updates' selectors    tListEntry *entry, *tmp;    // updates with priority < 0    DL_FOREACH_SAFE(_updatesNegList, entry, tmp)    {        if ((! entry->paused) && (! entry->markedForDeletion))        {            entry->callback(dt);        }    }    // updates with priority == 0    DL_FOREACH_SAFE(_updates0List, entry, tmp)    {        if ((! entry->paused) && (! entry->markedForDeletion))        {            entry->callback(dt);        }    }    // updates with priority > 0    DL_FOREACH_SAFE(_updatesPosList, entry, tmp)    {        if ((! entry->paused) && (! entry->markedForDeletion))        {            entry->callback(dt);        }    }    // Iterate over all the custom selectors    for (tHashTimerEntry *elt = _hashForTimers; elt != nullptr; )    {        _currentTarget = elt;        _currentTargetSalvaged = false;        if (! _currentTarget->paused)        {            // The 'timers' array may change while inside this loop            for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))            {                elt->currentTimer = (Timer*)(elt->timers->arr[elt->timerIndex]);                elt->currentTimerSalvaged = false;                elt->currentTimer->update(dt);                if (elt->currentTimerSalvaged)                {                    // The currentTimer told the remove itself. To prevent the timer from                    // accidentally deallocating itself before finishing its step, we retained                    // it. Now that step is done, it's safe to release it.                    elt->currentTimer->release();                }                elt->currentTimer = nullptr;            }        }        // elt, at this moment, is still valid        // so it is safe to ask this here (issue #490)        elt = (tHashTimerEntry *)elt->hh.next;        // only delete currentTarget if no actions were scheduled during the cycle (issue #481)        if (_currentTargetSalvaged && _currentTarget->timers->num == 0)        {            removeHashElement(_currentTarget);        }    }    // delete all updates that are marked for deletion    // updates with priority < 0    DL_FOREACH_SAFE(_updatesNegList, entry, tmp)    {        if (entry->markedForDeletion)        {            this->removeUpdateFromHash(entry);        }    }    // updates with priority == 0    DL_FOREACH_SAFE(_updates0List, entry, tmp)    {        if (entry->markedForDeletion)        {            this->removeUpdateFromHash(entry);        }    }    // updates with priority > 0    DL_FOREACH_SAFE(_updatesPosList, entry, tmp)    {        if (entry->markedForDeletion)        {            this->removeUpdateFromHash(entry);        }    }    _updateHashLocked = false;    _currentTarget = nullptr;#if CC_ENABLE_SCRIPT_BINDING    //    // Script callbacks    //    // Iterate over all the script callbacks    if (!_scriptHandlerEntries.empty())    {        for (auto i = _scriptHandlerEntries.size() - 1; i >= 0; i--)        {            SchedulerScriptHandlerEntry* eachEntry = _scriptHandlerEntries.at(i);            if (eachEntry->isMarkedForDeletion())            {                _scriptHandlerEntries.erase(i);            }            else if (!eachEntry->isPaused())            {                eachEntry->getTimer()->update(dt);            }        }    }#endif    //    // Functions allocated from another thread    //    // Testing size is faster than locking / unlocking.    // And almost never there will be functions scheduled to be called.    if( !_functionsToPerform.empty() ) {        _performMutex.lock();        // fixed #4123: Save the callback functions, they must be invoked after '_performMutex.unlock()', otherwise if new functions are added in callback, it will cause thread deadlock.        auto temp = _functionsToPerform;        _functionsToPerform.clear();        _performMutex.unlock();        for( const auto &function : temp ) {            function();        }            }}
这个过程就是这样,其实我们利用cocos2dx编写游戏时,可以先不了解这些过程。关键点就是在bool AppDelegate::applicationDidFinishLaunching()中设置一些平台相关的资源搜索路径,以及FPS等等之后,利用我们继承layer类所得的hellworld类中的scene方法中创建我们自己的场景 auto scene = HelloWorld::scene();并创建自己,最后将此layer添加到场景中。

Scene* HelloWorld::scene(){    // 'scene' is an autorelease object    auto scene = Scene::create();        // 'layer' is an autorelease object    HelloWorld *layer = <span style="color:#ff0000;"><strong>HelloWorld::create</strong></span>();    // add layer as a child to scene    scene->addChild(layer);    // return the scene    return scene;}
特别要注意的是这个HelloWorld::create方法,是由宏定义的 CREATE_FUNC(HelloWorld);

#define CREATE_FUNC(__TYPE__) \static __TYPE__* create() \{ \    __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \    if (pRet && pRet->init()) \    { \        pRet->autorelease(); \        return pRet; \    } \    else \    { \        delete pRet; \        pRet = NULL; \        return NULL; \    } \}
之后我们做的更多的事情就是在layer子类中对更多的事情,需要什么添加什么。

最后,我们欣赏下glfw框架下的helloworld程序:

#include <glfw3.h>int main(void){GLFWwindow* window;/* Initialize the library */if (!glfwInit())return -1;/* Create a windowed mode window and its OpenGL context */window = glfwCreateWindow(480, 320, "Hello World", NULL, NULL);if (!window){glfwTerminate();return -1;}/* Make the window's context current */glfwMakeContextCurrent(window);/* Loop until the user closes the window */while (!glfwWindowShouldClose(window)){/* Draw a triangle */glBegin(GL_TRIANGLES);glColor3f(1.0, 0.0, 0.0);    // RedglVertex3f(0.0, 1.0, 0.0);glColor3f(0.0, 1.0, 0.0);    // GreenglVertex3f(-1.0, -1.0, 0.0);glColor3f(0.0, 0.0, 1.0);    // BlueglVertex3f(1.0, -1.0, 0.0);glEnd();/* Swap front and back buffers */glfwSwapBuffers(window);/* Poll for and process events */glfwPollEvents();}glfwTerminate();return 0;}







0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 寄信时不知道对方的邮编怎么办 地下钱庄转账后银行户被冻结怎么办 老师遇到素质极差的垃圾学生怎么办 验证码忘了手机号也换了怎么办 手机上的验证码忘了怎么办 进入医联网的验证码忘了怎么办 育碧换电脑了无法同步云存档怎么办 刺客信条起源育碧需要激活码怎么办 电脑连不上网怎么办wifi可以用 电脑登录账号密码错误锁定了怎么办 白色T恤衫上沾上黑色的黄油怎么办 家教遇到成绩好的学生该怎么办 跟越南人离婚孩子中国户口9怎么办 老婆是个越南人至今没户口怎么办 等离子屏z板链接处排线打火怎么办 等离子自动调焊的成形不好怎么办 村里内村道路中间被抢占了怎么办 华为换电池之后卡没反应怎么办 汽车钥匙换电池后没反应怎么办 汽车解锁换电池后没反应怎么办 包裹显示待收件人向海关申报怎么办 在越南签证被公安扣了怎么办 酷派手机收不到验证码怎么办 苹果想把图片上的字盖上怎么办 婴儿自己把眼珠子抠红了怎么办 如果美陆战队员进入台湾那怎么办? 顺产生完小孩吸不通奶怎么办 耐克空军一号白色底发黄怎么办 中行网银u盾丢了怎么办 有人用你的手机号码不停注册怎么办 获得公开你微信头像的权限是怎么办 手机能进的网站电脑进不去怎么办 苹果8p下不了微信怎么办 苹果手机版本过底不能下微信怎么办 手机打开视频跳转到qq是怎么办 淘宝店铺显示服务竟然出错了怎么办 母羊下完羊羔把羊衣吃了怎么办? 移植后56天有黑色东西怎么办 我家的金丝熊浑身都是尿怎么办 一键启动车钥匙丢了怎么办 把爷爷的遗物弄丢了怎么办