cocos2d-x 启动和结束流程

版本:Cocos2dx 3.10
环境:Xcode
语言:C++/Lua

简介


简要的说明下cocos2d-Lua项目的启动,方便对后续内容的理解:

  1. 项目启动时,通过main开始调用Application
  2. Application负责管理游戏的生命周期,平台和语言的设置
  3. 它会通过Application::run对OpenGL窗口初始化,并初始化FPS, LuaEngine等
  4. 初始化成功,通过LuaEngine成功调用Lua项目的main.lua后表示应用程序启动
  5. 游戏进入主循环 mainLoop,根据FPS的设定进行渲染更新和内存管理

这个就是启动流程的大概步骤,主要的类接口有:

  • Application 应用程序类,负责管理生命周期,平台和语言等
  • AppDelegate 继承于Application 主要负责生命周期相关

Application


它是整个游戏的入口点,负责管理游戏的生命周期、平台和语言等。

class CC_DLL Application : public ApplicationProtocol {
public:
    Application();
    virtual ~Application();
  	static Application* getInstance();
    // 设置游戏动画的帧率间隔,FPS
    virtual void setAnimationInterval(float interval) override;
	// 运行应用程序
    int run();
    // 获取当前语言类型,比如中文,英文等
    virtual LanguageType getCurrentLanguage() override;
  	// 获取当前语言的代码
    virtual const char * getCurrentLanguageCode() override;
  	// 获取应用程序目标平台类型,比如Mac,IOS,Android等
    virtual Platform getTargetPlatform() override;
  	// 获取cocos版本号
    virtual std::string getVersion() override;
  	// 打开URL链接
    virtual bool openURL(const std::string &url) override;
};

启动流程的主要方法是:run

int Application::run() {
  	// 初始化OpenGL的属性,主要有:
  	// red,green,blue,alpha,depth,stencil,multisamplesCount
    initGLContextAttrs();
    // 检测应用程序启动逻辑相关,如果成功则true, 失败则false
    if(!applicationDidFinishLaunching()) {
        return 1;
    }
    
    long lastTime = 0L;
    long curTime = 0L;
    
  	// 获取Director和OpenGL的实例对象
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    glview->retain();

    unsigned int ctx_updated_count = 0;
	// 游戏主循环,实时监测OpenGL窗口是否关闭
    while (!glview->windowShouldClose()) {
        lastTime = getCurrentMillSecond();
      	// 执行场景的绘制相关
        director->mainLoop();
      	// 检测处理OpenGL窗口的输入事件相关
        glview->pollEvents();

      	// 计算当前帧时间监测是否等待下一阵休眠
        curTime = getCurrentMillSecond();
        if (curTime - lastTime < _animationInterval) {
            usleep(static_cast<useconds_t>((_animationInterval - curTime + lastTime)*1000));
        }
    }

    if (glview->isOpenGLReady()) {
        director->end();
        director->mainLoop();
    }
    glview->release();
    return 0;
}

mainLoop中,它的处理主要是:

void Director::mainLoop() {
    if (! _invalid) {
      	// 渲染场景,处理程序输入事件,监听等
        drawScene();
		// 内存管理相关
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

关于渲染相关,可参考博客:渲染机制简介
关于内存管理, 可参考博客: 内存管理机制

AppDelegate

它主要用于处理应用程序的生命周期,主要有三个接口:

  • applicationDidFinishLaunching 应用程序启动
  • applicationDidEnterBackground 应用程序进入后台
  • applicationWillEnterForeground 应用程序回到前台
class AppDelegate : private cocos2d::Application {
public:
    AppDelegate();
    virtual ~AppDelegate();
    virtual void initGLContextAttrs();

    // 主要负责设置应用程序的FPS, 设置窗口等
    virtual bool applicationDidFinishLaunching();
	// 主要负责暂停动画,声音等
    virtual void applicationDidEnterBackground();
	// 主要负责恢复动画,声音等
    virtual void applicationWillEnterForeground();
};

在启动应用程序时,我们看下它的逻辑处理:

bool AppDelegate::applicationDidFinishLaunching()
{
    // 设置动画间隔,即FPS
    Director::getInstance()->setAnimationInterval(1.0 / 60.0f);
	// 初始化LuaEngine
    auto engine = LuaEngine::getInstance();
    ScriptEngineManager::getInstance()->setScriptEngine(engine);
  	// 设置Lua的堆栈环境
    lua_State* L = engine->getLuaStack()->getLuaState();
  	// 注册tolua++接口相关,方便C++与Lua交互
    lua_module_register(L);
    register_all_packages();
	// 设置加密
    LuaStack* stack = engine->getLuaStack();
    stack->setXXTEAKeyAndSign("2dxLua", strlen("2dxLua"), "XXTEA", strlen("XXTEA"));
	// 设置Lua的资源搜索路径相关
    FileUtils::getInstance()->addSearchPath("src");
    FileUtils::getInstance()->addSearchPath("res");
  	// 执行Lua内的main文件
    if (engine->executeScriptFile("main.lua")) {
        return false;
    }
    return true;
}

至此大概的启动流程结束。


结束流程


Application::run中,主循环有个逻辑处理:

int Application::run() {
  // 检测OpenGL窗口是否关闭
  while (!glview->windowShouldClose()) {
    // ..
  }
}

windowShouldClose是OpenGL提供,用于检测窗口是否关闭。

在项目运行的过程中,如果需要告知OpenGL窗口关闭,需要调用OpenGL提供的方法:end()

告知项目,项目要结束运行了。


但我们在项目开发过程中,结束项目运行,会这样编写:

cc.Director:getInstance():end();

这个方法的主要处理逻辑是:

void Director::end() {
  	// 该变量有且只有在此处为true
    _purgeDirectorInNextLoop = true;
}

_purgeDirectorInNextLoop 是一个布尔类型的变量,被赋值为 true的情况下,也只有这里。

而通过该变量的判定逻辑处理在Director::mainLoop每帧刷新的主循环中。

void Director::mainLoop() {
    if (_purgeDirectorInNextLoop) {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    } else if (! _invalid) {
        drawScene();
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

该变量会作为一个开关进行调用purgeDirector。简单的说,这个方法就是做项目退出的收尾处理。

void Director::purgeDirector() {
    reset();
    // 退出OpenGLView
  	// 执行end方法后,windowShouldClose会收到关闭请求
    if (_openGLView) {
        _openGLView->end();
        _openGLView = nullptr;
    }
    // 调用Ref::release进行内存管理释放相关
    release();
}

void Director::reset() {
    // 场景退出
    if (_runningScene) {
        _runningScene->onExit();
        _runningScene->cleanup();
        _runningScene->release();
    }
    _runningScene = nullptr;
    _nextScene = nullptr;
    
    // 定时器关闭
    getScheduler()->unscheduleAll();
    
    // 移除事件相关
    if (_eventDispatcher) {
        _eventDispatcher->removeAllEventListeners();
    }
    
    _scenesStack.clear();
    // 停止动画
    stopAnimation();
    
    // 释放字体相关
    FontFNT::purgeCachedData();
    FontAtlasCache::purgeCachedData();
    FontFreeType::shutdownFreeType();
    
    // purge all managed caches
    DrawPrimitives::free();
    AnimationCache::destroyInstance();
    SpriteFrameCache::destroyInstance();
    GLProgramCache::destroyInstance();
    GLProgramStateCache::destroyInstance();
    FileUtils::destroyInstance();
    AsyncTaskPool::destroyInstance();
    UserDefault::destroyInstance();
    GL::invalidateStateCache();
    RenderState::finalize();
    destroyTextureCache();
}

通过这些代码分析,我们汇总下关于项目结束流程的步骤:

  1. Application::run中的主循环中,通过windowShouldClose()每帧检测窗口是否需要关闭
  2. 通过Director::end()方法设定标记_purgeDirectorInNextLooptrue
  3. Director::mainLoop()中,通过标记执行purgeDirector()方法对项目进行收尾处理,主要操作:
    • 执行场景退出和释放
    • 执行定时器销毁
    • 执行所有事件移除
    • 执行动画停止
    • 执行字体缓存释放
    • 执行着色器,动画,精灵帧,纹理缓存释放等
    • 关闭OpenGL窗口
  4. 调用内存管理的引用计数释放
  5. windowShouldClose 收到OpenGL关闭窗口请求,停止主循环刷新
  6. 项目运行结束。

其他


// purge all managed caches
AnimationCache::destroyInstance();	
SpriteFrameCache::destroyInstance();
destroyTextureCache();

void Director::destroyTextureCache() {
    if (_textureCache) {
        _textureCache->waitForQuit();
        CC_SAFE_RELEASE_NULL(_textureCache);
    }
}

这段代码是关于动画、精灵帧和纹理缓存的删除。

如果我们在项目开发中,尤其做内存优化处理的过程中,删除一定要严格按照此种方式,执行顺序:

动画 --> 精灵帧 --> 纹理

最后,祝大家学习生活愉快!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹤九日

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值