zoukankan      html  css  js  c++  java
  • cocos2dx学习笔记-启动流程

    引子

    按照官方给出的命令

    ./cocos.py new HelloWorldDemo -p com.coco2dx.org -l cpp -d ~/Desktop
    

    即可创建工程,运行起来,在HelloWorldScene.cpp可以添加自己的层、精灵等。但我们并不知道cocos是如何处理不同平台运行、如何渲染

    本文将通过HelloWorld的例子来跟踪一下程序的启动流程。

    首先找到程序的入口,在IOS工程,cocos的入口在AppController类的 didFinishLaunchingWithOptions方法中。

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
        cocos2d::Application *app = cocos2d::Application::getInstance();
        app->initGLContextAttrs();
        cocos2d::GLViewImpl::convertAttrs();
    
        // 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]];
    
        // Init the CCEAGLView
        CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]
                                             pixelFormat: (NSString*)cocos2d::GLViewImpl::_pixelFormat
                                             depthFormat: cocos2d::GLViewImpl::_depthFormat
                                      preserveBackbuffer: NO
                                              sharegroup: nil
                                           multiSampling: NO
                                         numberOfSamples: 0 ];
        
        // Enable or disable multiple touches
        [eaglView setMultipleTouchEnabled:NO];
    
        // Use RootViewController manage CCEAGLView 
        _viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
        _viewController.wantsFullScreenLayout = YES;
        _viewController.view = eaglView;
    
        // 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:true];
    
        // IMPORTANT: Setting the GLView should be done after creating the RootViewController
        cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView(eaglView);
        cocos2d::Director::getInstance()->setOpenGLView(glview);
    
        app->run();
    
        return YES;
    }
    

    在上面代码中,可以看出在完成初始化、设置OpenGL的属性、创建CCEAGView(这是OpenGL最终显示的画布)等操作以后,最终是调用app->run来启动应用的,Application是一个单体类,管理着整个程序运行的逻辑。Application是分平台定义的。定义如下:

    // CCApplication.h
    class CC_DLL Application : public ApplicationProtocol
    {
    public:
        /**
         * @js ctor
         */
        Application();
    
    
    // CCApplication_ios.mm
    Application* Application::sm_pSharedApplication = 0;
    
    Application::Application()
    {
        CC_ASSERT(! sm_pSharedApplication);
        sm_pSharedApplication = this;
    }
    

    在看了上面Application类的定义后,会发现Application并不是一个严格意义的单体类,构造函数依是public属性,并且没有创建对象,在构造函数中断言sm_pSharedApplication是非空的,否则抛出异常。

    回到AppController.mm的开头,有一个静态变量的定义。

    // cocos2d application instance
    static AppDelegate s_sharedApplication;
    

    查看AppDelegate类定义,它继承于Application,是平台共用的类,在app->run中完成applicationDidFinishLaunching方法的实现。接着程序进入MainLoop。

    int Application::run()
    {
        if (applicationDidFinishLaunching()) 
        {
            [[CCDirectorCaller sharedDirectorCaller] startMainLoop];
        }
        return 0;
    }
    

    在applicationDidFinishLaunching中,对游戏环境进行初始化,完成了Scene的创建和运行。

    bool AppDelegate::applicationDidFinishLaunching() {
        // initialize director
        auto director = Director::getInstance();
        auto glview = director->getOpenGLView();
        if(!glview) {
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
            glview = GLViewImpl::createWithRect("helloDemo", Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
    #else
            glview = GLViewImpl::create("helloDemo");
    #endif
            director->setOpenGLView(glview);
        }
    
        // 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);
    
        // Set the design resolution
        glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
        Size frameSize = glview->getFrameSize();
        // if the frame's height is larger than the height of medium size.
        if (frameSize.height > mediumResolutionSize.height)
        {        
            director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
        }
        // if the frame's height is larger than the height of small size.
        else if (frameSize.height > smallResolutionSize.height)
        {        
            director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
        }
        // if the frame's height is smaller than the height of medium size.
        else
        {        
            director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
        }
    
        register_all_packages();
    
        // create a scene. it's an autorelease object
        auto scene = HelloWorld::createScene();
    
        // run
        director->runWithScene(scene);
    
        return true;
    }
    

    applicationDidFinishLaunching执行成功进入程序住循环MainLoop,将程序的控制权交到director手中,displayLink设置好回调函数(doCaller)和帧率,通过addToRunLoop加入到RunLoop中去。 每一帧都会回调doCaller方法,而doCaller方法调用了mainLoop方法。

    -(void) startMainLoop
    {
            // Director::setAnimationInterval() is called, we should invalidate it first
        [self stopMainLoop];
        
        displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];
        [displayLink setFrameInterval: self.interval];
        [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    
    -(void) doCaller: (id) sender
    {
        cocos2d::Director* director = cocos2d::Director::getInstance();
        [EAGLContext setCurrentContext: [(CCEAGLView*)director->getOpenGLView()->getEAGLView() context]];
        director->mainLoop();
    }
    

    而mainLoop方法的实现是在DisplayLinkDirector类中,进入OpenGL主循环,实现场景绘制。

    void DisplayLinkDirector::mainLoop()
    {
        // 如果调用了director->end(),清理数据
        if (_purgeDirectorInNextLoop)
        {
            _purgeDirectorInNextLoop = false;
            purgeDirector();
        }
        else if (_restartDirectorInNextLoop) //如果调用了restart,重置数据
        {
            _restartDirectorInNextLoop = false;
            restartDirector();
        }
        else if (! _invalid)
        {
            drawScene();//OpenGL 主循环 绘制场景
         
            // release the objects每一次循环清理一次内存池
            PoolManager::getInstance()->getCurrentPool()->clear();
        }
    }
    
  • 相关阅读:
    Codeforces 1528E Mashtali and Hagh Trees
    Codeforces Round #709 (Div. 1, based on Technocup 2021 Final Round)
    Codeforces 1517G Starry Night Camping
    Codeforces 1508E Tree Calendar
    Codeforces 1508D Swap Pass
    Codeforces 1511G Chips on a Board
    Codeforces 1511F Chainword
    Codeforces 1516E Baby Ehab Plays with Permutations
    CF1539A Contest Start 题解
    关于 manacher
  • 原文地址:https://www.cnblogs.com/zhiqli/p/5918133.html
Copyright © 2011-2022 走看看