Cocos2d-x程序在Android下的启动过程

本文通过分析cocos2d-x(分析版本为cocos2d-x-2.2.1)自身提供的示例程序HelloLua(在目录$(sourcedir)samplesLuaHelloLua下)来分析cocos2d-x的在android平台下的具体启动过程。 我们知道android平台的游戏是从一个Activity开始的。HelloLua的启动Activity是在文件HelloLua.java中定义的,相关代码如下:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class HelloLua extends Cocos2dxActivity{
     protected void onCreate(Bundle savedInstanceState){
         super .onCreate(savedInstanceState);
     }
     
     public Cocos2dxGLSurfaceView onCreateGLSurfaceView() {
         return new LuaGLSurfaceView( this );
     }
     
     static {
         System.loadLibrary(hellolua);
    }
}

从上面的代码,启动Activity是继承Cocos2dxActivity的,在游戏启动时,Activity首先会执行静态代码块,加载libhellolua.so库,这个动态链接库是在用NDK编译的时候生成的;然后就是执行onCreate方法,这里调用了父类Cocos2dxActivity的onCreate方法。 Cocos2dxActivity在

?
1
$(sourcedir)cocos2dxplatformandroidjavasrcorgcocos2dxlibCocos2dxActivity.java

中定义,其OnCreate方法代码如下:

?
1
2
3
4
5
6
7
8
9
protected void onCreate( final Bundle savedInstanceState) {
     super .onCreate(savedInstanceState);
     sContext = this ;
     this .mHandler = new Cocos2dxHandler( this );
 
     this .init();
 
     Cocos2dxHelper.init( this , this );
}

这里主要是执行初始化过程,Cocos2dxHandler主要处理显示Dialog的消息,Cocos2dxHelper是个辅助类,我们主要看init()方法,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void init() {
         
         // FrameLayout
         ViewGroup.LayoutParams framelayout_params =
             new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                        ViewGroup.LayoutParams.FILL_PARENT);
         FrameLayout framelayout = new FrameLayout( this );
         framelayout.setLayoutParams(framelayout_params);
 
         // Cocos2dxEditText layout
         ViewGroup.LayoutParams edittext_layout_params =
             new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                        ViewGroup.LayoutParams.WRAP_CONTENT);
         Cocos2dxEditText edittext = new Cocos2dxEditText( this );
         edittext.setLayoutParams(edittext_layout_params);
 
         // ...add to FrameLayout
         framelayout.addView(edittext);
 
         // Cocos2dxGLSurfaceView
         this .mGLSurfaceView = this .onCreateView();
 
         // ...add to FrameLayout
         framelayout.addView( this .mGLSurfaceView);
 
         // Switch to supported OpenGL (ARGB888) mode on emulator
         if (isAndroidEmulator())
            this .mGLSurfaceView.setEGLConfigChooser( 8 , 8 , 8 , 8 , 16 , 0 );
 
         this .mGLSurfaceView.setCocos2dxRenderer( new Cocos2dxRenderer());
         this .mGLSurfaceView.setCocos2dxEditText(edittext);
 
         // Set framelayout as the content view
         setContentView(framelayout);
}
init()方法就是为Activity绑定View Hierarchy,这里的FrameLayout是根View,FrameLayout又包含一个Cocos2dxEditText和一个Cocos2dxGLSurfaceView,这个Cocos2dxGLSurfaceView的实例在方法onCreateView中创建的,代码非常简单,如下:
?
1
2
3
public Cocos2dxGLSurfaceView onCreateView() {
     return new Cocos2dxGLSurfaceView( this );
}
而类Cocos2dxGLSurfaceView本身是在
?
1
$(sourcedir)cocos2dxplatformandroidjavasrcorgcocos2dxlibCocos2dxGLSurfaceView.java

中定义,它继承自opengl中类GLSurfaceView。GLSurfaceView的核心就是Renderer,初始化时会调用Renderer的onSurfaceCreated方法,每一帧的绘制是通过调用Renderer的onDrawFrame方法。Cocos2dxGLSurfaceView的Renderer是一个Cocos2dxRenderer对象,类Cocos2dxRenderer在

?
1
$(sourcedir)cocos2dxplatformandroidjavasrcorgcocos2dxlibCocos2dxRenderer.java

中定义,其方法onSurfaceCreated代码如下:

?
1
2
3
4
public void onSurfaceCreated( final GL10 pGL10, final EGLConfig pEGLConfig) {
     Cocos2dxRenderer.nativeInit( this .mScreenWidth, this .mScreenHeight);
     this .mLastTickInNanoSeconds = System.nanoTime();
}

这里主要调用了一个方法nativeInit,nativeInit被声明为:

?
1
private static native void nativeInit( final int pWidth, final int pHeight);

即它是一个native的函数,即该函数用C++代码中实现,关于native函数简单说,就是在java在调用C++代码实现的函数,即需要采用JNI技术(可以看成是Java与C++交互的一个协议~)。方法nativeInit对应的C++实现是在(sourcedir)samplesLuaHelloLuaproj.androidjnihelloluamain.cpp中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
     if (!CCDirector::sharedDirector()->getOpenGLView())
     {
         CCEGLView *view = CCEGLView::sharedOpenGLView();
         view->setFrameSize(w, h);
 
         AppDelegate *pAppDelegate = new AppDelegate();
         CCApplication::sharedApplication()->run();
     }
     else
     {
     .....
     }
}
这里的函数命名Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit是完全按照JNI实现方法的命名规则。CCDirector就是是cocos2d-x中的导演类,该类在$(sourcedir)cocos2dxCCDirector.cpp中实现。方法sharedDirector是类CCDirector的一个静态方法,该方法用来创建游戏中唯一的CCDirector对象,代码如下:
?
1
2
3
4
5
6
7
8
9
10
CCDirector* CCDirector::sharedDirector( void )
{
     if (!s_SharedDirector)
     {
         s_SharedDirector = new CCDisplayLinkDirector();
         s_SharedDirector->init();
     }
 
     return s_SharedDirector;
}

这里的CCCCDisplayLinkDirector是CCDirector的子类,方法init()做一些初始化工作:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
bool CCDirector::init( void )
{
     setDefaultValues();
 
     //场景相关
     ...
     ...
 
     //管理场景的数组栈
     m_pobScenesStack = new CCArray();
     m_pobScenesStack->init();
 
     // 一些FPS等相关的成员变量初始化
     ...
     ...
 
     //初始化调度器对象
     m_pScheduler = new CCScheduler();
 
     //动作管理器对象
     m_pActionManager = new CCActionManager();
     m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false );
 
     // touchDispatcher,KeypadDispatcher,Accelerometer等对象初始化
     ...
     ...
 
     // CCPoolManager中实现了cocos2d-x CCObject对象的内存管理机制
     CCPoolManager::sharedPoolManager()->push();
 
     return true ;
}

创建好导演对象后,Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit中调用了该对象的getOpenGLView方法:

?
1
inline CCEGLView* getOpenGLView( void ) { return m_pobOpenGLView; }

该方法返回用于游戏绘制的CCEGLView,在init()中,m_pobOpenGLView复制为NULL。在Android平台下,这个CCEGLView其实没有什么作用,因为游戏都是绘制在Cocos2dxGLSurfaceView上的,因此方法Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit接着执行if分支:

?
1
2
CCEGLView *view = CCEGLView::sharedOpenGLView();
view->setFrameSize(w, h);

这里同样创建了游戏中类CCEGLView的唯一实例,类在$(sourcedir)cocos2dxplatformandroidCCEGLView.cpp中实现。接着执行

?
1
2
AppDelegate *pAppDelegate = new AppDelegate();
CCApplication::sharedApplication()->run();

创建了一个类AppDelegate对象,类AppDelegate在$(sourcedir)samplesLuaHelloLuaClassesAppDelegate.cpp中实现,类AppDelegate在各个平台之间共用的:

?
1
2
3
4
5
6
7
8
9
10
11
class  AppDelegate : private cocos2d::CCApplication
{
public :
     AppDelegate();
     virtual ~AppDelegate();
     virtual bool applicationDidFinishLaunching();
 
     virtual void applicationDidEnterBackground();
 
     virtual void applicationWillEnterForeground();
};

该类继承自CCApplication,注意类CCApplication是在$(sourcedir)cocos2dxplatformandroidCCApplication.cpp中实现的,它的实现是与平台相关的。创建AppDelegate实例的工作实质就是实例化CCApplication,它的构造函数代码如下:

?
1
2
3
4
5
CCApplication::CCApplication()
{
     CCAssert(! sm_pSharedApplication, );
     sm_pSharedApplication = this ;
}

因此在实例化AppDelegate时,主要工作是用AppDelegate对象初始化全局变量sm_pSharedApplication。接着后面调用CCApplication::sharedApplication()->run(),相关代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CCApplication* CCApplication::sharedApplication()
{
     CCAssert(sm_pSharedApplication, );
     return sm_pSharedApplication;
}
int CCApplication::run()
{
     // Initialize instance and cocos2d.
     if (! applicationDidFinishLaunching())
     {
         return 0 ;
     }
     
     return - 1 ;
}

run中调用的虚函数applicationDidFinishLaunching实质上调用的是子类AppDelegate中的applicationDidFinishLaunching,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool AppDelegate::applicationDidFinishLaunching()
{
     //初始化director
     CCDirector *pDirector = CCDirector::sharedDirector();
     pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
     
     CCEGLView::sharedOpenGLView()->setDesignResolutionSize( 480 , 320 , kResolutionNoBorder);
 
     //显示FPS
     pDirector->setDisplayStats( true );
 
     // 设置FPS
     pDirector->setAnimationInterval( 1.0 / 60 );
 
     //创建Lua脚本引擎
     CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
     CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
 
     //加载执行lua脚本
     std::string path = CCFileUtils::sharedFileUtils()->fullPathForFilename(hello.lua);
     pEngine->executeScriptFile(path.c_str());
 
     return true ;
}
至此游戏启动完成,但是我们并没看到类似while循环的东东(btw,分析windows和 Linux 平台上cocos2d-x的启动流程可以清楚看到类似while循环东东~),这是因为在android平台下,主循环是由渲染线程发起的,通过不断调用render来驱动的,具体说就是调用Java类Cocos2dxRenderer中的onDrawFrame方法:
?
1
2
3
public void onDrawFrame( final GL10 gl) {
     Cocos2dxRenderer.nativeRender();
}

其唯一的工作是调用了nativeRender方法,该方法是native的,其对应的实现是:

?
1
2
3
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) {
     cocos2d::CCDirector::sharedDirector()->mainLoop();
}

即执行导演对象中的方法mainLoop:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void CCDisplayLinkDirector::mainLoop( void )
{
     // 此变量决定程序是否结束
     if (m_bPurgeDirecotorInNextLoop)
     {
         m_bPurgeDirecotorInNextLoop = false ;
        
         purgeDirector();
     }
     else if (! m_bInvalid)
      {
         //屏幕绘制,并做一些相应的逻辑处理
          drawScene();
      
          // 释放对象管理器中CCObject 对象
          CCPoolManager::sharedPoolManager()->pop();       
      }
}

这个方法就是所有平台最后真正执行的循环体。

原文地址:http://www.2cto.com/kf/201409/335933.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值