Mac/ios startup process under Cocos2d-lua

Mac/ios startup process under Cocos2d-lua


Preface

In-depth source code, learn the role of Application, ApplicationProtocol, AppDelegate three classes, and the relationship between them, and understand the startup process of mac/ios under cocos2d-lua.
AppController—>AppDelegate—>cocos2d::Application(ios/mac)::run() under ios/mac
.


Tip: The following is the content of this article, the following cases are for reference

1. New cocos2d-lua project

New project using command

cocos new -l lua -p com.game.myluatest -d ./ MyGameLuaTest

2. Use xcode to open the /MyGameLuaTest.xcodeproj project

Use xcode to open the MyGameLuaTest/frameworks/runtime-src/proj.ios_mac/MyGameLuaTest.xcodeproj project. In the project code on the left, ios/mac under MyGameLuaTest is the startup source code under the corresponding platform:

1.The source code of AppController.mm under ios:

// cocos2d application instance
static AppDelegate s_sharedApplication;

Create a static global AppDegate object, until the end of the program, automatically destroyed.

2. Next look at the source code of AppDelegate.h:

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();
};

This shows that AppDelegate inherits Application. There are 4 methods implemented by the AppDelegate class. These 4 methods come from ApplicationProtocol.

The following is the source code of ApplicationProtocol.h:

    /** Subclass override the function to set OpenGL context attribution instead of use default value.
    * And now can only set six attributions:redBits,greenBits,blueBits,alphaBits,depthBits,stencilBits.
    * Default value are(5,6,5,0,16,0), usually use as follows:
    * void AppDelegate::initGLContextAttrs(){
    *     GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};
    *     GLView::setGLContextAttrs(glContextAttrs);
    * }
    */
    virtual void initGLContextAttrs() {
    
    }
    /**
    * @brief    Implement Director and Scene init code here.
    * @return true    Initialize success, app continue.
    * @return false   Initialize failed, app terminate.
    * @js NA
    * @lua NA
    */
    virtual bool applicationDidFinishLaunching() = 0;

    /**
    * @brief  This function will be called when the application enters background.
    * @js NA
    * @lua NA
    */
    virtual void applicationDidEnterBackground() = 0;

    /**
    * @brief  This function will be called when the application enters foreground.
    * @js NA
    * @lua NA
    */
    virtual void applicationWillEnterForeground() = 0;

However, cocos2d::Application inherits ApplicationProtocol, and there are only 4 methods in AppDelegate:
1.initGLContextAttrs:initialize glContext;
2.applicationDidFinishLaunching:app is loaded, this method implements the initialization of Director and Scene;
3.applicationDidEnterBackground:app enters the background When the callback method;
4.applicationWillEnterForeground: the callback method when the app enters the foreground;

Cocos2dx implements cross-platform functions by setting the app proxy and only modifying the code in AppDelegate; that is, if you need to implement some functions when returning to the background, such as clearing some infrequently used arts and science caches, you only need to use the applicationDidEnterBackground method Realize, you can achieve cross-platform effects. That is, all platforms (ios/mac/android/win32/winrt/linux) are applicable at the same time. Why, then continue to look at the following code.

2. Next look at the source code of CCApplication.h:

#if CC_TARGET_PLATFORM == CC_PLATFORM_MAC
#include "platform/mac/CCApplication-mac.h"
#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
#include "platform/ios/CCApplication-ios.h"
#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#include "platform/android/CCApplication-android.h"
#elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
#include "platform/win32/CCApplication-win32.h"
#elif CC_TARGET_PLATFORM == CC_PLATFORM_WINRT
#include "platform/winrt/CCApplication.h"
#elif CC_TARGET_PLATFORM == CC_PLATFORM_LINUX
#include "platform/linux/CCApplication-linux.h"
#endif

In the header file source code, introduce different CCApplication header files under different platforms

4. Take the source code of CCApplication-ios.h/CCApplication-ios.mm as an example:

The following is the source code of CCApplication-ios.h: inherited ApplicationProtocol

//在CCApplication-ios.h文件中
class CC_DLL Application : public ApplicationProtocol
...省略若干
/**
@brief    Run the message loop.
*/
int run();
    
/**
@brief    Get the current application instance.
@return Current application instance pointer.
*/
static Application* getInstance();

protected:
    static Application * sm_pSharedApplication;

The following is the source code of CCApplication-ios.mm:

Application* Application::sm_pSharedApplication = 0;

Application::Application()
{
    
    
    CC_ASSERT(! sm_pSharedApplication);
    sm_pSharedApplication = this;
}
/
// static member function
//

Application* Application::getInstance()
{
    
    
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}

Going back to the source code of AppController.mm in the first point, initialize the global static AppDelegate object; in fact, the parent class's CCApplication parameterless constructor is called by default. That is, the static member variable sm_pSharedApplication in the second example CCApplication-ios.mm is a pointer to its own CCApplication object instance. Therefore, cocos2d::Application *app = cocos2d::Application::getInstance() returns an instance of the CCApplication object under each platform.

AppController.mm source code:

// cocos2d application instance
static AppDelegate s_sharedApplication;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    
    
    cocos2d::Application *app = cocos2d::Application::getInstance();
    ...省略若干行代码
    //run the cocos2d-x game scene
    app->run();

    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    
    
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
     If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
     */
    cocos2d::Application::getInstance()->applicationDidEnterBackground();
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    
    
    /*
     Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
     */
    cocos2d::Application::getInstance()->applicationWillEnterForeground();
}

1. When the app->run(); method is called in AppController.mm, the applicationDidFinishLaunching method in the CCApplication parent class ApplicationProtocol is called, but the only implementation is in the AppDelegate file.
2. When ios AppController.mm enters the applicationDidEnterBackground method (the application goes to the background), it will call cocos2d::Application::getInstance()->applicationDidEnterBackground();
3.When iosAppController enters applicationWillEnterForegroundy, the application will be in the foreground. Cocos2d is called: :Application::getInstance()->applicationWillEnterForeground();

CCApplication-ios.mm source code:

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

Then call [[CCDirectorCaller sharedDirectorCaller] startMainLoop];
that is, startMainLoop in CCDirectorCaller starts the screen refresh timer in ios. CADisplayLink is a timer that allows us to draw content to the screen at the same frequency as the screen refresh rate. Create a new CADisplayLink object in the source code, add it to a runloop, and provide it with a target and selector to be called when the screen is refreshed. Called every time the screen is refreshed

cocos2d::Director* director = cocos2d::Director::getInstance();
director->mainLoop(dt)

CCDirectorCaller.mm source code:

-(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
{
    
    
    if (isAppActive) {
    
    
        cocos2d::Director* director = cocos2d::Director::getInstance();
        EAGLContext* cocos2dxContext = [(CCEAGLView*)director->getOpenGLView()->getEAGLView() context];
        if (cocos2dxContext != [EAGLContext currentContext])
            glFlush();
        
        [EAGLContext setCurrentContext: cocos2dxContext];

        CFTimeInterval dt = ((CADisplayLink*)displayLink).timestamp - lastDisplayTime;
        lastDisplayTime = ((CADisplayLink*)displayLink).timestamp;
        director->mainLoop(dt);
    }
}

At this time, it officially enters the Cocos2dx main loop.

CCDirector.cpp source code:

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

2.Info.plist under mac

to sum up

Take the iOS startup process as an example. In the file AppController.mm, create an AppDelegate object, AppDelegate inherits CCApplication, and CCApplication inherits ApplicationProtocol; then AppController.mm calls the run method of CCApplication, and the run method calls the applicationDidFinishLaunching method of ApplicationProtocol (The implementation method is in AppDelegate), and the timer CADisplayLink that opens the screen refresh in ios, calls the doCaller method every time the screen refreshes, and this method executes the mainLoop(dt) method in CCDirector, thus entering the main loop of Cocos2dx among.

Guess you like

Origin blog.csdn.net/Suarez1987/article/details/108704233