cocos2d-x (一): 从hello World示例中理解整个游戏框架

来源:互联网 发布:街霸5 网络 编辑:程序博客网 时间:2024/04/29 21:36
<span style="font-family: 微软雅黑; background-color: rgb(255, 255, 255);">首先找到main.cpp,程序由此进入</span>
一个游戏对应一个Application,Application的职责是管理游戏生命周期并设置默认窗口,获取平台及本地化信息。
Application::getInstance()->run() 为整个应用程序的入口。
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();}

Application 通常不直接创建一个 Application对象,而是创建一个Appliction的子类:AppDelegate
可以在游戏入口Application::getInstance()->run()看到
    if (!applicationDidFinishLaunching())    {        return 0;    }

在applicationDidFinishLaunching中,首先初始化一个 Director,并为Director创建一个 OpenGL ES窗口,然后创建第一个场景。
一般一些设置工作如 分辨率,帧率,资源搜索目录等都是在applicationDidFinishLaunching完成的。

一个基本的应用程序启动的初始化工作如下:
bool AppDelegate::applicationDidFinishLaunching() {    auto director = Director::getInstance();    auto glview = director->getOpenGLView();    if(!glview) {        glview = GLViewImpl::create("Cpp Empty Test");        director->setOpenGLView(glview);    }    director->setAnimationInterval(1.0 / 60);    auto scene = HelloWorld::scene();    director->runWithScene(scene);    return true;}

现在的操作系统基本都支持多任务,当玩家离开游戏时,应暂停游戏:
void AppDelegate::applicationDidEnterBackground() {    Director::getInstance()->stopAnimation();}

当玩家回到游戏中,应恢复游戏:
void AppDelegate::applicationWillEnterForeground() {    Director::getInstance()->startAnimation();    // if you use SimpleAudioEngine, it must resume here    // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();}

在 applicationDidFinishLaunching 中设置了帧率
director->setAnimationInterval(1.0 / 60);
帧率决定了游戏循环以怎样的间隔进行更新。
Application::run 驱动着游戏循环,按照帧率的设置进行游戏的循环逻辑更新,
如下是Application::run的实现
int Application::run(){    PVRFrameEnableControlWindow(false);    // Main message loop:    LARGE_INTEGER nLast;    LARGE_INTEGER nNow;    QueryPerformanceCounter(&nLast);    initGLContextAttrs();    // Initialize instance and cocos2d.    if (!applicationDidFinishLaunching())    {        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;}

mainLoop定义了一个游戏循环所有的事件和内容
Application::run() 在执行一次循环后,如果距离下一次更新还有空闲时间则休眠,直至下一次循环更新时间。


在applicationDidFinishLaunching 中,可以看到
    auto scene = HelloWorld::scene();    director->runWithScene(scene);
auto scene = HelloWorld::scene(); 创建了一个场景
Scene* HelloWorld::scene(){    // 'scene' is an autorelease object    auto scene = Scene::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;}

可以看到,创建一个类调用的是 create函数,为什么不直接 new Scene()呢,我们打开create函数
Scene* Scene::create(){    Scene *ret = new (std::nothrow) Scene();    if (ret && ret->init())    {        ret->autorelease();        return ret;    }    else    {        CC_SAFE_DELETE(ret);        return nullptr;    }}

可以看到在create函数中,先是new一个对象,然后调用对象的init方法,并把改对象加入cocos2d-x的内存管理中,设置为自动释放。
cocos2d-x中所以对象都是继承自ref基类,Ref基类主要职责就是对对象进行引用技术管理。用autorelease()方法声明一个对象指针为智能指针,但是这些智能指针并不单独关联某个自动变量,而是全部被加入一个AutoreleasePool中,在每一帧结束的时候加入AutoreleasePool中的对象进行清理。所以,在cocos2d-x中,一个智能指针的生命周期从被创建开始,到当前帧结束时结束。

一个类的初始化工作一般都在init中完成
在HelloWorld::init中,所完成的工作有
创建了一个菜单,一个字符标签和一个精灵。
Director::getInstance()->getVisibleSize() 获取窗口大小
Director::getInstance()->getVisibleOrigin() 获取游戏坐标,默认为左下角(0,0)
创建菜单的代码:
auto closeItem = MenuItemImage::create(                                        "CloseNormal.png",                                        "CloseSelected.png",                                        CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));        closeItem->setPosition(origin + Vec2(visibleSize) - Vec2(closeItem->getContentSize() / 2));    // create menu, it's an autorelease object    auto menu = Menu::create(closeItem, nullptr);    menu->setPosition(Vec2::ZERO);    this->addChild(menu, 1);

在这里是使用图片来创建菜单,默认时按钮图片为CloseNormal.png 选中时为CloseSelected.png,并添加了一个监听,菜单被点击时调用menuCloseCallback函数。
使用setPosition 在设置菜单的位置,通过this->addChild(menu, 1) 把菜单放置到场景的层中,1代表显示的优先级
创建字符标签和精灵(背景图片)都是使用类似的方法,先调用create创建,然后用setPosition设置位置,通过addChild加入层中。
场景初始化完毕后,
director->runWithScene(scene);
运行场景。游戏的第一个场景运行使用 runWithScene 方法
后面场景运行都是使用 director->replaceScene(newScene) 替换当前场景。
程序运行效果:


0 0